Compare commits
833 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
98416fab64 | ||
|
0917269b55 | ||
|
9321369194 | ||
|
3b55336f69 | ||
|
a35a2f371b | ||
|
2b6bc8f8d3 | ||
|
c20ebbb8bd | ||
|
93245923d8 | ||
|
96dc260e4b | ||
|
9fdfb3aad6 | ||
|
fafd8158cc | ||
|
bd90f292e5 | ||
|
88f59aafb8 | ||
|
41f3521042 | ||
|
a11c2d1bd5 | ||
|
797412efa5 | ||
|
f6156786c6 | ||
|
b8f57db684 | ||
|
da4527b0b6 | ||
|
0bf61e05fd | ||
|
b5f57d6baa | ||
|
a628fad2f4 | ||
|
0c496937d7 | ||
|
a69f40aac1 | ||
|
cb9b11a39a | ||
|
8a83f642b1 | ||
|
a812be4200 | ||
|
97755e1dcb | ||
|
9109047460 | ||
|
6ae58e15dd | ||
|
e1acbbe769 | ||
|
c03abede4a | ||
|
a4d1dd4ffa | ||
|
91a6e737dd | ||
|
bf9af4d350 | ||
|
05e2b95984 | ||
|
604a84b8ba | ||
|
2bdb2c3edb | ||
|
0a44e0c24a | ||
|
5ab40b2d17 | ||
|
dd2d82729d | ||
|
88e8a62770 | ||
|
d15bc8a082 | ||
|
7513ea123b | ||
|
a34dc1ae4e | ||
|
7b8f6cea3a | ||
|
c08de32713 | ||
|
5cd69c4a2a | ||
|
5a2ea98bce | ||
|
e231a13066 | ||
|
06f597ab1f | ||
|
c8ce81bdb0 | ||
|
f1cc16be15 | ||
|
d42eb6d364 | ||
|
ba4fa88a65 | ||
|
caa64f9e89 | ||
|
a05972e9ce | ||
|
5157e13ba1 | ||
|
9f97afc148 | ||
|
8b1b0091c6 | ||
|
3e9aee3687 | ||
|
48bb0a82f9 | ||
|
1efdf38085 | ||
|
3e4f4d2f38 | ||
|
a2f870f2b8 | ||
|
2ac167d438 | ||
|
c218695a3d | ||
|
fae5f1dbbe | ||
|
54d29cc05d | ||
|
5aea02def2 | ||
|
368aa20b75 | ||
|
d2a07f2b6c | ||
|
14253a9c66 | ||
|
6881f4218a | ||
|
17badb972e | ||
|
2ea09dd60d | ||
|
87f7b6b2c6 | ||
|
01986a4129 | ||
|
2b404b517f | ||
|
b21b2d10f7 | ||
|
04deaba788 | ||
|
5cabc62733 | ||
|
01c6c3f0b6 | ||
|
b1a5cd4dcb | ||
|
58f78725db | ||
|
4210e8eab8 | ||
|
115492d1cc | ||
|
edadbb0c95 | ||
|
6c67dfcab7 | ||
|
b9453ab77b | ||
|
9507ffdd86 | ||
|
ff768954f6 | ||
|
15729bb66a | ||
|
41f46aaeea | ||
|
9e0d884f80 | ||
|
d34491b85f | ||
|
45070fb4e1 | ||
|
18612b48d3 | ||
|
a38c0a544d | ||
|
d38c9730fb | ||
|
d25320833c | ||
|
d38600dd6a | ||
|
6fa48587e1 | ||
|
8da0f3e9a3 | ||
|
ab402c0867 | ||
|
545a915439 | ||
|
d026902d91 | ||
|
ff72157c5f | ||
|
faab306dbe | ||
|
57fef9f3f2 | ||
|
89fac77951 | ||
|
ef02e9b4ac | ||
|
99b09c1faa | ||
|
d66e86f5c6 | ||
|
9bd46984e0 | ||
|
3992392245 | ||
|
198e92bc2c | ||
|
2f899eed2a | ||
|
8cdd4bdea3 | ||
|
3d53b0c251 | ||
|
0ac9512eb9 | ||
|
3f0ac7c666 | ||
|
faf7d00fdd | ||
|
b31abb0979 | ||
|
f2009cf99b | ||
|
0d97a47cc5 | ||
|
7db6beb896 | ||
|
e56a629ad7 | ||
|
ef918bbbcf | ||
|
60911ab887 | ||
|
e10a96ecd5 | ||
|
e99973925a | ||
|
949c6f6341 | ||
|
e041723ffc | ||
|
89919928da | ||
|
d4fc504f3d | ||
|
05924b8deb | ||
|
6d4aa50596 | ||
|
7ee2755617 | ||
|
35406ceb5a | ||
|
9efb536e55 | ||
|
b8d27f1811 | ||
|
0939ba0705 | ||
|
3788bc7cbf | ||
|
54723abc07 | ||
|
900f57437f | ||
|
300c9d5d68 | ||
|
96c9996284 | ||
|
8a15bcaa66 | ||
|
d17d67869c | ||
|
c491f33ce4 | ||
|
1dee5c809c | ||
|
924ede61b4 | ||
|
0d64d9c42d | ||
|
6b6fb909cd | ||
|
b51ff46085 | ||
|
46ec23990f | ||
|
eb46feac2c | ||
|
2c206f4193 | ||
|
c1bd19b35b | ||
|
370154cc46 | ||
|
9a81ce8b89 | ||
|
c805d283d4 | ||
|
03379f361c | ||
|
c671c0e898 | ||
|
edaf49b4c5 | ||
|
682903b0cb | ||
|
53f7f599d5 | ||
|
cc669fc20f | ||
|
4e7496a38a | ||
|
5842cdceee | ||
|
b7e0be8d9d | ||
|
a203b60cbb | ||
|
2be08af321 | ||
|
ad4c229a6b | ||
|
b2e0206e34 | ||
|
743ae013ea | ||
|
767cf7c1b9 | ||
|
6be94ab81c | ||
|
b1ed304a61 | ||
|
edf47aefd1 | ||
|
203b2b251c | ||
|
987e6b97dc | ||
|
4a93e54e63 | ||
|
658201eb98 | ||
|
c0e486df3f | ||
|
e0177ed895 | ||
|
b325d9bf0f | ||
|
9e01e92839 | ||
|
83c53b7150 | ||
|
2fb7c5c289 | ||
|
e9ed034dc7 | ||
|
f88ee0fc82 | ||
|
68188a7958 | ||
|
b537a237a8 | ||
|
1fc3c4c2f2 | ||
|
8d695c5091 | ||
|
d3f4046396 | ||
|
b80f3717b8 | ||
|
7f9fc557a9 | ||
|
14639337d4 | ||
|
0c136e6815 | ||
|
3057cdab5d | ||
|
539f2eb700 | ||
|
4c0c610b15 | ||
|
6ec8f127c0 | ||
|
5db219d571 | ||
|
f3eb8fa30a | ||
|
f70da74f46 | ||
|
35bbfac2c5 | ||
|
b304bf008d | ||
|
ebe39d9fac | ||
|
4bafeb34fd | ||
|
8e1cefbbb7 | ||
|
2d4fb5e00b | ||
|
6e2ac3b931 | ||
|
3c7d73d4ae | ||
|
fca7d05ed7 | ||
|
cf649cdafe | ||
|
7c5a4065df | ||
|
475633c328 | ||
|
f542e97a70 | ||
|
c7ac6b5670 | ||
|
2d92cdade0 | ||
|
b53f83aa95 | ||
|
fa5728d773 | ||
|
85662bb478 | ||
|
a1b3538131 | ||
|
06ba09f357 | ||
|
f70f61ac2f | ||
|
953a271bee | ||
|
0ead914d02 | ||
|
ac8a4b5a3a | ||
|
e3bb4c9b14 | ||
|
d88eaacf8d | ||
|
1a541c43ad | ||
|
edd69b30e0 | ||
|
d85291ae3e | ||
|
ff0ebfbcc1 | ||
|
e0ca2178d0 | ||
|
69f1d776eb | ||
|
2ae503612b | ||
|
f53369089a | ||
|
2f5ebd2071 | ||
|
56cb000130 | ||
|
db5313129e | ||
|
844eb3868a | ||
|
1c14f562ad | ||
|
b26bd5e296 | ||
|
52b77464f1 | ||
|
8152207334 | ||
|
e7826d725e | ||
|
3523609cad | ||
|
663752010c | ||
|
d6778a55cf | ||
|
9418fd0fb8 | ||
|
124706afab | ||
|
cf818f64c6 | ||
|
b94445b32a | ||
|
f025edf095 | ||
|
09bbc9c28d | ||
|
a98f6db089 | ||
|
673fdf1b67 | ||
|
8ebbb55842 | ||
|
df31cbbe77 | ||
|
5c700394a8 | ||
|
d442c2158a | ||
|
11779e2037 | ||
|
855180f905 | ||
|
372eda8f2f | ||
|
e941f74f99 | ||
|
4350fad789 | ||
|
cce80ff535 | ||
|
c82845d22a | ||
|
7ab68fb418 | ||
|
ae56d51076 | ||
|
aa8898a720 | ||
|
e9ab459b30 | ||
|
65779b18eb | ||
|
ca0166d8fd | ||
|
5f62c1abb2 | ||
|
f94fd218a0 | ||
|
f3dfc9631c | ||
|
44fa85af6b | ||
|
cd04d027a0 | ||
|
7829be0936 | ||
|
b98d591077 | ||
|
29fa5c4cd9 | ||
|
70608158fe | ||
|
106740abca | ||
|
1c50db9ce9 | ||
|
2dfa25fbee | ||
|
fa577aa018 | ||
|
0e83e47f1a | ||
|
c1ee97fc40 | ||
|
ec66cf29f3 | ||
|
f1200ac74d | ||
|
be1827e554 | ||
|
b46af3405e | ||
|
6c2ed4baed | ||
|
247e8ffbf4 | ||
|
52d93e8881 | ||
|
5d2e3f37f1 | ||
|
455136a722 | ||
|
ec8fd589e0 | ||
|
5ea8586c59 | ||
|
47cd4de267 | ||
|
22a502fd59 | ||
|
fce45b1d8d | ||
|
2b7623b6d5 | ||
|
5f73c3fb0e | ||
|
9476c3a3de | ||
|
5d13694530 | ||
|
5df328424d | ||
|
51d89c7210 | ||
|
f8d48cc9fc | ||
|
5f7bd6087f | ||
|
7549d73115 | ||
|
5eef57f3b8 | ||
|
4ad6b2bebf | ||
|
af5211aada | ||
|
58b625ef03 | ||
|
4ffbd839eb | ||
|
f8def37879 | ||
|
205bde833f | ||
|
e2bb4d7340 | ||
|
b040870cf1 | ||
|
4de60911cd | ||
|
058808aa61 | ||
|
253d65d5a3 | ||
|
2b682a14ae | ||
|
84d817c9d4 | ||
|
4db10f8195 | ||
|
2277c14882 | ||
|
359fd9761d | ||
|
e9fa2259a7 | ||
|
746d24da50 | ||
|
e341120f64 | ||
|
4e71a56b18 | ||
|
6ec80ee427 | ||
|
28a8ca444b | ||
|
a75e827d62 | ||
|
3dbb4fad41 | ||
|
ecf70e7b86 | ||
|
53c1e0986b | ||
|
16f49b58a8 | ||
|
1df01c77e3 | ||
|
27073eb4f4 | ||
|
eb3d9553ed | ||
|
188dc0b3bd | ||
|
4e7672fd63 | ||
|
6c35a435f0 | ||
|
5263b21138 | ||
|
49d40186be | ||
|
660a7cd059 | ||
|
ad739d0ce8 | ||
|
4e8d0d46fe | ||
|
02713c1661 | ||
|
8d561b5a56 | ||
|
25ece740e2 | ||
|
1c66534cb8 | ||
|
08610eee13 | ||
|
b8ccf9b2af | ||
|
537115fac5 | ||
|
3924521aed | ||
|
8bbe15edee | ||
|
0a686337f8 | ||
|
98d939a81b | ||
|
e1c6e83b98 | ||
|
d41e30c359 | ||
|
4bb63d428f | ||
|
85f970ea2d | ||
|
3411dde52f | ||
|
4a63606c84 | ||
|
2d439ed959 | ||
|
0e213abfd4 | ||
|
be737a24f2 | ||
|
f796f1f133 | ||
|
b2dc6f1f3c | ||
|
d73800bd5f | ||
|
52bb303ffa | ||
|
4e8c99554a | ||
|
428dbe8f0e | ||
|
f24a25b370 | ||
|
4107c01ad1 | ||
|
24c7b0074a | ||
|
378aae9567 | ||
|
742f73f028 | ||
|
52930918f2 | ||
|
be0f2e7e45 | ||
|
6134c4fdec | ||
|
5f1a2df610 | ||
|
d3d29acf09 | ||
|
b32b84f8c7 | ||
|
95ce975d40 | ||
|
8532189b54 | ||
|
1223d3dac3 | ||
|
a6c838cd39 | ||
|
03f0870f53 | ||
|
931959ecc8 | ||
|
b34037f26f | ||
|
f95e2ad703 | ||
|
5fac4a34bd | ||
|
3f9c2366f2 | ||
|
a708f37cd6 | ||
|
dd1071f180 | ||
|
576a886937 | ||
|
1208035da3 | ||
|
7944c9f826 | ||
|
6ee7df9514 | ||
|
4a3b6aa1d3 | ||
|
77b8224949 | ||
|
c4c94de1ac | ||
|
75cb466909 | ||
|
fd6235995f | ||
|
840460d960 | ||
|
3b46f3fe32 | ||
|
a2281dcf58 | ||
|
a19eb9c447 | ||
|
ceffbb6a77 | ||
|
c5439b4e7d | ||
|
0b227eff42 | ||
|
033b4cc6cc | ||
|
4fdec44755 | ||
|
6606bd4185 | ||
|
7cc964dfc5 | ||
|
b3bfc2b464 | ||
|
a937ac265c | ||
|
1058dd93f1 | ||
|
f4f9a148af | ||
|
d07f191a1e | ||
|
0ba9a9e076 | ||
|
ac7aadf615 | ||
|
3873189d79 | ||
|
891692d914 | ||
|
2d31de245f | ||
|
8c587e9b75 | ||
|
84622380d6 | ||
|
0736a65f2a | ||
|
658deb3bcd | ||
|
cfed5be1ca | ||
|
9fa4033b2a | ||
|
2c620ba440 | ||
|
01bf3a3818 | ||
|
8641222395 | ||
|
b4aedd606c | ||
|
ee1afc665f | ||
|
57e31e1319 | ||
|
46f6941325 | ||
|
61f3e1854c | ||
|
5cb327af38 | ||
|
648b2d69f9 | ||
|
e4f8c229b4 | ||
|
189e3ea348 | ||
|
e2c71e7a18 | ||
|
3b1268bbfd | ||
|
248d26fe69 | ||
|
afcac34208 | ||
|
9aa6e2a338 | ||
|
434acf21a4 | ||
|
aaf0df736b | ||
|
bb0d82aa10 | ||
|
9556414bf5 | ||
|
172ccd0428 | ||
|
31a9c75c08 | ||
|
fde7ef75af | ||
|
af7b20ee55 | ||
|
0277d1213e | ||
|
c62c4fa1d9 | ||
|
a520f7bff3 | ||
|
37f5b9114e | ||
|
d2dc3082b1 | ||
|
bd4d5da641 | ||
|
dad65da497 | ||
|
49aadaab0e | ||
|
864d665494 | ||
|
719151b44e | ||
|
1c3a9da5ed | ||
|
154b672d47 | ||
|
cfa2268c05 | ||
|
d37fd8955c | ||
|
a7d30582a6 | ||
|
0a570849c5 | ||
|
442d1b2713 | ||
|
9749df00d1 | ||
|
8a9a48fda1 | ||
|
777ebd77c8 | ||
|
36855783a7 | ||
|
8595539dea | ||
|
687ed02df0 | ||
|
3b861983e6 | ||
|
9caf9fc98f | ||
|
f58ba2926e | ||
|
049184bdfd | ||
|
6d6f51fdb6 | ||
|
2ee085d13d | ||
|
fb8a761278 | ||
|
625a7b8fda | ||
|
b15bef72df | ||
|
0aa65e2d95 | ||
|
53acf6420e | ||
|
f54dee3ccc | ||
|
b494d5ae79 | ||
|
7975140452 | ||
|
11ea67632c | ||
|
af09c04834 | ||
|
90d6492de6 | ||
|
73bcbd2590 | ||
|
faf3558754 | ||
|
37719a247e | ||
|
08df9f924f | ||
|
5812b2bec1 | ||
|
1d54be04e0 | ||
|
de98665b00 | ||
|
f23af07f6a | ||
|
9904367106 | ||
|
46a73566f5 | ||
|
2de19a1c94 | ||
|
5594e25dcf | ||
|
0c47327fc4 | ||
|
d6bf6744d8 | ||
|
094e8653ff | ||
|
5d6f31a25d | ||
|
545b6abfa1 | ||
|
d8270bddfa | ||
|
dfb03eabe6 | ||
|
6ea9dc4f1b | ||
|
acfaf3970e | ||
|
4402bd8f03 | ||
|
56280db289 | ||
|
6ebc103bc5 | ||
|
a40253da26 | ||
|
8f181bc4a0 | ||
|
625dc0304b | ||
|
5f9c21120d | ||
|
1e6bbba189 | ||
|
13ac8c093a | ||
|
d7e68f3a1d | ||
|
d60b38b3aa | ||
|
e47b750d21 | ||
|
ff764df4af | ||
|
630439cddf | ||
|
8b477e1f71 | ||
|
e021695230 | ||
|
70f00872a1 | ||
|
f14ae332eb | ||
|
76ff49a8ba | ||
|
dad726b6ca | ||
|
4aa8ec6bb8 | ||
|
757f1c6175 | ||
|
cfa5c9932e | ||
|
4bbb07ee1f | ||
|
66581fcaa2 | ||
|
b83e9bbf82 | ||
|
48a3ad29ff | ||
|
cede16bc50 | ||
|
e57105669c | ||
|
17480fd887 | ||
|
42d8476ea1 | ||
|
d901f0ba86 | ||
|
cea780b85b | ||
|
381e89d3df | ||
|
b4a8e32f44 | ||
|
26a7d37298 | ||
|
9291c75669 | ||
|
f61d0a07b1 | ||
|
999e0ad4c2 | ||
|
1721a0b693 | ||
|
2ceb075706 | ||
|
9a84a7deea | ||
|
1f6323941b | ||
|
c6c91181ab | ||
|
e4e9f1bec8 | ||
|
18d9360ad3 | ||
|
efbbdf1e72 | ||
|
624c05bdf4 | ||
|
e0d63535a6 | ||
|
7832dd42b2 | ||
|
d49294d288 | ||
|
b84a884387 | ||
|
9eeed5223c | ||
|
f520b6d5d0 | ||
|
d3ce2162ca | ||
|
1cc1ba2b7a | ||
|
6c0d984990 | ||
|
08e4da1c8a | ||
|
ba77ca4292 | ||
|
398d2c7cce | ||
|
b513a34fb8 | ||
|
272c31f132 | ||
|
ef9a790df0 | ||
|
f020df31d2 | ||
|
d26cf3de9d | ||
|
6af4ff6537 | ||
|
5c4a7dd273 | ||
|
41fb2ee1dc | ||
|
656221dcc0 | ||
|
2b8825f814 | ||
|
020da4d5c8 | ||
|
e0d1fb72a8 | ||
|
6d61173bca | ||
|
0f4b1bc91b | ||
|
36738fc9e4 | ||
|
5750f51bdd | ||
|
c569678a26 | ||
|
af19a09a3c | ||
|
92fb2dbb0d | ||
|
bc33bd8420 | ||
|
27c2bc1b2d | ||
|
337be1f989 | ||
|
6c9c3ce7ec | ||
|
495fe05a75 | ||
|
ab61314e0f | ||
|
70c1cc8829 | ||
|
b6c1d06165 | ||
|
d40ed14d80 | ||
|
6970ea39e4 | ||
|
2ce5bb1fea | ||
|
6fb920c826 | ||
|
40dc30044f | ||
|
b9515d3408 | ||
|
b99a1a753c | ||
|
e1d4088d98 | ||
|
a1cd3cf5bb | ||
|
cf054875b5 | ||
|
61e934bacc | ||
|
13a1eed144 | ||
|
a2cc3ee2fd | ||
|
483386e440 | ||
|
695902d962 | ||
|
6d62fb8c1e | ||
|
9f0febe402 | ||
|
bbb28032e7 | ||
|
97b57009c9 | ||
|
c96ecd9697 | ||
|
e0edb2b15b | ||
|
f32bab7733 | ||
|
bc266e1f7c | ||
|
5b48442006 | ||
|
bf009c8854 | ||
|
898ad5804e | ||
|
dfd36d459b | ||
|
5ceb04e571 | ||
|
4ca29feab1 | ||
|
95e1d8c5a3 | ||
|
22e69bbb8c | ||
|
b8aa4e1bc3 | ||
|
b6cc9dae09 | ||
|
e6a394e8e7 | ||
|
4e09f52b22 | ||
|
903ea66b36 | ||
|
525072f757 | ||
|
b741d163a1 | ||
|
b1a135fff9 | ||
|
d8d7347394 | ||
|
d8b07cee9c | ||
|
729c9237fe | ||
|
b2fc9cb8ac | ||
|
89c04ea3f6 | ||
|
93bf2e1bb9 | ||
|
0504bec81d | ||
|
7f9ded7816 | ||
|
c915f2f161 | ||
|
034510cdda | ||
|
6899b38944 | ||
|
b3aa6c9a6c | ||
|
eddc7bbf4e | ||
|
9bc112090d | ||
|
0b37514cfe | ||
|
e93ef1dd6e | ||
|
fe7b798cda | ||
|
a0cd7869bc | ||
|
c2d0382bae | ||
|
bb09c15c30 | ||
|
0a68b36295 | ||
|
b4a8154eae | ||
|
869640b2e2 | ||
|
de982f8b50 | ||
|
0ed8e62de8 | ||
|
5f677d4c83 | ||
|
6218cec38a | ||
|
c2d9baa9d9 | ||
|
8f6cc7846a | ||
|
a2f139c204 | ||
|
22d3048017 | ||
|
1367d82006 | ||
|
9572c440ea | ||
|
45b57b715f | ||
|
48e3eb877d | ||
|
9ec9fb9362 | ||
|
f32c1f1338 | ||
|
4f14ce96cb | ||
|
aeeff01d64 | ||
|
2bc71743de | ||
|
0cffdf124a | ||
|
789b698e7a | ||
|
0dbe87e2f4 | ||
|
0e069c6b88 | ||
|
f4ccb9f802 | ||
|
3bf2fa1237 | ||
|
7609906994 | ||
|
c626a161cd | ||
|
bcf84c2b8c | ||
|
d15878555f | ||
|
5121d060db | ||
|
f48c2c9b5c | ||
|
2c9c5ea8bb | ||
|
2b8a1fa2ca | ||
|
6c55d1e510 | ||
|
577a706b9f | ||
|
e7d78ea52e | ||
|
2b947254d5 | ||
|
32da3965f8 | ||
|
44e10db28d | ||
|
bc96846839 | ||
|
1425b68c39 | ||
|
f3e45bd240 | ||
|
d2bd6b8744 | ||
|
dbb9d14deb | ||
|
6ec2fae320 | ||
|
ef81026ffb | ||
|
45a276cf33 | ||
|
c6259d2feb | ||
|
3a7cab851d | ||
|
158bbff8de | ||
|
3f457d4a00 | ||
|
9cb06d70b2 | ||
|
e616e33239 | ||
|
c2c6ace3e5 | ||
|
7fa7fe3886 | ||
|
8f61715b6d | ||
|
e4918e777e | ||
|
19da9ef754 | ||
|
0a07750efb | ||
|
c78fe2f701 | ||
|
9ea1fa7f4b | ||
|
b9087ad7b7 | ||
|
efaa1eb18f | ||
|
89f39f1a1f | ||
|
b0ae9fead5 | ||
|
983acfc7e4 | ||
|
79920efe4f | ||
|
b250d13362 | ||
|
df13198c5c | ||
|
202c4b821e | ||
|
e789066b9b | ||
|
46ffedf530 | ||
|
fd72e7fa4e | ||
|
a9e08a7104 | ||
|
442a933f9b | ||
|
a2d6d82d83 | ||
|
2a7adda968 | ||
|
98aaec0ffd | ||
|
c0183aa359 | ||
|
c3197a39b0 | ||
|
6789c1f032 | ||
|
6fe1d178dd | ||
|
859d2e8641 | ||
|
3787eefa48 | ||
|
54f280f792 | ||
|
401f691359 | ||
|
77b0adaf7f | ||
|
7b5ab89fef | ||
|
464170cca9 | ||
|
dcdb937cf3 | ||
|
2c180c6123 | ||
|
1540b7b5bf | ||
|
030b91ba9f | ||
|
76d4821295 | ||
|
e72cf5423c | ||
|
ad7ac35422 | ||
|
ea21848811 | ||
|
a65d037def | ||
|
a667fbd8b4 | ||
|
92240b6e0c | ||
|
20eeaf73ac | ||
|
a1314347f9 | ||
|
fab69e3cae | ||
|
cc2cc8397e | ||
|
fe7d128056 | ||
|
d3a8f57e1c | ||
|
96c279275e | ||
|
d6a504c38b | ||
|
b1224c0a2b | ||
|
694787c8d6 | ||
|
8a6254c47e | ||
|
216d4511f7 | ||
|
043aa8755d | ||
|
e772dcecad | ||
|
ac99970bd4 | ||
|
7547250631 | ||
|
06bd6edc8c | ||
|
98aa2a447e | ||
|
00973e6365 | ||
|
dc11760640 | ||
|
1f955ae8d5 | ||
|
8c6ef2f533 | ||
|
d4f12d6d33 | ||
|
00f2195dd2 | ||
|
23ecf1264f | ||
|
7fcdbe9c9e | ||
|
8fa8f9b733 | ||
|
7a731c0fa5 | ||
|
700e53eb2c | ||
|
5968d6c903 | ||
|
c7317dbe54 | ||
|
031f52f6b7 | ||
|
fa6579f8f0 | ||
|
c9c99d58ab | ||
|
b9d6548243 | ||
|
914c02b7ab | ||
|
b83a7bed00 | ||
|
f3c19779cd | ||
|
9ef5894685 | ||
|
71117d3c42 | ||
|
079f758b66 | ||
|
dd83f121c8 | ||
|
8f326ee41b | ||
|
f32320fd67 | ||
|
0a7e49f6d5 | ||
|
33d8c0314c | ||
|
b73d5b4424 | ||
|
c4a450e5de | ||
|
b32ac0cf04 | ||
|
52c0e9993b | ||
|
1c3b3e9173 | ||
|
9690276079 | ||
|
58362883b3 | ||
|
5b8f35294b | ||
|
12c5b18b05 | ||
|
05315b14bd | ||
|
dd842a1393 | ||
|
a467b8f2e8 |
1
.gitignore
vendored
@@ -17,3 +17,4 @@ clang/
|
||||
win/
|
||||
gcc/
|
||||
tags
|
||||
.DS_Store
|
||||
|
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "thirdparty/jreen"]
|
||||
path = thirdparty/jreen
|
||||
url = git://github.com/euroelessar/jreen.git
|
||||
[submodule "thirdparty/qtweetlib/QTweetLib"]
|
||||
path = thirdparty/qtweetlib/QTweetLib
|
||||
url = git://github.com/minimoog/QTweetLib.git
|
||||
|
@@ -15,8 +15,8 @@ SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" )
|
||||
SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 2 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 99 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 3 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 3 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
@@ -48,7 +48,6 @@ IF( NOT BUILD_RELEASE )
|
||||
ENDIF()
|
||||
|
||||
|
||||
|
||||
# set paths
|
||||
SET( THIRDPARTY_DIR ${CMAKE_SOURCE_DIR}/thirdparty )
|
||||
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" )
|
||||
@@ -85,8 +84,8 @@ if(PHONON_FOUND)
|
||||
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
|
||||
endif()
|
||||
|
||||
macro_optional_find_package(LibEchonest 1.1.7)
|
||||
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.1.8 is needed for dynamic playlists and the infosystem")
|
||||
macro_optional_find_package(LibEchonest 1.1.10)
|
||||
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.1.10 is needed for dynamic playlists and the infosystem")
|
||||
|
||||
macro_optional_find_package(CLucene 0.9.23)
|
||||
macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" "http://clucene.sf.net" TRUE "" "CLucene is used for indexing the collection")
|
||||
@@ -105,14 +104,40 @@ macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++
|
||||
macro_optional_find_package(QCA2)
|
||||
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "")
|
||||
|
||||
macro_optional_find_package(LibAttica)
|
||||
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" FALSE "" "")
|
||||
|
||||
macro_optional_find_package(QuaZip)
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically." "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
|
||||
IF( NOT QuaZip_FOUND )
|
||||
add_subdirectory( ${CMAKE_SOURCE_DIR}/src/libtomahawk/thirdparty/quazip )
|
||||
SET( QuaZip_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/libtomahawk/thirdparty/quazip )
|
||||
SET( QuaZip_LIBRARY quazip )
|
||||
SET( QuaZip_LIBRARIES ${QuaZip_LIBRARY} )
|
||||
SET( QuaZip_FOUND true )
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically. Building internal copy" "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
|
||||
# copy headers to build/quazip so we can use proper includes inside the code
|
||||
FILE( COPY ${CMAKE_SOURCE_DIR}/src/libtomahawk/thirdparty/quazip/quazip/ DESTINATION ${CMAKE_BINARY_DIR}/libtomahawk/thirdparty/quazip )
|
||||
ENDIF()
|
||||
|
||||
# required
|
||||
#While we distribute our own liblastfm2, don't need to look for it
|
||||
#macro_optional_find_package(LibLastFm 0.3.3)
|
||||
#macro_log_feature(LIBLASTFM_FOUND "LastFm" "Qt library for the Last.fm webservices" "https://github.com/mxcl/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork")
|
||||
set(LIBLASTFM_FOUND true)
|
||||
|
||||
#### submodules start
|
||||
|
||||
# this installs headers and such and should really be handled in a separate package by packagers
|
||||
IF( INTERNAL_JREEN )
|
||||
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules)
|
||||
EXECUTE_PROCESS(COMMAND git submodule init WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
EXECUTE_PROCESS(COMMAND git submodule update WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules)
|
||||
ENDIF()
|
||||
|
||||
IF( INTERNAL_JREEN )
|
||||
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/jreen )
|
||||
SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include )
|
||||
@@ -125,20 +150,9 @@ ELSE( INTERNAL_JREEN )
|
||||
ENDIF( INTERNAL_JREEN )
|
||||
macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "https://github.com/euroelessar/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin. \n\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!\n")
|
||||
|
||||
# this installs headers and such and should really be handled in a separate package by packagers
|
||||
IF( INTERNAL_QTWEETLIB )
|
||||
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/qtweetlib )
|
||||
# copy headers to build/QTweetLib so we can use proper includes inside the code
|
||||
FILE( COPY ${CMAKE_SOURCE_DIR}/thirdparty/qtweetlib/QTweetLib/src/ DESTINATION ${CMAKE_BINARY_DIR}/QTweetLib )
|
||||
SET( QTWEETLIB_INCLUDE_DIR ${CMAKE_BINARY_DIR} )
|
||||
SET( QTWEETLIB_LIBRARY tomahawk_qtweetlib )
|
||||
SET( QTWEETLIB_LIBRARIES ${QTWEETLIB_LIBRARY} )
|
||||
SET( QTWEETLIB_FOUND true )
|
||||
MESSAGE(STATUS "INTERNAL libQTweetLib: ${QTWEETLIB_INCLUDE_DIR}, ${QTWEETLIB_LIBRARY}")
|
||||
ELSE( INTERNAL_QTWEETLIB )
|
||||
macro_optional_find_package(QTweetLib)
|
||||
ENDIF( INTERNAL_QTWEETLIB )
|
||||
macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin. \n\n Use -DINTERNAL_QTWEETLIB=ON to build the git submodule inside Tomahawk \n")
|
||||
macro_optional_find_package(QTweetLib)
|
||||
macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin.\n")
|
||||
#### submodules end
|
||||
|
||||
### libportfwd
|
||||
SET( LIBPORTFWD_INCLUDE_DIR ${THIRDPARTY_DIR}/libportfwd/include )
|
||||
@@ -147,8 +161,8 @@ SET( LIBPORTFWD_LIBRARIES ${LIBPORTFWD_LIBRARY} )
|
||||
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/libportfwd )
|
||||
|
||||
# we need pthreads too
|
||||
macro_optional_find_package(Threads)
|
||||
macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
|
||||
#macro_optional_find_package(Threads)
|
||||
#macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
|
||||
|
||||
macro_optional_find_package(KDE4)
|
||||
macro_optional_find_package(KDE4Installed)
|
||||
@@ -158,9 +172,12 @@ macro_optional_find_package(KDE4Installed)
|
||||
|
||||
# macro_optional_find_package(KDE4)
|
||||
IF(KDE4_FOUND)
|
||||
#KDE4 adds and removes some compiler flags that we don't like
|
||||
STRING( REPLACE "-std=iso9899:1990" "" CLEAN_C_FLAGS ${CMAKE_C_FLAGS} )
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions" )
|
||||
IF( CMAKE_C_FLAGS )
|
||||
# KDE4 adds and removes some compiler flags that we don't like
|
||||
# (only for gcc not for clang e.g.)
|
||||
STRING( REPLACE "-std=iso9899:1990" "" CLEAN_C_FLAGS ${CMAKE_C_FLAGS} )
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions" )
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET( CLEAN_C_FLAGS ${CMAKE_C_FLAGS} )
|
||||
ENDIF()
|
||||
@@ -195,3 +212,7 @@ ADD_SUBDIRECTORY( src/libtomahawk )
|
||||
SET( TOMAHAWK_LIBRARIES tomahawklib )
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( admin )
|
||||
|
||||
IF( NOT DISABLE_CRASHREPORTER )
|
||||
ADD_SUBDIRECTORY( src/breakpad/CrashReporter )
|
||||
ENDIF()
|
||||
|
@@ -2,6 +2,7 @@
|
||||
# This module looks for clucene (http://clucene.sf.net) support
|
||||
# It will define the following values
|
||||
#
|
||||
# CLUCENE_INCLUDE_DIRS = CLUCENE_INCLUDE_DIR + CLUCENE_LIBRARY_DIR
|
||||
# CLUCENE_INCLUDE_DIR = where CLucene/StdHeader.h can be found
|
||||
# CLUCENE_LIBRARY_DIR = where CLucene/clucene-config.h can be found
|
||||
# CLUCENE_LIBRARIES = the libraries to link against CLucene
|
||||
@@ -12,7 +13,16 @@
|
||||
INCLUDE(CheckSymbolExists)
|
||||
INCLUDE(FindLibraryWithDebug)
|
||||
|
||||
# try to locate a patched unstable version (for comp's sake *sigh*) first
|
||||
FIND_PACKAGE(CLuceneUnstable)
|
||||
IF(CLUCENEUNSTABLE_FOUND)
|
||||
SET(CLucene_FOUND TRUE)
|
||||
SET(CLUCENE_INCLUDE_DIR ${CLUCENE_UNSTABLE_INCLUDE_DIRS})
|
||||
SET(CLUCENE_INCLUDE_DIRS ${CLUCENE_INCLUDE_DIR})
|
||||
SET(CLUCENE_LIBRARIES ${CLUCENE_UNSTABLE_LIBS})
|
||||
|
||||
#MESSAGE(FATAL_ERROR NARF)
|
||||
ELSE(CLUCENEUNSTABLE_FOUND)
|
||||
IF(CLucene_FIND_VERSION)
|
||||
SET(CLUCENE_MIN_VERSION ${CLucene_FIND_VERSION})
|
||||
ELSEIF()
|
||||
@@ -98,8 +108,11 @@ ENDIF (CLUCENE_LIBRARY_DIR)
|
||||
|
||||
IF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
|
||||
SET(CLucene_FOUND TRUE)
|
||||
SET(CLUCENE_INCLUDE_DIRS ${CLUCENE_LIBRARY_DIR} ${CLUCENE_INCLUDE_DIR})
|
||||
ENDIF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
|
||||
|
||||
ENDIF(CLUCENEUNSTABLE_FOUND)
|
||||
|
||||
IF(CLucene_FOUND)
|
||||
IF(NOT CLucene_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found CLucene: ${CLUCENE_LIBRARIES} version ${CLUCENE_VERSION}")
|
||||
@@ -111,7 +124,8 @@ ELSE(CLucene_FOUND)
|
||||
ENDIF(CLucene_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CLUCENE_INCLUDE_DIR
|
||||
CLUCENE_LIBRARY_DIR
|
||||
CLUCENE_INCLUDE_DIRS
|
||||
CLUCENE_INCLUDE_DIR
|
||||
CLUCENE_LIBRARY_DIR
|
||||
CLUCENE_LIBRARIES
|
||||
)
|
||||
|
37
CMakeModules/FindCLuceneUnstable.cmake
Normal file
@@ -0,0 +1,37 @@
|
||||
# - Try to find clucene-unstable
|
||||
# This is a workaround for distros, that want to ship a recent enough clucene but don't want to replace the old version
|
||||
#
|
||||
# CLUCENEUNSTABLE_FOUND - system has clucene-unstable
|
||||
# CLUCENE_UNSTABLE_INCLUDE_DIR - the clucene-unstable include directories
|
||||
# CLUCENE_UNSTABLE_LIBS - link these to use clucene-unstable
|
||||
#
|
||||
# (c) Dominik Schmidt <dev@dominik-schmidt.de>
|
||||
#
|
||||
|
||||
# Include dir
|
||||
find_path(CLUCENE_UNSTABLE_INCLUDE_DIR
|
||||
NAMES CLucene.h
|
||||
PATH_SUFFIXES clucene-unstable
|
||||
PATHS ${KDE4_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
# Finally the library itself
|
||||
find_library(CLUCENE_UNSTABLE_SHARED_LIB
|
||||
NAMES clucene-unstable-shared
|
||||
PATHS ${KDE4_LIB_DIR}
|
||||
)
|
||||
|
||||
find_library(CLUCENE_UNSTABLE_CORE_LIB
|
||||
NAMES clucene-unstable-core
|
||||
PATHS ${KDE4_LIB_DIR}
|
||||
)
|
||||
|
||||
|
||||
SET( CLUCENE_UNSTABLE_LIBS ${CLUCENE_UNSTABLE_SHARED_LIB} ${CLUCENE_UNSTABLE_CORE_LIB} )
|
||||
SET( CLUCENE_UNSTABLE_INCLUDE_DIRS ${CLUCENE_UNSTABLE_INCLUDE_DIR})
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CLuceneUnstable DEFAULT_MSG CLUCENE_UNSTABLE_LIBS CLUCENE_UNSTABLE_INCLUDE_DIRS)
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(CLUCENE_UNSTABLE_LIBS CLUCENE_UNSTABLE_INCLUDE_DIRS)
|
||||
|
63
CMakeModules/FindLibAttica.cmake
Normal file
@@ -0,0 +1,63 @@
|
||||
# Try to find the Attica library
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBATTICA_FOUND Indicates that Attica was found
|
||||
# LIBATTICA_LIBRARIES Libraries needed to use Attica
|
||||
# LIBATTICA_LIBRARY_DIRS Paths needed for linking against Attica
|
||||
# LIBATTICA_INCLUDE_DIR Path needed for finding Attica include files
|
||||
#
|
||||
# The minimum required version of LibAttica can be specified using the
|
||||
# standard syntax, e.g. find_package(LibAttica 0.20)
|
||||
|
||||
# Copyright (c) 2009 Frederik Gladhorn <gladhorn@kde.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
|
||||
# Support LIBATTICA_MIN_VERSION for compatibility:
|
||||
IF(NOT LibAttica_FIND_VERSION)
|
||||
SET(LibAttica_FIND_VERSION "${LIBATTICA_MIN_VERSION}")
|
||||
ENDIF(NOT LibAttica_FIND_VERSION)
|
||||
|
||||
# the minimum version of LibAttica we require
|
||||
IF(NOT LibAttica_FIND_VERSION)
|
||||
SET(LibAttica_FIND_VERSION "0.1.0")
|
||||
ENDIF(NOT LibAttica_FIND_VERSION)
|
||||
|
||||
|
||||
IF (NOT WIN32)
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_LIBATTICA QUIET libattica)
|
||||
SET(LIBATTICA_DEFINITIONS ${PC_ATTICA_CFLAGS_OTHER})
|
||||
ENDIF (NOT WIN32)
|
||||
|
||||
FIND_PATH(LIBATTICA_INCLUDE_DIR attica/provider.h
|
||||
HINTS
|
||||
${PC_LIBATTICA_INCLUDEDIR}
|
||||
${PC_LIBATTICA_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES attica
|
||||
)
|
||||
|
||||
# Store the version number in the cache, so we don't have to search everytime:
|
||||
IF(LIBATTICA_INCLUDE_DIR AND NOT LIBATTICA_VERSION)
|
||||
FILE(READ ${LIBATTICA_INCLUDE_DIR}/attica/version.h LIBATTICA_VERSION_CONTENT)
|
||||
STRING (REGEX MATCH "LIBATTICA_VERSION_STRING \".*\"\n" LIBATTICA_VERSION_MATCH "${LIBATTICA_VERSION_CONTENT}")
|
||||
IF(LIBATTICA_VERSION_MATCH)
|
||||
STRING(REGEX REPLACE "LIBATTICA_VERSION_STRING \"(.*)\"\n" "\\1" _LIBATTICA_VERSION ${LIBATTICA_VERSION_MATCH})
|
||||
ENDIF(LIBATTICA_VERSION_MATCH)
|
||||
SET(LIBATTICA_VERSION "${_LIBATTICA_VERSION}" CACHE STRING "Version number of LibAttica" FORCE)
|
||||
ENDIF(LIBATTICA_INCLUDE_DIR AND NOT LIBATTICA_VERSION)
|
||||
|
||||
|
||||
FIND_LIBRARY(LIBATTICA_LIBRARIES NAMES attica libattica
|
||||
HINTS
|
||||
${PC_LIBATTICA_LIBDIR}
|
||||
${PC_LIBATTICA_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibAttica REQUIRED_VARS LIBATTICA_LIBRARIES LIBATTICA_INCLUDE_DIR
|
||||
VERSION_VAR LIBATTICA_VERSION)
|
||||
|
||||
MARK_AS_ADVANCED(LIBATTICA_INCLUDE_DIR LIBATTICA_LIBRARIES)
|
@@ -19,53 +19,19 @@ macro(_phonon_find_version)
|
||||
file(READ ${_phonon_namespace_header_file} _phonon_header LIMIT 5000 OFFSET 1000)
|
||||
string(REGEX MATCH "define PHONON_VERSION_STR \"(4\\.[0-9]+\\.[0-9a-z]+)\"" _phonon_version_match "${_phonon_header}")
|
||||
set(PHONON_VERSION "${CMAKE_MATCH_1}")
|
||||
message(STATUS "Phonon Version: ${PHONON_VERSION}")
|
||||
endmacro(_phonon_find_version)
|
||||
|
||||
if(PHONON_FOUND)
|
||||
# Already found, nothing more to do except figuring out the version
|
||||
# the dirs listed with HINTS are searched before the default sets of dirs
|
||||
find_library(PHONON_LIBRARY NAMES phonon HINTS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR})
|
||||
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h HINTS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR})
|
||||
|
||||
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
|
||||
set(PHONON_LIBS ${phonon_LIB_DEPENDS} ${PHONON_LIBRARY})
|
||||
set(PHONON_INCLUDES ${PHONON_INCLUDE_DIR}/KDE ${PHONON_INCLUDE_DIR})
|
||||
_phonon_find_version()
|
||||
else(PHONON_FOUND)
|
||||
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
|
||||
set(PHONON_FIND_QUIETLY TRUE)
|
||||
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
|
||||
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
|
||||
|
||||
# As discussed on kde-buildsystem: first look at CMAKE_PREFIX_PATH, then at the suggested PATHS (kde4 install dir)
|
||||
find_library(PHONON_LIBRARY NAMES phonon phonon4 PATHS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR})
|
||||
# then at the default system locations (CMAKE_SYSTEM_PREFIX_PATH, i.e. /usr etc.)
|
||||
find_library(PHONON_LIBRARY NAMES phonon phonon4)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Phonon DEFAULT_MSG PHONON_INCLUDE_DIR PHONON_LIBRARY)
|
||||
|
||||
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h PATHS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR})
|
||||
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h)
|
||||
|
||||
_phonon_find_version()
|
||||
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY AND NOT PHONON_VERSION VERSION_LESS ${Phonon_FIND_VERSION})
|
||||
set(PHONON_LIBS ${phonon_LIB_DEPENDS} ${PHONON_LIBRARY})
|
||||
set(PHONON_INCLUDES ${PHONON_INCLUDE_DIR}/KDE ${PHONON_INCLUDE_DIR})
|
||||
set(PHONON_FOUND TRUE)
|
||||
else(PHONON_INCLUDE_DIR AND PHONON_LIBRARY AND NOT PHONON_VERSION VERSION_LESS ${Phonon_FIND_VERSION})
|
||||
set(PHONON_FOUND FALSE)
|
||||
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY AND NOT PHONON_VERSION VERSION_LESS ${Phonon_FIND_VERSION})
|
||||
|
||||
if(PHONON_FOUND)
|
||||
if(NOT PHONON_FIND_QUIETLY)
|
||||
message(STATUS "Found Phonon: ${PHONON_LIBRARY}")
|
||||
message(STATUS "Found Phonon Includes: ${PHONON_INCLUDES}")
|
||||
endif(NOT PHONON_FIND_QUIETLY)
|
||||
else(PHONON_FOUND)
|
||||
if(Phonon_FIND_REQUIRED)
|
||||
if(NOT PHONON_INCLUDE_DIR)
|
||||
message(STATUS "Phonon includes NOT found!")
|
||||
endif(NOT PHONON_INCLUDE_DIR)
|
||||
if(NOT PHONON_LIBRARY)
|
||||
message(STATUS "Phonon library NOT found!")
|
||||
endif(NOT PHONON_LIBRARY)
|
||||
message(FATAL_ERROR "Phonon library or includes NOT found!")
|
||||
else(Phonon_FIND_REQUIRED)
|
||||
message(STATUS "Unable to find Phonon")
|
||||
endif(Phonon_FIND_REQUIRED)
|
||||
endif(PHONON_FOUND)
|
||||
|
||||
|
||||
mark_as_advanced(PHONON_INCLUDE_DIR PHONON_LIBRARY PHONON_INCLUDES)
|
||||
endif(PHONON_FOUND)
|
||||
mark_as_advanced(PHONON_INCLUDE_DIR PHONON_LIBRARY)
|
||||
|
11
CMakeModules/FindQuaZip.cmake
Normal file
@@ -0,0 +1,11 @@
|
||||
find_package(Qt4)
|
||||
find_path(QuaZip_INCLUDE_DIR quazip.h ${CMAKE_INSTALL_PREFIX}/include/quazip ${CMAKE_INSTALL_PREFIX}/include /usr/include/quazip /usr/local/include/quazip ${QT_INCLUDE_DIR}/quazip ${QT_INCLUDE_DIR} ${QUAZIP_DIR}/include/quazip ${QUAZIP_DIR}/quazip ${QUAZIP_DIR}/include)
|
||||
find_library(QuaZip_LIBRARY NAMES quazip PATHS ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/Library/Frameworks ${QUAZIP_DIR}/lib64 ${QUAZIP_DIR}/lib ${QUAZIP_DIR}/quazip ${QUAZIP_DIR})
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(quazip DEFAULT_MSG QuaZip_LIBRARY QuaZip_INCLUDE_DIR)
|
||||
set(QuaZip_LIBRARIES ${QuaZip_LIBRARY})
|
||||
mark_as_advanced(QuaZip_LIBRARY QuaZip_INCLUDE_DIR)
|
||||
|
||||
if(QuaZip_LIBRARY AND QuaZip_INCLUDE_DIR)
|
||||
set(QuaZip_FOUND TRUE)
|
||||
endif()
|
182
CMakeModules/GNUInstallDirs.cmake
Normal file
@@ -0,0 +1,182 @@
|
||||
# - Define GNU standard installation directories
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
# Inclusion of this module defines the following variables:
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
# where <dir> is one of:
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||
# install() commands for the corresponding file type. If the includer does
|
||||
# not define a value the above-shown default will be used and the value will
|
||||
# appear in the cache for editing by the user.
|
||||
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the value
|
||||
# of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# Note that the future of multi-arch handling may be even
|
||||
# more complicated than that: http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING
|
||||
AND NOT EXISTS "/etc/debian_version")
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
@@ -273,9 +273,13 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
;Main executable.
|
||||
File "${INSTALL_PATH}\bin\tomahawk.exe"
|
||||
|
||||
File "${INSTALL_PATH}\bin\tomahawk_crash_reporter.exe"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_breakpad.dll"
|
||||
|
||||
File "${INSTALL_PATH}\bin\libqxtweb-standalone.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll"
|
||||
File "${INSTALL_PATH}\bin\libquazip.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawklib.dll"
|
||||
File "${INSTALL_PATH}\lib\libtomahawk_sip*.dll"
|
||||
!endif
|
||||
@@ -283,10 +287,14 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
;Main executable.
|
||||
File "${BUILD_PATH}\tomahawk.exe"
|
||||
|
||||
File "${BUILD_PATH}\tomahawk_crash_reporter.exe"
|
||||
File "${BUILD_PATH}\libtomahawk_breakpad.dll"
|
||||
|
||||
File "${BUILD_PATH}\libtomahawklib.dll"
|
||||
File "${BUILD_PATH}\libqxtweb-standalone.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_portfwd.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_lastfm2.dll"
|
||||
File "${BUILD_PATH}\libquazip.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_sip*.dll"
|
||||
!endif
|
||||
|
||||
@@ -321,12 +329,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
|
||||
;Phonon stuff
|
||||
|
||||
;Fix the phonon build to not use Dbus
|
||||
File "${QT_DLL_PATH}\QtDbus4.dll"
|
||||
File "${MING_BIN}\libdbus-1-3.dll"
|
||||
File "${MING_BIN}\dbus-daemon.exe"
|
||||
|
||||
File "${VLC_BIN}\libphonon.dll"
|
||||
SetOutPath "$INSTDIR\phonon_backend"
|
||||
File "${VLC_BIN}\phonon_backend\phonon_vlc.dll"
|
||||
@@ -339,13 +341,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
SetOutPath "$INSTDIR\plugins"
|
||||
File /r "${VLC_PLUGIN_PATH}\*.dll"
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${MING_BIN}\libmad-0.dll" ; MP3
|
||||
File "${MING_BIN}\libFLAC-8.dll" ; FLAC
|
||||
File "${MING_BIN}\libogg-0.dll" ; OGG, FLAC
|
||||
File "${MING_BIN}\libvorbis-0.dll" ; OGG
|
||||
File "${MING_BIN}\libvorbisenc-2.dll" ; OGG
|
||||
|
||||
|
||||
|
||||
; Other
|
||||
File "${MING_BIN}\libqjson.dll"
|
||||
@@ -370,6 +365,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${MING_LIB}\libclucene-shared.dll"
|
||||
|
||||
File "${MING_BIN}\libqtsparkle.dll"
|
||||
File "${MING_BIN}\libattica.dll"
|
||||
SectionEnd
|
||||
|
||||
SectionGroup "Shortcuts"
|
||||
@@ -459,7 +455,8 @@ Section -post
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tomahawk" "NoRepair" "1"
|
||||
|
||||
; Register tomahawk:// protocol handler
|
||||
WriteRegStr HKCR "tomahawk" "" "URL: Tomahawk Protocol"
|
||||
WriteRegStr HKCR "tomahawk" "" "URL:Tomahawk Protocol"
|
||||
WriteRegStr HKCR "tomahawk" "URL Protocol" ""
|
||||
WriteRegStr HKCR "tomahawk\DefaultIcon" "" $INSTDIR\tomahawk.exe,1
|
||||
WriteRegStr HKCR "tomahawk\shell" "" "open"
|
||||
WriteRegStr HKCR "tomahawk\shell\open\command" "" '"$INSTDIR\tomahawk.exe" "%1"'
|
||||
|
112
ChangeLog
@@ -1,6 +1,118 @@
|
||||
Version 0.3.3:
|
||||
* Automatically load Super Collection tracks when no official release
|
||||
information is available.
|
||||
* Fixed stations not fetching new tracks under certain circumstances.
|
||||
* Fixed Footnotes not always updating when selecting a new track.
|
||||
* Added support for ow.ly, fb.me, itun.es and tinyurl.com URL shorteners.
|
||||
* Fixed playback issues with non-latin filenames on Windows.
|
||||
* Fixed tomahawk:// protocol not working properly on Windows.
|
||||
* Fixed dupe menu entry appearing on OS X.
|
||||
* Fixed invisible sidebar items on Linux.
|
||||
|
||||
Version 0.3.2:
|
||||
* Improved syncing process, it's faster and more reliable now.
|
||||
* Fixed UPnP issues.
|
||||
* Fixed not updating collections and views after a collection changes.
|
||||
* Fixed not showing a source's proper name at all times.
|
||||
* Improved music scanner reliability.
|
||||
* Fixed various labels not being painted in the right color when selected.
|
||||
* Support .oga (ogg mimetype) files.
|
||||
* Fixed stuck Now Playing indicator icon.
|
||||
* Fixed sidebar width of settings dialog on Windows.
|
||||
* Fixed not always showing delete icon on hovered temporary pages.
|
||||
* Fixed inability to select externally mounted drives.
|
||||
* Fixed bug where speaker would be stuck next to a playlist.
|
||||
* Fixed bug where first startup would show a loading spinner in the
|
||||
Dashboard's "Recent Additions" forever.
|
||||
* Automatically upgrade resolvers when an update is found.
|
||||
* Fixed last played track of a friend never expiring.
|
||||
* Fixed parsing of rdio tracks.
|
||||
* Changed steering mechanism in stations to be user-friendlier.
|
||||
* Fixed loading biographies of artist names with special characters.
|
||||
* Fixed behaviour of dropping Spotify playlists on the sidebar.
|
||||
* Fixed hard to read source-name in the audio control area on OS X.
|
||||
* Fixed crashes when playing Grooveshark tracks.
|
||||
* Fixed bug where clicking the latch button would flicker and unlatch.
|
||||
* Fixed Jabber accounts not connecting properly when proxy is in use.
|
||||
|
||||
Version 0.3.1:
|
||||
* Fixed not resolving to local files.
|
||||
* Fixed shutdown crash on Windows.
|
||||
* Support more widget types in Javascript resolver configs.
|
||||
* Fixed bug where red headphone would be visible on My Collection
|
||||
when listened along to source went offline.
|
||||
* Draw author name as well as avatar in recently played playlists.
|
||||
* Fixed Tomahawk integration in Unity.
|
||||
* Fixed incorrect item selected in source tree when deleting temporary
|
||||
pages.
|
||||
* Fixed currently played label disappearing after 10 minutes regardless
|
||||
of length of track.
|
||||
* Fixed crash on Sparkle upgrade on OS X.
|
||||
|
||||
Version 0.3.0:
|
||||
* Make artist names in the album view clickable.
|
||||
* Don't start playing if a tomahawk:// link was clicked while Tomahawk
|
||||
is paused.
|
||||
* Make artist name clickable in header of Album pages.
|
||||
* Added a drop shadow to cover images, and put placeholder in jewel case.
|
||||
* Added shuffle and repeat support to tree view.
|
||||
* Draw a speaker next to the currently playing playlist.
|
||||
* Refresh station previews whenever a filter is changed.
|
||||
* Support and show official releases on album and track pages.
|
||||
* Filter out duplicates from station previews and upcoming tracks.
|
||||
* Added YouTube resolver.
|
||||
* Fixed bug where going offline then online would not re-connect to many
|
||||
peers.
|
||||
* Added support for auto-updating live XSPF playlists.
|
||||
* Don't show an age of 41 years for tracks that have no age information.
|
||||
* Show config UI for resolvers that have them as soon as you add them.
|
||||
* Add support for Echo Nest Personal Catalogs and User Radio. Synchronize
|
||||
your catalog with The Echo Nest and enable personal recommendations
|
||||
from you and your friends.
|
||||
* Added support for Grooveshark resolver (requires Grooveshark Anywhere).
|
||||
* Fixed re-resolving when resolvers or sources go off- / online.
|
||||
* Correctly sort recently played tracks on the Dashboard.
|
||||
* Show a Lion full-screen toggle button if running on Lion.
|
||||
* Show a list of users who are currently listening along to you.
|
||||
* Show headphone icon in source item to allow users to listen along; paint
|
||||
headphones red on a source if you are currently listening along to it.
|
||||
* Added new job status view in the bottom of the source list that displays
|
||||
current jobs such as resolving, parsing playlists, and loading from
|
||||
database.
|
||||
* Parse and convert a Spotify playlist URL when dropped anywhere on the
|
||||
sidebar.
|
||||
* Convert resolvers to use asynchronous calls to avoid blocking Tomahawk's
|
||||
UI, greatly increasing responsiveness of Tomahawk while resolving.
|
||||
* Fixed no playlists overlay not disappearing when playlists were added.
|
||||
* Add support for parsing itunes track, artist and album links.
|
||||
* Fixed crash when syncing playlists with peers.
|
||||
* Add support for browsing, downloading and rating resolvers from within
|
||||
Tomahawk directly.
|
||||
* Support multi-folder selection and scanning.
|
||||
* Fixed handling of special characters in tomahawk:// links
|
||||
* Improve sidebar performance by caching pixmaps and shrinking them.
|
||||
* Send updated playlists to peers when tracks are moved/copied.
|
||||
* Remove splitter handles in sidebar.
|
||||
* Fixed Tomahawk preventing system shutdown / logout.
|
||||
* Ignore leading 'The' when sorting artists.
|
||||
* Added Charts page, which shows various sources' top hits & artists.
|
||||
* The Collection tree-views can now be filtered.
|
||||
* Fixed crash when pressing enter in an empty playlist.
|
||||
* Moved the song queue to the bottom of the sidebar.
|
||||
* Added Footnotes, a contextual view that you can slide it.
|
||||
* Show recently added playlists in dashboard rather than recently opened
|
||||
playlists.
|
||||
* Fixed seek slider and give it some smooth animation between ticks.
|
||||
* Fixed Twitter issue where it would repeatedly send DMs to friends.
|
||||
* Add a new drag and drop menu when dropping items onto playlists,
|
||||
allowing users to drop the dragged tracks, the whole album, or
|
||||
the whole artists's tracks.
|
||||
* Bring Tomahawk window to the front when clicking a Tomahawk link.
|
||||
* Fixed crash in source list when initially syncing with remote sources.
|
||||
* Open temporary artist, album, and search playlists as temporary items
|
||||
in the sidebar.
|
||||
* Fixed sorting of playlists and items in the artist view.
|
||||
* Allow dragging and dropping albums and artists to playlists.
|
||||
* Added MPRIS 2.1 support.
|
||||
|
||||
Version 0.2.3:
|
||||
|
27
README
@@ -27,18 +27,25 @@ Doxygen Documentation
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
CMake 2.8.0 http://www.cmake.org/
|
||||
Qt 4.7.0 http://qt.nokia.com/
|
||||
QJson 0.7.1 http://qjson.sourceforge.net/
|
||||
SQLite 3.6.22 http://www.sqlite.org/
|
||||
TagLib 1.6.2 http://developer.kde.org/~wheeler/taglib.html
|
||||
Boost 1.3x http://www.boost.org/
|
||||
CLucene 0.9.23 (0.9.21 will fail) http://clucene.sourceforge.net/download.shtml
|
||||
libechonest 1.1.8 http://projects.kde.org/projects/playground/libs/libechonest/
|
||||
CMake 2.8.0 - http://www.cmake.org/
|
||||
Qt 4.7.0 - http://qt.nokia.com/
|
||||
QJson 0.7.1 - http://qjson.sourceforge.net/
|
||||
SQLite 3.6.22 - http://www.sqlite.org/
|
||||
TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html
|
||||
Boost 1.3 - http://www.boost.org/
|
||||
CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml
|
||||
libechonest 1.2.0 - http://projects.kde.org/projects/playground/libs/libechonest/
|
||||
|
||||
The following dependencies are optional, but recommended:
|
||||
|
||||
Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
|
||||
jreen (Git) - https://github.com/euroelessar/jreen
|
||||
QTweetLib 0.3.0 - https://github.com/minimoog/QTweetLib
|
||||
|
||||
Third party libraries that we ship with our source:
|
||||
|
||||
MiniUPnP http://miniupnp.free.fr/
|
||||
liblastfm 0.4.0 http://github.com/jonocole/liblastfm/
|
||||
MiniUPnP 1.6 - http://miniupnp.free.fr/
|
||||
liblastfm 0.4.0 - http://github.com/jonocole/liblastfm/
|
||||
QuaZip 0.4.3 - http://quazip.sourceforge.net/
|
||||
|
||||
Enjoy!
|
||||
|
@@ -1,3 +1,3 @@
|
||||
IF(WIN32)
|
||||
INSTALL(DIRECTORY win DESTINATION share/tomahawk/admin )
|
||||
ENDIF(WIN32)
|
||||
ENDIF(WIN32)
|
||||
|
5
admin/copy_syms.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
DUMPID=`head -n1 $1 | cut -f4 -d' '`
|
||||
mkdir -p $2/$DUMPID
|
||||
cp $1 $2/$DUMPID/
|
@@ -41,7 +41,7 @@ VERSION=$1
|
||||
|
||||
header "Copying Sparkle framework"
|
||||
cp -R /Library/Frameworks/Sparkle.framework Contents/Frameworks
|
||||
|
||||
|
||||
header "Creating DMG"
|
||||
cd ..
|
||||
|
||||
|
@@ -207,7 +207,7 @@ TOMAHAWK_PLUGINS = [
|
||||
]
|
||||
|
||||
QT_PLUGINS_SEARCH_PATH=[
|
||||
'/usr/local/Cellar/qt/4.7.3/plugins',
|
||||
'/usr/local/Cellar/qt/4.7.4/plugins',
|
||||
]
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
|
||||
commands.append(['mkdir', '-p', frameworks_dir])
|
||||
resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
|
||||
commands.append(['mkdir', '-p', resources_dir])
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'plugins')
|
||||
binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name)
|
||||
|
||||
fixed_libraries = []
|
||||
@@ -500,6 +500,11 @@ try:
|
||||
FixPlugin('spotify_tomahawkresolver', '../MacOS')
|
||||
except:
|
||||
print 'Failed to find spotify resolver'
|
||||
|
||||
try:
|
||||
FixPlugin('tomahawk_crash_reporter', '../MacOS')
|
||||
except:
|
||||
print 'Failed to find tomahawk_crash_reporter'
|
||||
|
||||
for plugin in QT_PLUGINS:
|
||||
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
||||
|
@@ -4,8 +4,9 @@ Version=1.0
|
||||
Name=Tomahawk
|
||||
GenericName=Music Player
|
||||
TryExec=tomahawk
|
||||
Exec=tomahawk
|
||||
Exec=tomahawk %u
|
||||
Comment=Tomahawk - Social Music Player
|
||||
Icon=tomahawk
|
||||
Terminal=false
|
||||
Categories=Qt;AudioVideo;Audio;Player;
|
||||
MimeType=x-scheme-handler/tomahawk;
|
||||
|
@@ -1,22 +1,31 @@
|
||||
#!/bin/bash
|
||||
echo "Remove old vlc dir..."
|
||||
|
||||
mkdir -p vlc/
|
||||
|
||||
if [ "$1" = "-c" ] ; then
|
||||
echo "Continuing last download.."
|
||||
rm -rvf vlc/prefix/
|
||||
else
|
||||
echo "Remove old vlc dir..."
|
||||
rm -rvf vlc/*
|
||||
fi
|
||||
|
||||
cd vlc/
|
||||
|
||||
#rm -vf vlc-*.7z
|
||||
#rm -rf vlc/
|
||||
|
||||
echo "Download specified binary..."
|
||||
echo "Download phonon archive..."
|
||||
#wget -c "http://downloads.sourceforge.net/project/vlc/1.1.9/win32/vlc-1.1.9-win32.7z?r=http%3A%2F%2Fwww.videolan.org%2Fvlc%2Fdownload-windows.html&ts=1306272584&use_mirror=leaseweb"
|
||||
#wget -c "http://download.tomahawk-player.org/tomahawk-vlc-0.1.zip"
|
||||
wget -c http://people.videolan.org/~jb/phonon/phonon-vlc-last.7z
|
||||
#wget -c http://people.videolan.org/~jb/phonon/phonon-vlc-last.7z
|
||||
wget -c http://people.videolan.org/~jb/phonon/phonon_phonon-vlc_20111128.7z
|
||||
|
||||
echo "Extract binary..."
|
||||
7z x phonon-vlc-last.7z
|
||||
7z x phonon*.7z
|
||||
#mv -v vlc-*/ vlc/
|
||||
#unzip tomahawk-vlc-0.1.zip
|
||||
|
||||
echo "Download phonon_vlc_no_video.dll..."
|
||||
wget -c http://people.videolan.org/~jb/phonon/phonon_vlc_no_video.dll
|
||||
cp -v phonon_vlc_no_video.dll prefix/bin/phonon_backend/phonon_vlc.dll
|
||||
|
||||
echo "Strip unneeded plugins from vlc/plugins..."
|
||||
cd prefix/bin/plugins
|
||||
rm -rvf libold* libvcd* libdvd* liblibass* libx264* libschroe* liblibmpeg2* \
|
||||
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 204 KiB |
BIN
data/images/apply-check.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 4.4 KiB |
BIN
data/images/close.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
data/images/collapse.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
BIN
data/images/downloading.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
data/images/headphones-bigger.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/images/headphones-off.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
data/images/headphones-sidebar.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
data/images/headphones.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/images/itunes.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 68 KiB |
BIN
data/images/no-album-no-case.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
data/images/now-playing-speaker-dark.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
data/images/open.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
data/images/private-listening.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
data/images/rdio.png
Normal file
After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 5.1 KiB |
BIN
data/images/spotify-logo.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
data/images/star-hover.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
data/images/star-unstarred.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
data/images/starred.png
Normal file
After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 563 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 3.8 KiB |
BIN
data/images/uploading.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -184,6 +184,21 @@ Tomahawk.syncRequest = function(url)
|
||||
}
|
||||
};
|
||||
|
||||
Tomahawk.asyncRequest = function(url, callback)
|
||||
{
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open('GET', url, true);
|
||||
xmlHttpRequest.onreadystatechange = function() {
|
||||
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) {
|
||||
callback.call(window, xmlHttpRequest);
|
||||
} else if (xmlHttpRequest.readyState === 4) {
|
||||
Tomahawk.log("Failed to do GET request: to: " + url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
}
|
||||
}
|
||||
xmlHttpRequest.send(null);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Secure Hash Algorithm (SHA256)
|
||||
|
10
data/sql/dbmigrate-26_to_27.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Script to migate from db version 6 to 27
|
||||
-- Nothing to do
|
||||
|
||||
CREATE TABLE IF NOT EXISTS collection_attributes (
|
||||
id INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, -- source id, null for local source
|
||||
k TEXT NOT NULL,
|
||||
v TEXT NOT NULL
|
||||
);
|
||||
UPDATE settings SET v = '27' WHERE k == 'schema_version';
|
||||
|
3200
lang/tomahawk_de.ts
3180
lang/tomahawk_en.ts
Normal file
3017
lang/tomahawk_es.ts
Normal file
@@ -1,5 +1,8 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/lang">
|
||||
<file>tomahawk_en.qm</file>
|
||||
<file>tomahawk_es.qm</file>
|
||||
<file>tomahawk_de.qm</file>
|
||||
<file>tomahawk_pl.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
3218
lang/tomahawk_pl.ts
Normal file
@@ -4,7 +4,6 @@
|
||||
<file>data/images/avatar-dude.png</file>
|
||||
<file>data/images/back-pressed.png</file>
|
||||
<file>data/images/back-rest.png</file>
|
||||
<file>data/images/cover-shadow.png</file>
|
||||
<file>data/images/filter.png</file>
|
||||
<file>data/images/loved.png</file>
|
||||
<file>data/images/not-loved.png</file>
|
||||
@@ -13,6 +12,7 @@
|
||||
<file>data/images/track-placeholder.png</file>
|
||||
<file>data/images/now-playing-panel.png</file>
|
||||
<file>data/images/now-playing-speaker.png</file>
|
||||
<file>data/images/now-playing-speaker-dark.png</file>
|
||||
<file>data/images/pause-pressed.png</file>
|
||||
<file>data/images/pause-rest.png</file>
|
||||
<file>data/images/play-pressed.png</file>
|
||||
@@ -72,6 +72,7 @@
|
||||
<file>data/images/music-icon.png</file>
|
||||
<file>data/images/configure.png</file>
|
||||
<file>data/images/create-playlist.png</file>
|
||||
<file>data/images/private-listening.png</file>
|
||||
<file>data/images/add.png</file>
|
||||
<file>data/images/recently-played.png</file>
|
||||
<file>data/images/supercollection.png</file>
|
||||
@@ -91,9 +92,13 @@
|
||||
<file>data/images/artist-icon.png</file>
|
||||
<file>data/images/album-icon.png</file>
|
||||
<file>data/images/search-icon.png</file>
|
||||
<file>data/images/star-hover.png</file>
|
||||
<file>data/images/starred.png</file>
|
||||
<file>data/images/star-unstarred.png</file>
|
||||
<file>data/images/track-icon-22x22.png</file>
|
||||
<file>data/images/track-icon-32x32.png</file>
|
||||
<file>data/images/track-icon-16x16.png</file>
|
||||
<file>data/images/apply-check.png</file>
|
||||
<file>data/stylesheets/topbar-radiobuttons.css</file>
|
||||
<file>data/icons/tomahawk-icon-16x16.png</file>
|
||||
<file>data/icons/tomahawk-icon-32x32.png</file>
|
||||
@@ -108,6 +113,7 @@
|
||||
<file>data/sql/dbmigrate-23_to_24.sql</file>
|
||||
<file>data/sql/dbmigrate-24_to_25.sql</file>
|
||||
<file>data/sql/dbmigrate-25_to_26.sql</file>
|
||||
<file>data/sql/dbmigrate-26_to_27.sql</file>
|
||||
<file>data/js/tomahawk.js</file>
|
||||
<file>data/images/avatar_frame.png</file>
|
||||
<file>data/images/drop-all-songs.png</file>
|
||||
@@ -115,5 +121,15 @@
|
||||
<file>data/images/drop-top-songs.png</file>
|
||||
<file>data/images/drop-song.png</file>
|
||||
<file>data/images/drop-album.png</file>
|
||||
<file>data/images/spotify-logo.png</file>
|
||||
<file>data/images/itunes.png</file>
|
||||
<file>data/images/uploading.png</file>
|
||||
<file>data/images/downloading.png</file>
|
||||
<file>data/images/headphones.png</file>
|
||||
<file>data/images/headphones-off.png</file>
|
||||
<file>data/images/headphones-sidebar.png</file>
|
||||
<file>data/images/headphones-bigger.png</file>
|
||||
<file>data/images/no-album-no-case.png</file>
|
||||
<file>data/images/rdio.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -1,8 +1,3 @@
|
||||
SET( OS_SPECIFIC_LINK_LIBRARIES
|
||||
${OS_SPECIFIC_LINK_LIBRARIES}
|
||||
tomahawklib
|
||||
)
|
||||
|
||||
FILE( GLOB _icons "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-*.png" )
|
||||
FOREACH( _file ${_icons} )
|
||||
STRING( REPLACE "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-" "" _res ${_file} )
|
||||
@@ -10,6 +5,6 @@ FOREACH( _file ${_icons} )
|
||||
INSTALL( FILES ${_file} RENAME tomahawk.png DESTINATION share/icons/hicolor/${_res}/apps )
|
||||
ENDFOREACH( _file )
|
||||
|
||||
INSTALL( FILES ${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon.svg RENAME tomahawk.svg DESTINATION share/icons/hicolor/scalable )
|
||||
INSTALL( FILES ${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon.svg RENAME tomahawk.svg DESTINATION share/icons/hicolor/scalable/apps )
|
||||
|
||||
INSTALL( FILES ${CMAKE_SOURCE_DIR}/admin/unix/tomahawk.desktop DESTINATION share/applications )
|
||||
|
@@ -1,10 +1,11 @@
|
||||
SET( TOMAHAWK_LIBRARIES tomahawklib )
|
||||
SET( TOMAHAWK_LIBRARIES tomahawklib )
|
||||
|
||||
SET( OS_SPECIFIC_LINK_LIBRARIES
|
||||
${OS_SPECIFIC_LINK_LIBRARIES}
|
||||
${COREAUDIO_LIBRARY}
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
|
||||
crypto
|
||||
SPMediaKeyTap
|
||||
|
||||
/System/Library/Frameworks/AppKit.framework
|
||||
@@ -26,12 +27,15 @@ if (APPLE)
|
||||
# Uses Darwin kernel version.
|
||||
# 9.8.0 -> 10.5/Leopard
|
||||
# 10.4.0 -> 10.6/Snow Leopard
|
||||
# 11.x.x -> Lion
|
||||
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${CMAKE_HOST_SYSTEM_VERSION})
|
||||
if (DARWIN_VERSION GREATER 9)
|
||||
if (DARWIN_VERSION GREATER 10)
|
||||
SET(LION 1)
|
||||
elseif (DARWIN_VERSION GREATER 9)
|
||||
SET(SNOW_LEOPARD 1)
|
||||
elseif (DARWIN_VERSION GREATER 8)
|
||||
SET(LEOPARD 1)
|
||||
endif (DARWIN_VERSION GREATER 9)
|
||||
endif (DARWIN_VERSION GREATER 10)
|
||||
|
||||
# Use two different sparkle update tracks for debug and release
|
||||
# We have to change the URL in the Info.plist file :-/
|
||||
|
@@ -37,12 +37,10 @@ ENDIF()
|
||||
SET( tomahawkSources ${tomahawkSources}
|
||||
web/api_v1.cpp
|
||||
|
||||
resolvers/scriptresolver.cpp
|
||||
resolvers/qtscriptresolver.cpp
|
||||
|
||||
musicscanner.cpp
|
||||
shortcuthandler.cpp
|
||||
scanmanager.cpp
|
||||
ubuntuunityhack.cpp
|
||||
tomahawkapp.cpp
|
||||
main.cpp
|
||||
)
|
||||
@@ -66,8 +64,8 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
||||
sourcetree/items/genericpageitems.cpp
|
||||
sourcetree/items/temporarypageitem.cpp
|
||||
|
||||
transferview.cpp
|
||||
PipelineStatusView.cpp
|
||||
breakpad/BreakPad.cpp
|
||||
|
||||
tomahawktrayicon.cpp
|
||||
audiocontrols.cpp
|
||||
settingsdialog.cpp
|
||||
@@ -78,6 +76,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
||||
settingslistdelegate.cpp
|
||||
resolversmodel.cpp
|
||||
tomahawkwindow.cpp
|
||||
LoadXSPFDialog.cpp
|
||||
)
|
||||
|
||||
SET( tomahawkHeaders ${tomahawkHeaders}
|
||||
@@ -85,11 +84,9 @@ SET( tomahawkHeaders ${tomahawkHeaders}
|
||||
|
||||
web/api_v1.h
|
||||
|
||||
resolvers/scriptresolver.h
|
||||
resolvers/qtscriptresolver.h
|
||||
|
||||
musicscanner.h
|
||||
scanmanager.h
|
||||
ubuntuunityhack.h
|
||||
shortcuthandler.h
|
||||
)
|
||||
|
||||
@@ -99,6 +96,12 @@ IF(LIBLASTFM_FOUND)
|
||||
)
|
||||
ENDIF(LIBLASTFM_FOUND)
|
||||
|
||||
IF(LIBATTICA_FOUND)
|
||||
SET( tomahawkSources ${tomahawkSources} GetNewStuffDialog.cpp GetNewStuffDelegate.cpp GetNewStuffModel.cpp )
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} GetNewStuffDialog.h GetNewStuffDelegate.h GetNewStuffModel.h )
|
||||
INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} )
|
||||
ENDIF(LIBATTICA_FOUND)
|
||||
|
||||
|
||||
SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
||||
sourcetree/sourcesmodel.h
|
||||
@@ -113,8 +116,6 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
||||
sourcetree/items/genericpageitems.h
|
||||
sourcetree/items/temporarypageitem.h
|
||||
|
||||
transferview.h
|
||||
PipelineStatusView.h
|
||||
tomahawktrayicon.h
|
||||
audiocontrols.h
|
||||
settingsdialog.h
|
||||
@@ -126,8 +127,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
||||
resolversmodel.h
|
||||
delegateconfigwrapper.h
|
||||
tomahawkwindow.h
|
||||
|
||||
Qocoa/qsearchfield.h
|
||||
LoadXSPFDialog.h
|
||||
)
|
||||
|
||||
SET( tomahawkUI ${tomahawkUI}
|
||||
@@ -137,6 +137,9 @@ SET( tomahawkUI ${tomahawkUI}
|
||||
proxydialog.ui
|
||||
|
||||
audiocontrols.ui
|
||||
|
||||
GetNewStuffDialog.ui
|
||||
LoadXSPFDialog.ui
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
@@ -157,6 +160,7 @@ INCLUDE_DIRECTORIES(
|
||||
${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb
|
||||
${THIRDPARTY_DIR}/qtweetlib/qtweetlib/src
|
||||
${THIRDPARTY_DIR}/qtweetlib/tomahawk-custom
|
||||
${THIRDPARTY_DIR}/breakpad
|
||||
|
||||
${TAGLIB_INCLUDES}
|
||||
${PHONON_INCLUDES}
|
||||
@@ -177,14 +181,12 @@ ENDIF( UNIX )
|
||||
IF( APPLE )
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap )
|
||||
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h )
|
||||
SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp Qocoa/qsearchfield_mac.mm )
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h )
|
||||
SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp )
|
||||
|
||||
IF(HAVE_SPARKLE)
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} ${SPARKLE}/Headers )
|
||||
ENDIF(HAVE_SPARKLE)
|
||||
ELSE( APPLE )
|
||||
SET( tomahawkSources ${tomahawkSources} Qocoa/qsearchfield.cpp )
|
||||
ENDIF( APPLE )
|
||||
|
||||
IF(GLOOX_FOUND)
|
||||
@@ -237,12 +239,12 @@ ENDIF(LIBLASTFM_FOUND)
|
||||
IF(GLOOX_FOUND)
|
||||
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${GLOOX_LIBRARIES} )
|
||||
ENDIF(GLOOX_FOUND)
|
||||
|
||||
IF(QCA2_FOUND)
|
||||
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} )
|
||||
ENDIF(QCA2_FOUND)
|
||||
|
||||
TARGET_LINK_LIBRARIES( tomahawk
|
||||
tomahawk_breakpad
|
||||
${LINK_LIBRARIES}
|
||||
${TOMAHAWK_LIBRARIES}
|
||||
${PHONON_LIBS}
|
||||
|
@@ -4,7 +4,7 @@ ADD_DEFINITIONS( -g )
|
||||
ADD_DEFINITIONS( -fno-operator-names )
|
||||
ADD_DEFINITIONS( -fPIC )
|
||||
|
||||
SET( QXTWEB_LIBRARIES qxtweb-standalone )
|
||||
SET( QXTWEB_LIBRARIES qxtweb-standalone )
|
||||
|
||||
IF( APPLE )
|
||||
INCLUDE( "CMakeLists.osx.txt" )
|
||||
|
@@ -3,6 +3,7 @@ SET( CMAKE_BUILD_TYPE "Release" )
|
||||
ADD_DEFINITIONS( /DNOMINMAX )
|
||||
ADD_DEFINITIONS( /DWIN32_LEAN_AND_MEAN )
|
||||
ADD_DEFINITIONS( -static-libgcc )
|
||||
ADD_DEFINITIONS( -DUNICODE )
|
||||
|
||||
SET( QXTWEB_LIBRARIES qxtweb-standalone )
|
||||
|
||||
|
323
src/GetNewStuffDelegate.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GetNewStuffDelegate.h"
|
||||
|
||||
#include "GetNewStuffModel.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include "AtticaManager.h"
|
||||
|
||||
#define PADDING 4
|
||||
#define PADDING_BETWEEN_STARS 2
|
||||
#define STAR_SIZE 12
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#define SIZEHINT_HEIGHT 70
|
||||
#else
|
||||
#define SIZEHINT_HEIGHT 60
|
||||
#endif
|
||||
|
||||
GetNewStuffDelegate::GetNewStuffDelegate( QObject* parent )
|
||||
: QStyledItemDelegate ( parent )
|
||||
, m_widestTextWidth( 0 )
|
||||
, m_hoveringOver( -1 )
|
||||
{
|
||||
m_defaultCover.load( RESPATH "images/sipplugin-online.png" );
|
||||
m_ratingStarPositive.load( RESPATH "images/starred.png" );
|
||||
m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" );
|
||||
m_onHoverStar.load( RESPATH "images/star-hover.png" );
|
||||
|
||||
m_ratingStarPositive = m_ratingStarPositive.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_ratingStarNegative = m_ratingStarNegative.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_onHoverStar = m_onHoverStar.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
const int w = SIZEHINT_HEIGHT - 2*PADDING;
|
||||
m_defaultCover = m_defaultCover.scaled( w, w, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
// save the widest wifth
|
||||
QFont f( QApplication::font() );
|
||||
f.setPointSize( f.pointSize() - 1 );
|
||||
QFontMetrics fm( f );
|
||||
QStringList l = QStringList() << tr( "Installed" ) << tr( "Installing" ) << tr( "Failed" ) << tr( "Uninstalling" );
|
||||
foreach ( const QString& str, l )
|
||||
{
|
||||
if ( fm.width( str ) > m_widestTextWidth )
|
||||
m_widestTextWidth = fm.width( str );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetNewStuffDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
|
||||
QFont titleFont = opt.font;
|
||||
titleFont.setBold( true );
|
||||
titleFont.setPointSize( titleFont.pointSize() + 2 );
|
||||
QFontMetrics titleMetrics( titleFont );
|
||||
|
||||
QFont authorFont = opt.font;
|
||||
authorFont.setItalic( true );
|
||||
authorFont.setPointSize( authorFont.pointSize() - 1 );
|
||||
QFontMetrics authorMetrics( authorFont );
|
||||
|
||||
QFont descFont = authorFont;
|
||||
descFont.setItalic( false );
|
||||
QFontMetrics descMetrics( descFont );
|
||||
|
||||
QFont installFont = opt.font;
|
||||
installFont.setPointSize( installFont.pointSize() - 1 );
|
||||
QFontMetrics installMetrics( descFont );
|
||||
|
||||
const int height = opt.rect.height();
|
||||
const int center = height / 2 + opt.rect.top();
|
||||
|
||||
// Pixmap
|
||||
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
|
||||
const int pixmapWidth = height - 2*PADDING;
|
||||
QRect pixmapRect( PADDING, PADDING + opt.rect.top(), pixmapWidth, pixmapWidth );
|
||||
if ( p.isNull() ) // default image... TODO
|
||||
p = m_defaultCover;
|
||||
else
|
||||
p = p.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
painter->drawPixmap( pixmapRect, p );
|
||||
|
||||
// Go from right edge now, stars, install button, and downloaded info
|
||||
|
||||
// install / status button
|
||||
AtticaManager::ResolverState state = static_cast< AtticaManager::ResolverState >( index.data( GetNewStuffModel::StateRole ).toInt() );
|
||||
QString actionText;
|
||||
switch( state )
|
||||
{
|
||||
case AtticaManager::Uninstalled:
|
||||
actionText = tr( "Install" );
|
||||
break;
|
||||
case AtticaManager::Installing:
|
||||
actionText = tr( "Installing" );
|
||||
break;
|
||||
case AtticaManager::Upgrading:
|
||||
actionText = tr( "Upgrading" );
|
||||
break;
|
||||
case AtticaManager::Failed:
|
||||
actionText = tr( "Failed" );
|
||||
break;
|
||||
case AtticaManager::Installed:
|
||||
actionText = tr( "Uninstall" );
|
||||
break;
|
||||
case AtticaManager::NeedsUpgrade:
|
||||
actionText = tr( "Upgrade" );
|
||||
break;
|
||||
}
|
||||
|
||||
const int btnWidth = m_widestTextWidth + 7;
|
||||
const int leftEdge = opt.rect.width() - PADDING - btnWidth - 3;
|
||||
const QRect btnRect( leftEdge, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 4 );
|
||||
m_cachedButtonRects[ QPair<int, int>(index.row(), index.column()) ] = btnRect;
|
||||
|
||||
QPen saved = painter->pen();
|
||||
painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
|
||||
|
||||
QPainterPath btnPath;
|
||||
const int radius = 3;
|
||||
//btnPath.addRoundedRect( btnRect, 3, 3 );
|
||||
// draw top half gradient
|
||||
const int btnCenter = btnRect.bottom() - ( btnRect.height() / 2 );
|
||||
btnPath.moveTo( btnRect.left(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnRect.top() + radius );
|
||||
btnPath.quadTo( QPoint( btnRect.topLeft() ), QPoint( btnRect.left() + radius, btnRect.top() ) );
|
||||
btnPath.lineTo( btnRect.right() - radius, btnRect.top() );
|
||||
btnPath.quadTo( QPoint( btnRect.topRight() ), QPoint( btnRect.right(), btnRect.top() + radius ) );
|
||||
btnPath.lineTo( btnRect.right(),btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnCenter );
|
||||
|
||||
QLinearGradient g;
|
||||
g.setColorAt( 0, QColor(54, 127, 211) );
|
||||
g.setColorAt( 0.5, QColor(43, 104, 182) );
|
||||
//painter->setPen( bg.darker() );
|
||||
painter->fillPath( btnPath, g );
|
||||
//painter->drawPath( btnPath );
|
||||
|
||||
btnPath = QPainterPath();
|
||||
btnPath.moveTo( btnRect.left(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnRect.bottom() - radius );
|
||||
btnPath.quadTo( QPoint( btnRect.bottomLeft() ), QPoint( btnRect.left() + radius, btnRect.bottom() ) );
|
||||
btnPath.lineTo( btnRect.right() - radius, btnRect.bottom() );
|
||||
btnPath.quadTo( QPoint( btnRect.bottomRight() ), QPoint( btnRect.right(), btnRect.bottom() - radius ) );
|
||||
btnPath.lineTo( btnRect.right(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnCenter );
|
||||
|
||||
g.setColorAt( 0, QColor(34, 85, 159) );
|
||||
g.setColorAt( 0.5, QColor(35, 79, 147) );
|
||||
painter->fillPath( btnPath, g );
|
||||
|
||||
painter->setFont( installFont );
|
||||
painter->drawText( btnRect, Qt::AlignCenter, actionText );
|
||||
|
||||
painter->setPen( saved );
|
||||
|
||||
// rating stars
|
||||
int rating = index.data( GetNewStuffModel::RatingRole ).toInt();
|
||||
const int ratingWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
|
||||
int runningEdge = ( btnRect.right() - btnRect.width() / 2 ) - ratingWidth / 2;
|
||||
for ( int i = 1; i < 6; i++ )
|
||||
{
|
||||
QRect r( runningEdge, btnRect.top() - m_ratingStarPositive.height() - PADDING, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
|
||||
if ( i == 1 )
|
||||
m_cachedStarRects[ QPair<int, int>(index.row(), index.column()) ] = r;
|
||||
|
||||
const bool userHasRated = index.data( GetNewStuffModel::UserHasRatedRole ).toBool();
|
||||
if ( !userHasRated && // Show on-hover animation if the user hasn't rated it yet, and is hovering over it
|
||||
m_hoveringOver > -1 &&
|
||||
m_hoveringItem == index )
|
||||
{
|
||||
if ( i <= m_hoveringOver ) // positive star
|
||||
painter->drawPixmap( r, m_onHoverStar );
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarNegative );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( i <= rating ) // positive or rated star
|
||||
{
|
||||
if ( userHasRated )
|
||||
painter->drawPixmap( r, m_onHoverStar );
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarPositive );
|
||||
}
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarNegative );
|
||||
}
|
||||
runningEdge += m_ratingStarPositive.width() + PADDING_BETWEEN_STARS;
|
||||
}
|
||||
|
||||
// downloaded num times, underneath button
|
||||
QString count = tr( "%1 downloads" ).arg( index.data( GetNewStuffModel::DownloadCounterRole ).toInt() );
|
||||
const QRect countRect( btnRect.left(), btnRect.bottom() + PADDING, btnRect.width(), opt.rect.bottom() - PADDING - btnRect.bottom() );
|
||||
QFont countFont = descFont;
|
||||
countFont.setPointSize( countFont.pointSize() - 2 );
|
||||
countFont.setBold( true );
|
||||
painter->setFont( countFont );
|
||||
painter->drawText( countRect, Qt::AlignCenter | Qt::TextWordWrap, count );
|
||||
|
||||
// author and version
|
||||
QString author = index.data( GetNewStuffModel::AuthorRole ).toString();
|
||||
const int authorWidth = authorMetrics.width( author );
|
||||
const int topTextLine = opt.rect.top() + PADDING;
|
||||
const QRect authorRect( btnRect.x() - 3*PADDING - authorWidth, topTextLine, authorWidth + 6, authorMetrics.height() );
|
||||
painter->setFont( authorFont );
|
||||
painter->drawText( authorRect, Qt::AlignCenter, author );
|
||||
|
||||
const QRect versionRect = authorRect.translated( 0, authorRect.height() );
|
||||
QString version = index.data( GetNewStuffModel::VersionRole ).toString();
|
||||
painter->drawText( versionRect, Qt::AlignCenter, version );
|
||||
|
||||
// title
|
||||
QString title = index.data( Qt::DisplayRole ).toString();
|
||||
const int rightTitleEdge = authorRect.left() - PADDING;
|
||||
const int leftTitleEdge = pixmapRect.right() + PADDING;
|
||||
const QRect textRect( leftTitleEdge, topTextLine, rightTitleEdge - leftTitleEdge, versionRect.bottom() - opt.rect.top() - PADDING );
|
||||
painter->setFont( titleFont );
|
||||
painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title );
|
||||
|
||||
// description
|
||||
QString desc = index.data( GetNewStuffModel::DescriptionRole ).toString();
|
||||
const int descWidth = btnRect.left() - leftTitleEdge - PADDING;
|
||||
const QRect descRect( leftTitleEdge, versionRect.bottom(), descWidth, opt.rect.bottom() - versionRect.bottom() + PADDING );
|
||||
painter->setFont( descFont );
|
||||
painter->drawText( descRect, Qt::AlignLeft | Qt::TextWordWrap, desc );
|
||||
}
|
||||
|
||||
|
||||
QSize
|
||||
GetNewStuffDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
Q_UNUSED( option );
|
||||
Q_UNUSED( index );
|
||||
return QSize( 200, SIZEHINT_HEIGHT );
|
||||
}
|
||||
|
||||
bool
|
||||
GetNewStuffDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
Q_UNUSED( option );
|
||||
|
||||
if ( event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseMove )
|
||||
return false;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease && m_cachedButtonRects.contains( QPair<int, int>( index.row(), index.column() ) ) )
|
||||
{
|
||||
QRect rect = m_cachedButtonRects[ QPair<int, int>( index.row(), index.column() ) ];
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
|
||||
if ( rect.contains( me->pos() ) )
|
||||
{
|
||||
model->setData( index, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_cachedStarRects.contains( QPair<int, int>( index.row(), index.column() ) ) )
|
||||
{
|
||||
QRect fullStars = m_cachedStarRects[ QPair<int, int>( index.row(), index.column() ) ];
|
||||
const int starsWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
|
||||
fullStars.setWidth( starsWidth );
|
||||
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
|
||||
if ( fullStars.contains( me->pos() ) )
|
||||
{
|
||||
const int eachStar = starsWidth / 5;
|
||||
const int clickOffset = me->pos().x() - fullStars.x();
|
||||
const int whichStar = (clickOffset / eachStar) + 1;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
model->setData( index, whichStar, GetNewStuffModel::RatingRole );
|
||||
}
|
||||
else if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
// 0-indexed
|
||||
m_hoveringOver = whichStar;
|
||||
m_hoveringItem = index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hoveringOver > -1 )
|
||||
{
|
||||
emit update( m_hoveringItem );
|
||||
m_hoveringOver = -1;
|
||||
m_hoveringItem = QPersistentModelIndex();
|
||||
}
|
||||
return false;
|
||||
}
|
50
src/GetNewStuffDelegate.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GETNEWSTUFFDELEGATE_H
|
||||
#define GETNEWSTUFFDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
|
||||
class
|
||||
GetNewStuffDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GetNewStuffDelegate( QObject* parent = 0 );
|
||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
signals:
|
||||
void update( const QModelIndex& idx );
|
||||
|
||||
protected:
|
||||
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||
|
||||
private:
|
||||
QPixmap m_defaultCover, m_onHoverStar, m_ratingStarPositive, m_ratingStarNegative;
|
||||
|
||||
int m_widestTextWidth;
|
||||
int m_hoveringOver;
|
||||
QPersistentModelIndex m_hoveringItem;
|
||||
mutable QHash< QPair<int, int>, QRect > m_cachedButtonRects;
|
||||
mutable QHash< QPair<int, int>, QRect > m_cachedStarRects;
|
||||
};
|
||||
|
||||
#endif // GETNEWSTUFFDELEGATE_H
|
54
src/GetNewStuffDialog.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GetNewStuffDialog.h"
|
||||
|
||||
#include "ui_GetNewStuffDialog.h"
|
||||
#include "GetNewStuffDelegate.h"
|
||||
#include "GetNewStuffModel.h"
|
||||
|
||||
GetNewStuffDialog::GetNewStuffDialog( QWidget* parent, Qt::WindowFlags f )
|
||||
: QDialog( parent, f )
|
||||
, ui( new Ui::GetNewStuffDialog )
|
||||
, m_model( new GetNewStuffModel( this ) )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
ui->listView->setModel( m_model );
|
||||
GetNewStuffDelegate* del = new GetNewStuffDelegate( ui->listView );
|
||||
connect( del, SIGNAL( update( QModelIndex ) ), ui->listView, SLOT( update( QModelIndex ) ) );
|
||||
ui->listView->setItemDelegate( del );
|
||||
ui->listView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
|
||||
|
||||
ui->listView->setMouseTracking( true );
|
||||
|
||||
setMinimumSize( 560, 350 );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
setMaximumSize( 560, 350 );
|
||||
setSizeGripEnabled( false );
|
||||
|
||||
ui->listView->setAttribute( Qt::WA_MacShowFocusRect, false );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
GetNewStuffDialog::~GetNewStuffDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
41
src/GetNewStuffDialog.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GETNEWSTUFFDIALOG_H
|
||||
#define GETNEWSTUFFDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class GetNewStuffModel;
|
||||
namespace Ui {
|
||||
class GetNewStuffDialog;
|
||||
}
|
||||
|
||||
class GetNewStuffDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GetNewStuffDialog( QWidget *parent = 0, Qt::WindowFlags f = 0 );
|
||||
~GetNewStuffDialog();
|
||||
|
||||
private:
|
||||
Ui::GetNewStuffDialog *ui;
|
||||
GetNewStuffModel* m_model;
|
||||
};
|
||||
|
||||
#endif // GETNEWSTUFFDIALOG_H
|
67
src/GetNewStuffDialog.ui
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GetNewStuffDialog</class>
|
||||
<widget class="QDialog" name="GetNewStuffDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>449</width>
|
||||
<height>282</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Download New Resolvers</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="listView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>GetNewStuffDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>GetNewStuffDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
156
src/GetNewStuffModel.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GetNewStuffModel.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QUrl>
|
||||
#include "AtticaManager.h"
|
||||
|
||||
GetNewStuffModel::GetNewStuffModel( QObject* parent )
|
||||
: QAbstractListModel ( parent )
|
||||
{
|
||||
|
||||
if ( AtticaManager::instance()->resolversLoaded() )
|
||||
m_contentList = AtticaManager::instance()->resolvers();
|
||||
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversReloaded( Attica::Content::List ) ), this, SLOT( resolversReloaded( Attica::Content::List ) ) );
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverStateChanged( QString ) ), this, SLOT( resolverStateChanged( QString ) ) );
|
||||
|
||||
}
|
||||
|
||||
GetNewStuffModel::~GetNewStuffModel()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GetNewStuffModel::resolversReloaded( const Attica::Content::List& resolvers )
|
||||
{
|
||||
beginResetModel();
|
||||
m_contentList = resolvers;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void
|
||||
GetNewStuffModel::resolverStateChanged( const QString& resolverId )
|
||||
{
|
||||
for ( int i = 0; i < m_contentList.count(); i++ )
|
||||
{
|
||||
const Attica::Content resolver = m_contentList[ i ];
|
||||
if ( resolver.id() == resolverId )
|
||||
{
|
||||
QModelIndex idx = index( i, 0, QModelIndex() );
|
||||
emit dataChanged( idx, idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
GetNewStuffModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() || !hasIndex( index.row(), index.column(), index.parent() ) )
|
||||
return QVariant();
|
||||
|
||||
Attica::Content resolver = m_contentList[ index.row() ];
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return resolver.name();
|
||||
case Qt::DecorationRole:
|
||||
return QVariant::fromValue< QPixmap >( AtticaManager::instance()->iconForResolver( resolver ) );
|
||||
case DownloadUrlRole:
|
||||
// TODO
|
||||
return QUrl();
|
||||
case RatingRole:
|
||||
return resolver.rating() / 20; // rating is out of 100
|
||||
case DownloadCounterRole:
|
||||
return resolver.downloads();
|
||||
case VersionRole:
|
||||
return resolver.version();
|
||||
case DescriptionRole:
|
||||
return resolver.description();
|
||||
case TypeRole:
|
||||
return ResolverType;
|
||||
case AuthorRole:
|
||||
return resolver.author();
|
||||
case StateRole:
|
||||
return (int)AtticaManager::instance()->resolverState( resolver );
|
||||
case UserHasRatedRole:
|
||||
return AtticaManager::instance()->userHasRated( resolver );
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int
|
||||
GetNewStuffModel::rowCount( const QModelIndex& parent ) const
|
||||
{
|
||||
Q_UNUSED( parent );
|
||||
return m_contentList.count();
|
||||
}
|
||||
|
||||
bool
|
||||
GetNewStuffModel::setData( const QModelIndex &index, const QVariant &value, int role )
|
||||
{
|
||||
Q_UNUSED( value );
|
||||
if ( !hasIndex( index.row(), index.column(), index.parent() ) )
|
||||
return false;
|
||||
|
||||
|
||||
Attica::Content resolver = m_contentList[ index.row() ];
|
||||
AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( resolver );
|
||||
if ( role == Qt::EditRole )
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
case AtticaManager::Uninstalled:
|
||||
// install
|
||||
AtticaManager::instance()->installResolver( resolver );
|
||||
break;
|
||||
case AtticaManager::Installing:
|
||||
case AtticaManager::Upgrading:
|
||||
// Do nothing, busy
|
||||
break;
|
||||
case AtticaManager::Installed:
|
||||
// Uninstall
|
||||
AtticaManager::instance()->uninstallResolver( resolver );
|
||||
break;
|
||||
case AtticaManager::NeedsUpgrade:
|
||||
AtticaManager::instance()->upgradeResolver( resolver );
|
||||
break;
|
||||
default:
|
||||
//FIXME -- this handles e.g. Failed
|
||||
break;
|
||||
};
|
||||
} else if ( role == RatingRole )
|
||||
{
|
||||
// For now only allow rating if a resolver is installed!
|
||||
if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade )
|
||||
return false;
|
||||
if ( AtticaManager::instance()->userHasRated( resolver ) )
|
||||
return false;
|
||||
m_contentList[ index.row() ].setRating( value.toInt() * 20 );
|
||||
AtticaManager::instance()->uploadRating( m_contentList[ index.row() ] );
|
||||
}
|
||||
emit dataChanged( index, index );
|
||||
|
||||
return true;
|
||||
}
|
64
src/GetNewStuffModel.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GETNEWSTUFFMODEL_H
|
||||
#define GETNEWSTUFFMODEL_H
|
||||
|
||||
#include <QModelIndex>
|
||||
|
||||
#include <attica/content.h>
|
||||
#include <QPixmap>
|
||||
|
||||
class GetNewStuffModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum NewStuffRoles {
|
||||
// DisplayRole is title
|
||||
// DecorationRole is qicon for item
|
||||
DownloadUrlRole = Qt::UserRole + 1,
|
||||
RatingRole = Qt::UserRole + 2,
|
||||
DownloadCounterRole = Qt::UserRole + 3,
|
||||
VersionRole = Qt::UserRole + 4,
|
||||
DescriptionRole = Qt::UserRole + 5,
|
||||
TypeRole = Qt::UserRole + 6, // Category in attica-speak. What sort of item this is (resolver, etc).
|
||||
AuthorRole = Qt::UserRole + 7,
|
||||
StateRole = Qt::UserRole + 8,
|
||||
UserHasRatedRole = Qt::UserRole + 9
|
||||
};
|
||||
|
||||
enum Types {
|
||||
ResolverType = 0,
|
||||
};
|
||||
|
||||
explicit GetNewStuffModel( QObject* parent = 0 );
|
||||
virtual ~GetNewStuffModel();
|
||||
|
||||
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
|
||||
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
|
||||
virtual bool setData( const QModelIndex &index, const QVariant &value, int role );
|
||||
|
||||
private slots:
|
||||
void resolversReloaded( const Attica::Content::List& );
|
||||
void resolverStateChanged( const QString& resolverId );
|
||||
|
||||
private:
|
||||
Attica::Content::List m_contentList;
|
||||
};
|
||||
|
||||
#endif // GETNEWSTUFFMODEL_H
|
61
src/LoadXSPFDialog.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LoadXSPFDialog.h"
|
||||
|
||||
#include "ui_LoadXSPFDialog.h"
|
||||
#include <QFileDialog>
|
||||
|
||||
LoadXSPFDialog::LoadXSPFDialog( QWidget* parent, Qt::WindowFlags f )
|
||||
: QDialog( parent, f )
|
||||
, m_ui( new Ui_LoadXSPF )
|
||||
{
|
||||
m_ui->setupUi( this );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
m_ui->horizontalLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
m_ui->horizontalLayout->setSpacing( 5 );
|
||||
m_ui->verticalLayout->setContentsMargins( 0, 10, 0, 0 );
|
||||
m_ui->verticalLayout->setSpacing( 0 );
|
||||
#endif
|
||||
|
||||
connect( m_ui->navigateButton, SIGNAL( clicked( bool ) ), this, SLOT( getLocalFile() ) );
|
||||
}
|
||||
|
||||
LoadXSPFDialog::~LoadXSPFDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LoadXSPFDialog::getLocalFile()
|
||||
{
|
||||
QString url = QFileDialog::getOpenFileName( this, tr( "Load XSPF File" ), QDir::homePath(), tr( "XSPF Files (*.xspf)" ) );
|
||||
m_ui->lineEdit->setText( url );
|
||||
}
|
||||
|
||||
QString
|
||||
LoadXSPFDialog::xspfUrl() const
|
||||
{
|
||||
return m_ui->lineEdit->text();
|
||||
}
|
||||
|
||||
bool
|
||||
LoadXSPFDialog::autoUpdate() const
|
||||
{
|
||||
return m_ui->autoUpdate->isChecked();
|
||||
}
|
43
src/LoadXSPFDialog.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LOADXSPFDIALOG_H
|
||||
#define LOADXSPFDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class Ui_LoadXSPF;
|
||||
|
||||
class LoadXSPFDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LoadXSPFDialog( QWidget* parent = 0, Qt::WindowFlags f = 0 );
|
||||
virtual ~LoadXSPFDialog();
|
||||
|
||||
QString xspfUrl() const;
|
||||
bool autoUpdate() const;
|
||||
|
||||
public slots:
|
||||
void getLocalFile();
|
||||
|
||||
private:
|
||||
Ui_LoadXSPF* m_ui;
|
||||
};
|
||||
|
||||
#endif // LOADXSPFDIALOG_H
|
102
src/LoadXSPFDialog.ui
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LoadXSPF</class>
|
||||
<widget class="QDialog" name="LoadXSPF">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>444</width>
|
||||
<height>121</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Load XSPF</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Playlist Url</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Enter URL...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="navigateButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoUpdate">
|
||||
<property name="text">
|
||||
<string>Automatically update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>LoadXSPF</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>LoadXSPF</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -16,7 +17,7 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PipelineStatusView.h"
|
||||
#include "JobStatusView.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QVBoxLayout>
|
||||
@@ -28,7 +29,7 @@
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent )
|
||||
JobStatusView::JobStatusView( AnimatedSplitter* parent )
|
||||
: AnimatedWidget( parent )
|
||||
, m_parent( parent )
|
||||
{
|
||||
@@ -76,7 +77,7 @@ PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent )
|
||||
|
||||
|
||||
void
|
||||
PipelineStatusView::onPipelineUpdate( const query_ptr& query )
|
||||
JobStatusView::onPipelineUpdate( const query_ptr& query )
|
||||
{
|
||||
QTreeWidgetItem* ti = m_tree->invisibleRootItem()->child( 0 );
|
||||
|
||||
@@ -100,7 +101,7 @@ PipelineStatusView::onPipelineUpdate( const query_ptr& query )
|
||||
|
||||
|
||||
QSize
|
||||
PipelineStatusView::sizeHint() const
|
||||
JobStatusView::sizeHint() const
|
||||
{
|
||||
unsigned int y = 0;
|
||||
y += m_tree->header()->height();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -16,23 +17,24 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPELINESTATUSVIEW_H
|
||||
#define PIPELINESTATUSVIEW_H
|
||||
#ifndef JOBSTATUSVIEW_H
|
||||
#define JOBSTATUSVIEW_H
|
||||
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "utils/animatedsplitter.h"
|
||||
#include "widgets/animatedsplitter.h"
|
||||
#include "query.h"
|
||||
|
||||
class StreamConnection;
|
||||
|
||||
class PipelineStatusView : public AnimatedWidget
|
||||
class JobStatusView : public AnimatedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PipelineStatusView( AnimatedSplitter* parent );
|
||||
virtual ~PipelineStatusView()
|
||||
explicit JobStatusView( AnimatedSplitter* parent );
|
||||
virtual ~JobStatusView()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,8 +44,8 @@ private slots:
|
||||
void onPipelineUpdate( const Tomahawk::query_ptr& query = Tomahawk::query_ptr() );
|
||||
|
||||
private:
|
||||
QTreeWidget* m_tree;
|
||||
QTreeView* m_tree;
|
||||
AnimatedSplitter* m_parent;
|
||||
};
|
||||
|
||||
#endif // TRANSFERVIEW_H
|
||||
#endif // JOBSTATUSVIEW_H
|
||||
|
@@ -19,23 +19,21 @@
|
||||
#include "audiocontrols.h"
|
||||
#include "ui_audiocontrols.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QDropEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtGui/QDropEvent>
|
||||
#include <QtGui/QMouseEvent>
|
||||
|
||||
#include "audio/audioengine.h"
|
||||
#include "viewmanager.h"
|
||||
#include "playlist/playlistview.h"
|
||||
#include "database/database.h"
|
||||
#include "database/databasecommand_socialaction.h"
|
||||
|
||||
#include "album.h"
|
||||
|
||||
#include "utils/imagebutton.h"
|
||||
#include "widgets/imagebutton.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <globalactionmanager.h>
|
||||
#include "album.h"
|
||||
#include "dropjob.h"
|
||||
#include "globalactionmanager.h"
|
||||
#include "viewmanager.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -47,7 +45,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
, ui( new Ui::AudioControls )
|
||||
, m_repeatMode( PlaylistInterface::NoRepeat )
|
||||
, m_shuffled( false )
|
||||
, m_dropAreaExpanded( false )
|
||||
, m_lastSliderCheck( 0 )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
setAcceptDrops( true );
|
||||
@@ -89,9 +87,13 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
|
||||
ui->loveButton->setCheckable( true );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
ui->ownerLabel->setForegroundRole( QPalette::Text );
|
||||
#else
|
||||
ui->ownerLabel->setForegroundRole( QPalette::Dark );
|
||||
#endif
|
||||
ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
|
||||
|
||||
|
||||
ui->seekSlider->setEnabled( true );
|
||||
ui->volumeSlider->setRange( 0, 100 );
|
||||
ui->volumeSlider->setValue( AudioEngine::instance()->volume() );
|
||||
@@ -100,7 +102,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->seekSlider->setTimeLine( &m_sliderTimeLine );
|
||||
|
||||
connect( &m_sliderTimeLine, SIGNAL( frameChanged( int ) ), ui->seekSlider, SLOT( setValue( int ) ) );
|
||||
|
||||
|
||||
connect( ui->seekSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( seek( int ) ) );
|
||||
connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( setVolume( int ) ) );
|
||||
connect( ui->prevButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( previous() ) );
|
||||
@@ -110,8 +112,8 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
connect( ui->volumeLowButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( lowerVolume() ) );
|
||||
connect( ui->volumeHighButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( raiseVolume() ) );
|
||||
|
||||
connect( ui->playPauseButton, SIGNAL( clicked() ), this, SIGNAL( playPressed() ) );
|
||||
connect( ui->pauseButton, SIGNAL( clicked() ), this, SIGNAL( pausePressed() ) );
|
||||
connect( ui->playPauseButton, SIGNAL( clicked() ), SIGNAL( playPressed() ) );
|
||||
connect( ui->pauseButton, SIGNAL( clicked() ), SIGNAL( pausePressed() ) );
|
||||
|
||||
connect( ui->repeatButton, SIGNAL( clicked() ), SLOT( onRepeatClicked() ) );
|
||||
connect( ui->shuffleButton, SIGNAL( clicked() ), SLOT( onShuffleClicked() ) );
|
||||
@@ -131,7 +133,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
connect( AudioEngine::instance(), SIGNAL( timerMilliSeconds( qint64 ) ), SLOT( onPlaybackTimer( qint64 ) ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( volumeChanged( int ) ), SLOT( onVolumeChanged( int ) ) );
|
||||
|
||||
m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" )
|
||||
m_defaultCover = QPixmap( RESPATH "images/no-album-no-case.png" )
|
||||
.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
@@ -149,46 +151,6 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->stackedLayout->setSizeConstraint( QLayout::SetFixedSize );
|
||||
|
||||
onPlaybackStopped(); // initial state
|
||||
|
||||
|
||||
m_dragAnimation = new QPropertyAnimation( this, "dropAreaSize", this );
|
||||
m_dragAnimation->setStartValue( 0 );
|
||||
m_dragAnimation->setDuration( 300 );
|
||||
m_dragAnimation->setEasingCurve( QEasingCurve::Linear );
|
||||
connect( m_dragAnimation, SIGNAL( finished() ), SLOT(dragAnimationFinished()));
|
||||
|
||||
m_dropAreaCollapseTimer.setInterval( 300 );
|
||||
m_dropAreaCollapseTimer.setSingleShot( true );
|
||||
connect( &m_dropAreaCollapseTimer, SIGNAL( timeout() ), this, SLOT( collapseDropMenu() ) );
|
||||
|
||||
connect( ui->metaDataDropArea, SIGNAL( dropReceived( QDropEvent* ) ), this, SLOT( dropReceived( QDropEvent* ) ) );
|
||||
connect( ui->metaDataDropArea, SIGNAL( mouseLeft() ), &m_dropAreaCollapseTimer, SLOT( start() ) );
|
||||
|
||||
DropMenuEntry *trackEntry = new DropMenuEntry( QPixmap(":/data/images/drop-song.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
|
||||
"Track",
|
||||
DropJob::DropFlagTrack );
|
||||
ui->metaDataDropArea->addEntry( trackEntry, true );
|
||||
|
||||
DropMenuEntry *albumEntry = new DropMenuEntry( QPixmap(":/data/images/drop-album.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
|
||||
"Album",
|
||||
DropJob::DropFlagAlbum );
|
||||
ui->metaDataDropArea->addEntry( albumEntry );
|
||||
|
||||
DropMenuEntry *artistEntry = new DropMenuEntry( QPixmap(":/data/images/drop-all-songs.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
|
||||
"Artist",
|
||||
DropJob::DropFlagArtist );
|
||||
ui->metaDataDropArea->addEntry( artistEntry );
|
||||
|
||||
DropMenuEntry *localEntry = new DropMenuEntry( QPixmap(":/data/images/drop-local-songs.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
|
||||
"Local",
|
||||
DropJob::DropFlagAlbum | DropJob::DropFlagLocal );
|
||||
ui->metaDataDropArea->addEntry( localEntry );
|
||||
|
||||
DropMenuEntry *top10Entry = new DropMenuEntry( QPixmap(":/data/images/drop-top-songs.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
|
||||
"Top 10",
|
||||
DropJob::DropFlagArtist | DropJob::DropFlagTop10 );
|
||||
ui->metaDataDropArea->addEntry( top10Entry );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -230,7 +192,7 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
|
||||
if ( result.isNull() )
|
||||
return;
|
||||
|
||||
|
||||
if ( m_currentTrack.isNull() || ( !m_currentTrack.isNull() && m_currentTrack.data()->id() != result.data()->id() ) )
|
||||
onPlaybackLoading( result );
|
||||
|
||||
@@ -238,7 +200,7 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
|
||||
if ( duration == -1 )
|
||||
duration = result.data()->duration() * 1000;
|
||||
|
||||
|
||||
ui->seekSlider->setRange( 0, duration );
|
||||
ui->seekSlider->setValue( 0 );
|
||||
|
||||
@@ -249,15 +211,18 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
m_seekMsecs = -1;
|
||||
|
||||
ui->seekSlider->setVisible( true );
|
||||
|
||||
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
|
||||
|
||||
m_noTimeChange = false;
|
||||
m_lastSliderCheck = 0;
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
trackInfo["artist"] = result->artist()->name();
|
||||
trackInfo["album"] = result->album()->name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = s_acInfoIdentifier;
|
||||
requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt;
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo );
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
|
||||
requestData.customData = QVariantMap();
|
||||
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
|
||||
@@ -328,9 +293,10 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
|
||||
result->loadSocialActions();
|
||||
|
||||
connect( result.data(), SIGNAL( socialActionsLoaded() ), this, SLOT( socialActionsLoaded() ) );
|
||||
connect( result.data(), SIGNAL( socialActionsLoaded() ), SLOT( socialActionsLoaded() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::socialActionsLoaded()
|
||||
{
|
||||
@@ -361,6 +327,7 @@ AudioControls::onPlaybackPaused()
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::onPlaybackResumed()
|
||||
{
|
||||
@@ -406,7 +373,11 @@ AudioControls::onPlaybackStopped()
|
||||
void
|
||||
AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
{
|
||||
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << " msElapsed = " << msElapsed << " and timer current time = " << m_sliderTimeLine.currentTime() << " and m_seekMsecs = " << m_seekMsecs;
|
||||
// tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime() << "and m_seekMsecs =" << m_seekMsecs;
|
||||
if ( msElapsed > 0 && msElapsed - 500 < m_lastSliderCheck )
|
||||
return;
|
||||
m_lastSliderCheck = msElapsed;
|
||||
|
||||
if ( m_currentTrack.isNull() )
|
||||
return;
|
||||
|
||||
@@ -415,10 +386,23 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
const int seconds = msElapsed / 1000;
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
|
||||
|
||||
if ( m_sliderTimeLine.currentTime() > msElapsed || m_seekMsecs != -1 )
|
||||
|
||||
if ( m_noTimeChange )
|
||||
{
|
||||
if ( m_sliderTimeLine.currentTime() != msElapsed )
|
||||
{
|
||||
m_noTimeChange = false;
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
}
|
||||
else if ( m_sliderTimeLine.currentTime() >= msElapsed || m_seekMsecs != -1 )
|
||||
{
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
|
||||
m_noTimeChange = false;
|
||||
if ( m_sliderTimeLine.currentTime() == msElapsed )
|
||||
m_noTimeChange = true;
|
||||
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
m_seekMsecs = -1;
|
||||
if ( AudioEngine::instance()->state() != AudioEngine::Paused )
|
||||
@@ -427,7 +411,7 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
else if ( m_sliderTimeLine.duration() > msElapsed && m_sliderTimeLine.state() == QTimeLine::NotRunning )
|
||||
{
|
||||
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
|
||||
m_sliderTimeLine.resume();
|
||||
m_sliderTimeLine.start();
|
||||
}
|
||||
else if ( m_sliderTimeLine.state() == QTimeLine::Paused && AudioEngine::instance()->state() != AudioEngine::Paused )
|
||||
{
|
||||
@@ -562,36 +546,7 @@ void
|
||||
AudioControls::dragEnterEvent( QDragEnterEvent* e )
|
||||
{
|
||||
if ( DropJob::acceptsMimeData( e->mimeData() ) )
|
||||
{
|
||||
e->acceptProposedAction();
|
||||
|
||||
m_dropAreaCollapseTimer.stop();
|
||||
|
||||
DropJob::DropFlags flags = DropJob::DropFlagsNone;
|
||||
|
||||
if ( e->mimeData()->hasFormat( "application/tomahawk.query.list" )
|
||||
|| e->mimeData()->hasFormat( "application/tomahawk.result.list" )
|
||||
|| e->mimeData()->hasFormat( "application/tomahawk.result" ) )
|
||||
flags = DropJob::DropFlagsAll;
|
||||
|
||||
if ( e->mimeData()->hasFormat( "application/tomahawk.metadata.album" ) )
|
||||
flags = DropJob::DropFlagAlbum | DropJob::DropFlagArtist | DropJob::DropFlagLocal | DropJob::DropFlagTop10;
|
||||
|
||||
if ( e->mimeData()->hasFormat( "application/tomahawk.metadata.artist" ) )
|
||||
flags = DropJob::DropFlagArtist | DropJob::DropFlagLocal | DropJob::DropFlagTop10;
|
||||
|
||||
ui->metaDataDropArea->setFilter( flags );
|
||||
|
||||
if( !m_dropAreaExpanded )
|
||||
{
|
||||
m_dragAnimation->stop();
|
||||
m_dragAnimation->setDirection( QAbstractAnimation::Forward );
|
||||
m_dragAnimation->setStartValue( dropAreaSize() );
|
||||
m_dragAnimation->setEndValue( ui->metaDataArea->height() );
|
||||
m_dragAnimation->start();
|
||||
m_dropAreaExpanded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -603,32 +558,6 @@ AudioControls::dragMoveEvent( QDragMoveEvent* /* e */ )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::dragLeaveEvent( QDragLeaveEvent * )
|
||||
{
|
||||
qDebug() << "******************************** dragLeaveEvent" << ui->metaDataDropArea->hovered();
|
||||
if( !ui->metaDataDropArea->hovered() )
|
||||
m_dropAreaCollapseTimer.start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::collapseDropMenu()
|
||||
{
|
||||
// Check if the menu is hovered now...
|
||||
if( ui->metaDataDropArea->hovered() )
|
||||
return;
|
||||
|
||||
m_dropAreaExpanded = false;
|
||||
|
||||
m_dragAnimation->stop();
|
||||
// m_dragAnimation->setDirection( QAbstractAnimation::Backward );
|
||||
m_dragAnimation->setStartValue( dropAreaSize() );
|
||||
m_dragAnimation->setEndValue( 0 );
|
||||
m_dragAnimation->start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::dropEvent( QDropEvent* e )
|
||||
{
|
||||
@@ -636,12 +565,10 @@ AudioControls::dropEvent( QDropEvent* e )
|
||||
if ( DropJob::acceptsMimeData( e->mimeData() ) )
|
||||
{
|
||||
DropJob *dj = new DropJob();
|
||||
dj->setDropAction( DropJob::Append );
|
||||
connect( dj, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( droppedTracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
dj->setDropFlags( ui->metaDataDropArea->activeEntry()->dropFlags() );
|
||||
dj->tracksFromMimeData( e->mimeData() );
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( collapseDropMenu() ) );
|
||||
|
||||
e->accept();
|
||||
}
|
||||
}
|
||||
@@ -652,8 +579,8 @@ AudioControls::droppedTracks( QList< query_ptr > tracks )
|
||||
{
|
||||
if ( !tracks.isEmpty() )
|
||||
{
|
||||
// queue and play the first if nothign is playing
|
||||
GlobalActionManager::instance()->handleOpenTrack( tracks.first() );
|
||||
// queue and play the first no matter what
|
||||
GlobalActionManager::instance()->handlePlayTrack( tracks.first() );
|
||||
|
||||
// just queue the rest
|
||||
for ( int i = 1; i < tracks.size(); i++ )
|
||||
@@ -667,7 +594,7 @@ AudioControls::droppedTracks( QList< query_ptr > tracks )
|
||||
void
|
||||
AudioControls::onLoveButtonClicked( bool checked )
|
||||
{
|
||||
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
trackInfo["title"] = m_currentTrack->track();
|
||||
trackInfo["artist"] = m_currentTrack->artist()->name();
|
||||
trackInfo["album"] = m_currentTrack->album()->name();
|
||||
@@ -676,7 +603,7 @@ AudioControls::onLoveButtonClicked( bool checked )
|
||||
{
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_acInfoIdentifier, Tomahawk::InfoSystem::InfoLove,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) );
|
||||
|
||||
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( m_currentTrack, QString( "Love" ), QString( "true") );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
@@ -686,7 +613,7 @@ AudioControls::onLoveButtonClicked( bool checked )
|
||||
{
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_acInfoIdentifier, Tomahawk::InfoSystem::InfoUnLove,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) );
|
||||
|
||||
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( m_currentTrack, QString( "Love" ), QString( "false" ) );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
@@ -694,28 +621,3 @@ AudioControls::onLoveButtonClicked( bool checked )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::dragAnimationFinished()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
AudioControls::dropAreaSize()
|
||||
{
|
||||
return ui->metaDataDropArea->maximumHeight();
|
||||
}
|
||||
|
||||
void
|
||||
AudioControls::setDropAreaSize( int size )
|
||||
{
|
||||
ui->metaDataDropArea->setMaximumHeight( size );
|
||||
ui->metaDataInfoArea->setMaximumHeight( ui->metaDataArea->height() - size );
|
||||
}
|
||||
|
||||
void
|
||||
AudioControls::dropReceived( QDropEvent *event )
|
||||
{
|
||||
dropEvent( event );
|
||||
}
|
||||
|
@@ -19,19 +19,18 @@
|
||||
#ifndef AUDIOCONTROLS_H
|
||||
#define AUDIOCONTROLS_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimeLine>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QTimer>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtCore/QTimeLine>
|
||||
|
||||
#include "result.h"
|
||||
#include "playlistinterface.h"
|
||||
#include "infosystem/infosystem.h"
|
||||
#include "utils/dropmenu.h"
|
||||
#include "query.h"
|
||||
|
||||
class QDropEvent;
|
||||
class QDragEnterEvent;
|
||||
class QDragMoveEvent;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AudioControls;
|
||||
@@ -40,7 +39,6 @@ namespace Ui
|
||||
class AudioControls : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( int dropAreaSize READ dropAreaSize WRITE setDropAreaSize )
|
||||
|
||||
public:
|
||||
AudioControls( QWidget* parent = 0 );
|
||||
@@ -58,12 +56,8 @@ protected:
|
||||
void changeEvent( QEvent* e );
|
||||
void dragEnterEvent ( QDragEnterEvent* );
|
||||
void dragMoveEvent ( QDragMoveEvent* );
|
||||
void dragLeaveEvent( QDragLeaveEvent * );
|
||||
void dropEvent ( QDropEvent* );
|
||||
|
||||
int dropAreaSize();
|
||||
void setDropAreaSize( int size );
|
||||
|
||||
private slots:
|
||||
void onPlaybackStarted( const Tomahawk::result_ptr& result );
|
||||
void onPlaybackLoading( const Tomahawk::result_ptr& result );
|
||||
@@ -90,10 +84,6 @@ private slots:
|
||||
|
||||
void socialActionsLoaded();
|
||||
|
||||
void collapseDropMenu();
|
||||
void dragAnimationFinished();
|
||||
void dropReceived( QDropEvent *event );
|
||||
|
||||
private:
|
||||
Ui::AudioControls *ui;
|
||||
|
||||
@@ -105,10 +95,8 @@ private:
|
||||
|
||||
QTimeLine m_sliderTimeLine;
|
||||
qint64 m_seekMsecs;
|
||||
|
||||
QPropertyAnimation *m_dragAnimation;
|
||||
bool m_dropAreaExpanded;
|
||||
QTimer m_dropAreaCollapseTimer;
|
||||
qint64 m_lastSliderCheck;
|
||||
bool m_noTimeChange;
|
||||
};
|
||||
|
||||
#endif // AUDIOCONTROLS_H
|
||||
|
@@ -28,9 +28,6 @@
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
@@ -84,14 +81,14 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<item>
|
||||
<widget class="ImageButton" name="playPauseButton">
|
||||
<property name="text">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<item>
|
||||
<widget class="ImageButton" name="pauseButton">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
@@ -125,269 +122,262 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="metaDataArea" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="margin">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>74</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="DropMenu" name="metaDataDropArea" native="true">
|
||||
<widget class="QLabel" name="coverImage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>58</width>
|
||||
<height>58</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>0</height>
|
||||
<width>58</width>
|
||||
<height>58</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="metaDataInfoArea" native="true">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>74</height>
|
||||
</size>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="coverImage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>58</width>
|
||||
<height>58</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>58</width>
|
||||
<height>58</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0,0">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="trackLabelLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QueryLabel" name="artistTrackLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Artist</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QueryLabel" name="albumLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Album</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>4</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="ImageButton" name="loveButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>love</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>13</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="ownerLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>7</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Owner</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>4</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="timeLabel">
|
||||
<property name="text">
|
||||
<string>Time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SeekSlider" name="seekSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="timeLeftLabel">
|
||||
<property name="text">
|
||||
<string>Time Left</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="trackLabelLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QueryLabel" name="artistTrackLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Artist</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QueryLabel" name="albumLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Album</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>4</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="ownerLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>7</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Owner</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="socialLayout">
|
||||
<item>
|
||||
<spacer name="socialSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ImageButton" name="loveButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>love</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>4</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="timeLabel">
|
||||
<property name="text">
|
||||
<string>Time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SeekSlider" name="seekSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="timeLeftLabel">
|
||||
<property name="text">
|
||||
<string>Time Left</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>metaDataInfoArea</zorder>
|
||||
<zorder>metaDataDropArea</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -558,18 +548,12 @@
|
||||
<customwidget>
|
||||
<class>ImageButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>utils/imagebutton.h</header>
|
||||
<header>widgets/imagebutton.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QueryLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>utils/querylabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>DropMenu</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>utils/dropmenu.h</header>
|
||||
<container>1</container>
|
||||
<header>widgets/querylabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
|
179
src/breakpad/BreakPad.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BreakPad.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QFileInfo>
|
||||
#include <string.h>
|
||||
|
||||
#define CRASH_REPORTER_BINARY "tomahawk_crash_reporter"
|
||||
|
||||
bool s_active = true;
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static bool
|
||||
LaunchUploader( const char* dump_dir, const char* minidump_id, void* that, bool succeeded )
|
||||
{
|
||||
// DON'T USE THE HEAP!!!
|
||||
// So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!
|
||||
|
||||
if ( !succeeded )
|
||||
return false;
|
||||
|
||||
const char* crashReporter = static_cast<BreakPad*>(that)->crashReporter();
|
||||
if ( !s_active || strlen( crashReporter ) == 0 )
|
||||
return false;
|
||||
|
||||
pid_t pid = fork();
|
||||
if ( pid == -1 ) // fork failed
|
||||
return false;
|
||||
if ( pid == 0 )
|
||||
{
|
||||
// we are the fork
|
||||
execl( crashReporter,
|
||||
crashReporter,
|
||||
dump_dir,
|
||||
minidump_id,
|
||||
minidump_id,
|
||||
(char*) 0 );
|
||||
|
||||
// execl replaces this process, so no more code will be executed
|
||||
// unless it failed. If it failed, then we should return false.
|
||||
printf( "Error: Can't launch CrashReporter!\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// we called fork()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BreakPad::BreakPad( const QString& path, bool active )
|
||||
#ifdef Q_OS_LINUX
|
||||
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true )
|
||||
#else
|
||||
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true, 0 )
|
||||
#endif
|
||||
{
|
||||
s_active = active;
|
||||
|
||||
QString reporter;
|
||||
QString localReporter = QString( "%1/%2" ).arg( qApp->applicationDirPath() ).arg( CRASH_REPORTER_BINARY );
|
||||
QString globalReporter = QString( "%1/%2" ).arg( CMAKE_INSTALL_PREFIX "/" CMAKE_INSTALL_LIBEXECDIR ).arg( CRASH_REPORTER_BINARY );
|
||||
|
||||
if ( QFileInfo( localReporter ).exists() )
|
||||
reporter = localReporter;
|
||||
else if ( QFileInfo( globalReporter ).exists() )
|
||||
reporter = globalReporter;
|
||||
else
|
||||
tLog() << "Could not find \"" CRASH_REPORTER_BINARY "\" in \"" CMAKE_INSTALL_PREFIX "/" CMAKE_INSTALL_LIBEXECDIR "\" or application path";
|
||||
|
||||
char* creporter;
|
||||
std::string sreporter = reporter.toStdString();
|
||||
creporter = new char[ sreporter.size() + 1 ];
|
||||
strcpy( creporter, sreporter.c_str() );
|
||||
|
||||
m_crashReporter = creporter;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
static bool
|
||||
LaunchUploader( const wchar_t* dump_dir, const wchar_t* minidump_id, void* that, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded )
|
||||
{
|
||||
if ( !succeeded )
|
||||
return false;
|
||||
|
||||
// DON'T USE THE HEAP!!!
|
||||
// So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!
|
||||
|
||||
// broken in mingw, hardcode it for now
|
||||
|
||||
// const char* productName = static_cast<BreakPad*>(that)->productName();s
|
||||
// convert productName to widechars, which sadly means the product name must be Latin1
|
||||
|
||||
wchar_t product_name[ 256 ] = L"tomahawk";;
|
||||
|
||||
// char* out = (char*)product_name;
|
||||
// const char* in = productName - 1;
|
||||
// do {
|
||||
// *out++ = *++in; //latin1 chars fit in first byte of each wchar
|
||||
// *out++ = '\0'; //every second byte is NULL
|
||||
// }
|
||||
// while (*in);
|
||||
|
||||
wchar_t command[MAX_PATH * 3 + 6];
|
||||
wcscpy( command, CRASH_REPORTER_BINARY L" \"" );
|
||||
wcscat( command, dump_dir );
|
||||
wcscat( command, L"\" \"" );
|
||||
wcscat( command, minidump_id );
|
||||
wcscat( command, L"\" \"" );
|
||||
wcscat( command, product_name );
|
||||
wcscat( command, L"\"" );
|
||||
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
ZeroMemory( &si, sizeof( si ) );
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
ZeroMemory( &pi, sizeof(pi) );
|
||||
|
||||
if ( CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ) )
|
||||
{
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
TerminateProcess( GetCurrentProcess(), 1 );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BreakPad::BreakPad( const QString& path, bool active )
|
||||
: google_breakpad::ExceptionHandler( path.toStdWString(), 0, LaunchUploader, this, true )
|
||||
{
|
||||
s_active = active;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
|
||||
void
|
||||
BreakPad::setActive( bool enabled )
|
||||
{
|
||||
s_active = enabled;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BreakPad::isActive()
|
||||
{
|
||||
return s_active;
|
||||
}
|
50
src/breakpad/BreakPad.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include "client/mac/handler/exception_handler.h"
|
||||
#elif defined WIN32
|
||||
# include "client/windows/handler/exception_handler.h"
|
||||
#elif defined __linux__
|
||||
# include "client/linux/handler/exception_handler.h"
|
||||
#endif
|
||||
|
||||
class BreakPad : public google_breakpad::ExceptionHandler
|
||||
{
|
||||
const char* m_productName; // yes! It MUST be const char[]
|
||||
const char* m_crashReporter; // again, const char[]
|
||||
|
||||
public:
|
||||
BreakPad( const QString& dump_write_dirpath, bool active );
|
||||
|
||||
~BreakPad()
|
||||
{}
|
||||
|
||||
static void setActive( bool enabled );
|
||||
static bool isActive();
|
||||
|
||||
void setProductName( const char* s ) { m_productName = s; };
|
||||
const char* productName() const { return m_productName; }
|
||||
|
||||
void setCrashReporter( const char* s ) { m_crashReporter = s; };
|
||||
const char* crashReporter() const { return m_crashReporter; }
|
||||
};
|
||||
|
||||
#undef char
|
25
src/breakpad/CrashReporter/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
PROJECT( CrashReporter )
|
||||
|
||||
|
||||
FIND_PACKAGE( Qt4 REQUIRED )
|
||||
SET( QT_USE_QTNETWORK TRUE )
|
||||
|
||||
|
||||
SET( crashreporter_SOURCES main.cpp CrashReporter.cpp )
|
||||
SET( crashreporter_HEADERS CrashReporter.h )
|
||||
SET( crashreporter_UI CrashReporter.ui )
|
||||
SET( crashreporter_RC ../../../resources.qrc )
|
||||
|
||||
QT4_WRAP_CPP( crashreporter_HEADERS_MOC ${crashreporter_HEADERS} )
|
||||
QT4_WRAP_UI( crashreporter_UI_HEADERS ${crashreporter_UI} )
|
||||
QT4_ADD_RESOURCES( crashreporter_RC_RCC ${crashreporter_RC} )
|
||||
|
||||
INCLUDE( ${QT_USE_FILE} )
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src ../../libtomahawk )
|
||||
ADD_DEFINITIONS( ${QT_DEFINITIONS} )
|
||||
|
||||
ADD_EXECUTABLE( tomahawk_crash_reporter WIN32 ${crashreporter_SOURCES} ${crashreporter_HEADERS_MOC} ${crashreporter_UI_HEADERS} ${crashreporter_RC_RCC} )
|
||||
TARGET_LINK_LIBRARIES( tomahawk_crash_reporter ${QT_LIBRARIES} tomahawklib )
|
||||
|
||||
INCLUDE(GNUInstallDirs)
|
||||
install(TARGETS tomahawk_crash_reporter RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR})
|
186
src/breakpad/CrashReporter/CrashReporter.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CrashReporter.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
#include <QHttp>
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
|
||||
#define LOGFILE TomahawkUtils::appLogDir().filePath( "Tomahawk.log" ).toLocal8Bit()
|
||||
#define RESPATH ":/data/"
|
||||
|
||||
|
||||
CrashReporter::CrashReporter( const QStringList& args )
|
||||
{
|
||||
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
|
||||
|
||||
ui.setupUi( this );
|
||||
|
||||
ui.logoLabel->setPixmap( QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ).scaled( QSize( 55, 55 ), Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
|
||||
ui.progressBar->setRange( 0, 100 );
|
||||
ui.progressBar->setValue( 0 );
|
||||
ui.progressLabel->setPalette( Qt::gray );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
QFont f = ui.bottomLabel->font();
|
||||
f.setPointSize( 10 );
|
||||
ui.bottomLabel->setFont( f );
|
||||
f.setPointSize( 11 );
|
||||
ui.progressLabel->setFont( f );
|
||||
ui.progressLabel->setIndent( 3 );
|
||||
#else
|
||||
ui.vboxLayout->setSpacing( 16 );
|
||||
ui.progressBar->setTextVisible( false );
|
||||
ui.progressLabel->setIndent( 1 );
|
||||
ui.bottomLabel->setDisabled( true );
|
||||
ui.bottomLabel->setIndent( 1 );
|
||||
|
||||
// adjust the spacer since we adjusted the spacing above
|
||||
for ( int x = 0; x < ui.vboxLayout->count(); ++x )
|
||||
{
|
||||
if ( QSpacerItem* spacer = ui.vboxLayout->itemAt( x )->spacerItem() )
|
||||
{
|
||||
spacer->changeSize( 6, 2, QSizePolicy::Minimum, QSizePolicy::Fixed );
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif //Q_WS_MAC
|
||||
|
||||
m_http = new QHttp( "oops.tomahawk-player.org", 80, this );
|
||||
|
||||
connect( m_http, SIGNAL( done( bool ) ), SLOT( onDone() ), Qt::QueuedConnection );
|
||||
connect( m_http, SIGNAL( dataSendProgress( int, int ) ), SLOT( onProgress( int, int ) ) );
|
||||
|
||||
m_dir = args.value( 1 );
|
||||
m_minidump = m_dir + '/' + args.value( 2 ) + ".dmp";
|
||||
m_product_name = args.value( 3 );
|
||||
|
||||
setFixedSize( sizeHint() );
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( send() ) );
|
||||
}
|
||||
|
||||
|
||||
static QByteArray
|
||||
contents( const QString& path )
|
||||
{
|
||||
QFile f( path );
|
||||
f.open( QFile::ReadOnly );
|
||||
return f.readAll();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CrashReporter::send()
|
||||
{
|
||||
QByteArray body;
|
||||
|
||||
// socorro expects a 10 digit build id
|
||||
QRegExp rx( "(\\d+\\.\\d+\\.\\d+).(\\d+)" );
|
||||
rx.exactMatch( TomahawkUtils::appFriendlyVersion() );
|
||||
QString const version = rx.cap( 1 );
|
||||
QString const buildId = rx.cap( 2 ).leftJustified( 10, '0' );
|
||||
|
||||
// add parameters
|
||||
typedef QPair<QByteArray, QByteArray> Pair;
|
||||
QList<Pair> pairs;
|
||||
pairs << Pair( "BuildID", buildId.toUtf8() )
|
||||
<< Pair( "ProductName", m_product_name.toUtf8() )
|
||||
<< Pair( "Version", TomahawkUtils::appFriendlyVersion().toLocal8Bit() )
|
||||
<< Pair( "Vendor", "Tomahawk" )
|
||||
<< Pair( "timestamp", QByteArray::number( QDateTime::currentDateTime().toTime_t() ) );
|
||||
|
||||
foreach ( Pair const pair, pairs )
|
||||
{
|
||||
body += "--thkboundary\r\n";
|
||||
body += "Content-Disposition: form-data; name=\"" +
|
||||
pair.first + "\"\r\n\r\n" +
|
||||
pair.second + "\r\n";
|
||||
}
|
||||
|
||||
// add minidump file
|
||||
body += "--thkboundary\r\n";
|
||||
body += "Content-Disposition: form-data; name=\"upload_file_minidump\"; filename=\""
|
||||
+ QFileInfo( m_minidump ).fileName() + "\"\r\n";
|
||||
body += "Content-Type: application/octet-stream\r\n";
|
||||
body += "\r\n";
|
||||
body += contents( m_minidump );
|
||||
body += "\r\n";
|
||||
|
||||
// add logfile
|
||||
body += "--thkboundary\r\n";
|
||||
body += "Content-Disposition: form-data; name=\"upload_file_tomahawklog\"; filename=\"Tomahawk.log\"\r\n";
|
||||
body += "Content-Type: application/x-gzip\r\n";
|
||||
body += "\r\n";
|
||||
body += qCompress( contents( LOGFILE ) );
|
||||
body += "\r\n";
|
||||
body += "--thkboundary--\r\n";
|
||||
|
||||
QHttpRequestHeader header( "POST", "/addreport.php" );
|
||||
header.setContentType( "multipart/form-data; boundary=thkboundary" );
|
||||
header.setValue( "HOST", "oops.tomahawk-player.org" );
|
||||
|
||||
m_http->request( header, body );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CrashReporter::onProgress( int done, int total )
|
||||
{
|
||||
if ( total )
|
||||
{
|
||||
QString const msg = tr( "Uploaded %L1 of %L2 KB." ).arg( done / 1024 ).arg( total / 1024 );
|
||||
|
||||
ui.progressBar->setMaximum( total );
|
||||
ui.progressBar->setValue( done );
|
||||
ui.progressLabel->setText( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CrashReporter::onDone()
|
||||
{
|
||||
QByteArray data = m_http->readAll();
|
||||
ui.progressBar->setValue( ui.progressBar->maximum() );
|
||||
ui.button->setText( tr( "Close" ) );
|
||||
|
||||
QString const response = QString::fromUtf8( data );
|
||||
|
||||
if ( m_http->error() != QHttp::NoError || !response.startsWith( "CrashID=" ) )
|
||||
{
|
||||
onFail( m_http->error(), m_http->errorString() );
|
||||
}
|
||||
else
|
||||
ui.progressLabel->setText( tr( "Sent! <b>Many thanks</b>." ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CrashReporter::onFail( int error, const QString& errorString )
|
||||
{
|
||||
ui.button->setText( tr( "Close" ) );
|
||||
ui.progressLabel->setText( tr( "Failed to send crash info." ) );
|
||||
qDebug() << "Error:" << error << errorString;
|
||||
}
|
@@ -16,34 +16,37 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "databasecommand_loadfile.h"
|
||||
#ifndef CRASHREPORTER_H
|
||||
#define CRASHREPORTER_H
|
||||
|
||||
#include "databaseimpl.h"
|
||||
#include "collection.h"
|
||||
#include "utils/logger.h"
|
||||
#include <QDialog>
|
||||
#include <QFile>
|
||||
|
||||
#include "ui_CrashReporter.h"
|
||||
|
||||
|
||||
DatabaseCommand_LoadFile::DatabaseCommand_LoadFile( const QString& id, QObject* parent )
|
||||
: DatabaseCommand( parent )
|
||||
, m_id( id )
|
||||
class CrashReporter : public QDialog
|
||||
{
|
||||
}
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CrashReporter( const QStringList& argv );
|
||||
|
||||
void
|
||||
DatabaseCommand_LoadFile::exec( DatabaseImpl* dbi )
|
||||
{
|
||||
Tomahawk::result_ptr r;
|
||||
// file ids internally are really ints, at least for now:
|
||||
bool ok;
|
||||
do
|
||||
{
|
||||
unsigned int fid = m_id.toInt( &ok );
|
||||
if( !ok )
|
||||
break;
|
||||
private:
|
||||
Ui::CrashReporter ui;
|
||||
|
||||
r = dbi->file( fid );
|
||||
} while( false );
|
||||
QString m_minidump;
|
||||
QString m_dir;
|
||||
QString m_product_name;
|
||||
class QHttp* m_http;
|
||||
|
||||
emit result( r );
|
||||
}
|
||||
public slots:
|
||||
void send();
|
||||
|
||||
private slots:
|
||||
void onDone();
|
||||
void onProgress( int done, int total );
|
||||
void onFail( int error, const QString& errorString );
|
||||
};
|
||||
|
||||
#endif // CRASHREPORTER_H
|
223
src/breakpad/CrashReporter/CrashReporter.ui
Normal file
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CrashReporter</class>
|
||||
<widget class="QDialog" name="CrashReporter">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>438</width>
|
||||
<height>196</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tomahawk Crash Reporter</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="logoLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>55</width>
|
||||
<height>55</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>55</width>
|
||||
<height>55</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="topLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><p><b>Sorry!</b>&nbsp;Tomahawk crashed. Information about the crash is now being sent to Tomahawk HQ so that we can fix the bug.</p></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="progressLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Abort</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="bottomLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>You can disable sending crash reports in the configuration dialog.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>button</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>CrashReporter</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>424</x>
|
||||
<y>154</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>247</x>
|
||||
<y>195</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
56
src/breakpad/CrashReporter/main.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CrashReporter.h"
|
||||
|
||||
#include <QTranslator>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
const char* k_usage =
|
||||
"Usage:\n"
|
||||
" CrashReporter <logDir> <dumpFileName> <productName>\n";
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
// used by some Qt stuff, eg QSettings
|
||||
// leave first! As Settings object is created quickly
|
||||
QCoreApplication::setApplicationName( "Tomahawk" );
|
||||
QCoreApplication::setOrganizationName( "Tomahawk" );
|
||||
QCoreApplication::setOrganizationDomain( "tomahawk-player.org" );
|
||||
|
||||
QApplication app( argc, argv );
|
||||
|
||||
QString langCode;
|
||||
QTranslator translatorApp;
|
||||
QTranslator translatorQt;
|
||||
|
||||
/* app.installTranslator( &translatorApp );
|
||||
app.installTranslator( &translatorQt );*/
|
||||
|
||||
if ( app.arguments().size() != 4 )
|
||||
{
|
||||
std::cout << k_usage;
|
||||
return 1;
|
||||
}
|
||||
|
||||
CrashReporter reporter( app.arguments() );
|
||||
reporter.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
@@ -9,8 +9,10 @@
|
||||
#cmakedefine DEBUG_BUILD
|
||||
|
||||
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
#define CMAKE_INSTALL_LIBEXECDIR "${CMAKE_INSTALL_LIBEXECDIR}"
|
||||
#define CMAKE_SYSTEM "${CMAKE_SYSTEM}"
|
||||
|
||||
#cmakedefine LION
|
||||
#cmakedefine SNOW_LEOPARD
|
||||
#cmakedefine LEOPARD
|
||||
#cmakedefine HAVE_SPARKLE
|
||||
@@ -18,5 +20,6 @@
|
||||
#cmakedefine LIBLASTFM_FOUND
|
||||
#cmakedefine GLOOX_FOUND
|
||||
#cmakedefine QCA2_FOUND
|
||||
#cmakedefine LIBATTICA_FOUND
|
||||
|
||||
#endif // CONFIG_H_IN
|
||||
|
@@ -30,7 +30,7 @@ public:
|
||||
DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf )
|
||||
{
|
||||
m_widget->setWindowFlags( Qt::Sheet );
|
||||
#ifdef Q_OS_MAC
|
||||
#ifdef Q_WS_MAC
|
||||
m_widget->setVisible( true );
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
setLayout( v );
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#ifdef Q_WS_MAC
|
||||
setSizeGripEnabled( false );
|
||||
setMinimumSize( sizeHint() );
|
||||
setMaximumSize( sizeHint() ); // to remove the resize grip on osx this is the only way
|
||||
@@ -86,7 +86,8 @@ public slots:
|
||||
m_widget->setVisible( false );
|
||||
}
|
||||
|
||||
void updateSizeHint() {
|
||||
void updateSizeHint()
|
||||
{
|
||||
hide();
|
||||
setSizeGripEnabled( false );
|
||||
setMinimumSize( sizeHint() );
|
||||
|
@@ -123,6 +123,7 @@ void DiagnosticsDialog::updateLogView()
|
||||
|
||||
Q_FOREACH( const QString &peerId, sip->peersOnline() )
|
||||
{
|
||||
/* enable this again, when we check the source has this peerId
|
||||
bool connected = false;
|
||||
Q_FOREACH( const Tomahawk::source_ptr &source, sources )
|
||||
{
|
||||
@@ -131,33 +132,35 @@ void DiagnosticsDialog::updateLogView()
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
QString versionString = SipHandler::instance()->versionString( peerId );
|
||||
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
|
||||
if( !sipInfo.isValid() )
|
||||
log.append(
|
||||
QString(" %1: %2 (%3) %4\n")
|
||||
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( "sipinfo invalid" )
|
||||
.arg( connected ? "connected" : "not connected")
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
else if( sipInfo.isVisible() )
|
||||
log.append(
|
||||
QString(" %1: %2:%3 (%4) %5\n")
|
||||
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( sipInfo.host().hostName() )
|
||||
.arg( sipInfo.port() )
|
||||
.arg( connected ? "connected" : "not connected")
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
|
||||
);
|
||||
else
|
||||
log.append(
|
||||
QString(" %1: visible: false (%2) %3\n")
|
||||
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( connected ? "connected" : "not connected")
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
|
||||
);
|
||||
}
|
||||
log.append("\n");
|
||||
|
517
src/libtomahawk/AtticaManager.cpp
Normal file
@@ -0,0 +1,517 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AtticaManager.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
#include <attica/downloaditem.h>
|
||||
#include <quazip.h>
|
||||
#include <quazipfile.h>
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QTemporaryFile>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
using namespace Attica;
|
||||
|
||||
AtticaManager* AtticaManager::s_instance = 0;
|
||||
|
||||
|
||||
AtticaManager::AtticaManager( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
connect( &m_manager, SIGNAL( providerAdded( Attica::Provider ) ), this, SLOT( providerAdded( Attica::Provider ) ) );
|
||||
|
||||
// resolvers
|
||||
m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) );
|
||||
|
||||
qRegisterMetaType< Attica::Content >( "Attica::Content" );
|
||||
}
|
||||
|
||||
|
||||
AtticaManager::~AtticaManager()
|
||||
{
|
||||
savePixmapsToCache();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::loadPixmapsFromCache()
|
||||
{
|
||||
QDir cacheDir = TomahawkUtils::appDataDir();
|
||||
if ( !cacheDir.cd( "atticacache" ) ) // doesn't exist, no cache
|
||||
return;
|
||||
|
||||
qDebug() << "Loading resolvers from cache dir:" << cacheDir.absolutePath();
|
||||
qDebug() << "Currently we know about these resolvers:" << m_resolverStates.keys();
|
||||
foreach ( const QString& file, cacheDir.entryList( QStringList() << "*.png", QDir::Files | QDir::NoSymLinks ) )
|
||||
{
|
||||
// load all the pixmaps
|
||||
QFileInfo info( file );
|
||||
if ( !m_resolverStates.contains( info.baseName() ) )
|
||||
{
|
||||
tLog() << "Found resolver icon cached for resolver we no longer see in synchrotron repo:" << info.baseName();
|
||||
continue;
|
||||
}
|
||||
|
||||
QPixmap* icon = new QPixmap( cacheDir.absoluteFilePath( file ) );
|
||||
m_resolverStates[ info.baseName() ].pixmap = icon;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::savePixmapsToCache()
|
||||
{
|
||||
QDir cacheDir = TomahawkUtils::appDataDir();
|
||||
if ( !cacheDir.cd( "atticacache" ) ) // doesn't exist, create
|
||||
{
|
||||
cacheDir.mkdir( "atticacache" );
|
||||
cacheDir.cd( "atticache" );
|
||||
}
|
||||
|
||||
foreach( const QString& id, m_resolverStates.keys() )
|
||||
{
|
||||
if ( !m_resolverStates[ id ].pixmap )
|
||||
continue;
|
||||
|
||||
const QString filename = cacheDir.absoluteFilePath( QString( "%1.png" ).arg( id ) );
|
||||
if ( !m_resolverStates[ id ].pixmap->save( filename ) )
|
||||
{
|
||||
tLog() << "Failed to open cache file for writing:" << filename;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
AtticaManager::iconForResolver( const Content& resolver )
|
||||
{
|
||||
if ( !m_resolverStates[ resolver.id() ].pixmap )
|
||||
return QPixmap();
|
||||
|
||||
return *m_resolverStates.value( resolver.id() ).pixmap;
|
||||
}
|
||||
|
||||
|
||||
Content::List
|
||||
AtticaManager::resolvers() const
|
||||
{
|
||||
return m_resolvers;
|
||||
}
|
||||
|
||||
|
||||
AtticaManager::ResolverState
|
||||
AtticaManager::resolverState ( const Content& resolver ) const
|
||||
{
|
||||
if ( !m_resolverStates.contains( resolver.id() ) )
|
||||
{
|
||||
return AtticaManager::Uninstalled;
|
||||
}
|
||||
|
||||
return m_resolverStates[ resolver.id() ].state;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AtticaManager::resolversLoaded() const
|
||||
{
|
||||
return !m_resolvers.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
AtticaManager::pathFromId( const QString& resolverId ) const
|
||||
{
|
||||
if ( !m_resolverStates.contains( resolverId ) )
|
||||
return QString();
|
||||
|
||||
return m_resolverStates.value( resolverId ).scriptPath;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::uploadRating( const Content& c )
|
||||
{
|
||||
m_resolverStates[ c.id() ].userRating = c.rating();
|
||||
|
||||
for ( int i = 0; i < m_resolvers.count(); i++ )
|
||||
{
|
||||
if ( m_resolvers[ i ].id() == c.id() )
|
||||
{
|
||||
Attica::Content atticaContent = m_resolvers[ i ];
|
||||
atticaContent.setRating( c.rating() );
|
||||
m_resolvers[ i ] = atticaContent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TomahawkSettings::instance()->setAtticaResolverStates( m_resolverStates );
|
||||
|
||||
PostJob* job = m_resolverProvider.voteForContent( c.id(), (uint)c.rating() );
|
||||
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), job, SLOT( deleteLater() ) );
|
||||
|
||||
job->start();
|
||||
|
||||
emit resolverStateChanged( c.id() );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AtticaManager::userHasRated( const Content& c ) const
|
||||
{
|
||||
return m_resolverStates[ c.id() ].userRating != -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::providerAdded( const Provider& provider )
|
||||
{
|
||||
if ( provider.name() == "Tomahawk Resolvers" )
|
||||
{
|
||||
m_resolverProvider = provider;
|
||||
|
||||
ListJob< Content >* job = m_resolverProvider.searchContents( Category::List(), QString(), Provider::Downloads, 0, 30 );
|
||||
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolversList( Attica::BaseJob* ) ) );
|
||||
job->start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::resolversList( BaseJob* j )
|
||||
{
|
||||
ListJob< Content >* job = static_cast< ListJob< Content >* >( j );
|
||||
|
||||
m_resolvers = job->itemList();
|
||||
m_resolverStates = TomahawkSettings::instance()->atticaResolverStates();
|
||||
|
||||
// load icon cache from disk, and fetch any we are missing
|
||||
loadPixmapsFromCache();
|
||||
|
||||
foreach ( Content resolver, m_resolvers )
|
||||
{
|
||||
if ( !m_resolverStates.contains( resolver.id() ) )
|
||||
m_resolverStates.insert( resolver.id(), Resolver() );
|
||||
|
||||
if ( !m_resolverStates.value( resolver.id() ).pixmap && !resolver.icons().isEmpty() && !resolver.icons().first().url().isEmpty() )
|
||||
{
|
||||
QNetworkReply* fetch = TomahawkUtils::nam()->get( QNetworkRequest( resolver.icons().first().url() ) );
|
||||
fetch->setProperty( "resolverId", resolver.id() );
|
||||
|
||||
connect( fetch, SIGNAL( finished() ), this, SLOT( resolverIconFetched() ) );
|
||||
}
|
||||
}
|
||||
|
||||
syncServerData();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::resolverIconFetched()
|
||||
{
|
||||
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( reply );
|
||||
|
||||
const QString resolverId = reply->property( "resolverId" ).toString();
|
||||
|
||||
if ( !reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
tLog() << "Failed to fetch resolver icon image:" << reply->errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QPixmap* icon = new QPixmap;
|
||||
icon->loadFromData( data );
|
||||
m_resolverStates[ resolverId ].pixmap = icon;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::syncServerData()
|
||||
{
|
||||
// look for any newer. m_resolvers has list from server, and m_resolverStates will contain any locally installed ones
|
||||
// also update ratings
|
||||
foreach ( const QString& id, m_resolverStates.keys() )
|
||||
{
|
||||
Resolver r = m_resolverStates[ id ];
|
||||
for ( int i = 0; i < m_resolvers.size(); i++ )
|
||||
{
|
||||
Attica::Content upstream = m_resolvers[ i ];
|
||||
// same resolver
|
||||
if ( id != upstream.id() )
|
||||
continue;
|
||||
|
||||
// Update our rating with the server's idea of rating if we haven't rated it
|
||||
if ( m_resolverStates[ id ].userRating != -1 )
|
||||
{
|
||||
upstream.setRating( m_resolverStates[ id ].userRating );
|
||||
m_resolvers[ i ] = upstream;
|
||||
}
|
||||
|
||||
// DO we need to upgrade?
|
||||
if ( ( r.state == Installed || r.state == NeedsUpgrade ) &&
|
||||
!upstream.version().isEmpty() )
|
||||
{
|
||||
if ( TomahawkUtils::newerVersion( r.version, upstream.version() ) )
|
||||
{
|
||||
m_resolverStates[ id ].state = NeedsUpgrade;
|
||||
QMetaObject::invokeMethod( this, "upgradeResolver", Qt::QueuedConnection, Q_ARG( Attica::Content, upstream ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::installResolver( const Content& resolver )
|
||||
{
|
||||
Q_ASSERT( !resolver.id().isNull() );
|
||||
|
||||
if ( m_resolverStates[ resolver.id() ].state != Upgrading )
|
||||
m_resolverStates[ resolver.id() ].state = Installing;
|
||||
|
||||
m_resolverStates[ resolver.id() ].scriptPath = resolver.attribute( "mainscript" );
|
||||
m_resolverStates[ resolver.id() ].version = resolver.version();
|
||||
emit resolverStateChanged( resolver.id() );
|
||||
|
||||
ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
|
||||
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) );
|
||||
job->setProperty( "resolverId", resolver.id() );
|
||||
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::upgradeResolver( const Content& resolver )
|
||||
{
|
||||
Q_ASSERT( m_resolverStates.contains( resolver.id() ) );
|
||||
Q_ASSERT( m_resolverStates[ resolver.id() ].state == NeedsUpgrade );
|
||||
|
||||
if ( !m_resolverStates.contains( resolver.id() ) || m_resolverStates[ resolver.id() ].state != NeedsUpgrade )
|
||||
return;
|
||||
|
||||
m_resolverStates[ resolver.id() ].state = Upgrading;
|
||||
emit resolverStateChanged( resolver.id() );
|
||||
|
||||
uninstallResolver( resolver );
|
||||
installResolver( resolver );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::resolverDownloadFinished ( BaseJob* j )
|
||||
{
|
||||
ItemJob< DownloadItem >* job = static_cast< ItemJob< DownloadItem >* >( j );
|
||||
|
||||
if ( job->metadata().error() == Attica::Metadata::NoError )
|
||||
{
|
||||
DownloadItem item = job->result();
|
||||
QUrl url = item.url();
|
||||
// download the resolver itself :)
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
|
||||
reply->setProperty( "resolverId", job->property( "resolverId" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Failed to do resolver download job!" << job->metadata().error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::payloadFetched()
|
||||
{
|
||||
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( reply );
|
||||
|
||||
// we got a zip file, save it to a temporary file, then unzip it to our destination data dir
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QTemporaryFile f( QDir::tempPath() + QDir::separator() + "tomahawkattica_XXXXXX.zip" );
|
||||
if ( !f.open() )
|
||||
{
|
||||
tLog() << "Failed to write zip file to temp file:" << f.fileName();
|
||||
return;
|
||||
}
|
||||
f.write( reply->readAll() );
|
||||
f.close();
|
||||
|
||||
QString resolverId = reply->property( "resolverId" ).toString();
|
||||
QDir dir( extractPayload( f.fileName(), resolverId ) );
|
||||
QString resolverPath = dir.absoluteFilePath( m_resolverStates[ resolverId ].scriptPath );
|
||||
|
||||
if ( !resolverPath.isEmpty() )
|
||||
{
|
||||
// update with absolute, not relative, path
|
||||
m_resolverStates[ resolverId ].scriptPath = resolverPath;
|
||||
|
||||
// Do the install / add to tomahawk
|
||||
Tomahawk::Pipeline::instance()->addScriptResolver( resolverPath, true );
|
||||
m_resolverStates[ resolverId ].state = Installed;
|
||||
TomahawkSettings::instance()->setAtticaResolverStates( m_resolverStates );
|
||||
emit resolverInstalled( resolverId );
|
||||
emit resolverStateChanged( resolverId );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Failed to download attica payload...:" << reply->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
AtticaManager::extractPayload( const QString& filename, const QString& resolverId ) const
|
||||
{
|
||||
// uses QuaZip to extract the temporary zip file to the user's tomahawk data/resolvers directory
|
||||
QuaZip zipFile( filename );
|
||||
if ( !zipFile.open( QuaZip::mdUnzip ) )
|
||||
{
|
||||
tLog() << "Failed to QuaZip open:" << zipFile.getZipError();
|
||||
return QString();
|
||||
}
|
||||
|
||||
if ( !zipFile.goToFirstFile() )
|
||||
{
|
||||
tLog() << "Failed to go to first file in zip archive: " << zipFile.getZipError();
|
||||
return QString();
|
||||
}
|
||||
|
||||
QDir resolverDir = TomahawkUtils::appDataDir();
|
||||
if ( !resolverDir.mkpath( QString( "atticaresolvers/%1" ).arg( resolverId ) ) )
|
||||
{
|
||||
tLog() << "Failed to mkdir resolver save dir: " << TomahawkUtils::appDataDir().absoluteFilePath( QString( "atticaresolvers/%1" ).arg( resolverId ) );
|
||||
return QString();
|
||||
}
|
||||
resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) );
|
||||
tDebug() << "Installing resolver to:" << resolverDir.absolutePath();
|
||||
|
||||
QuaZipFile fileInZip( &zipFile );
|
||||
do
|
||||
{
|
||||
QuaZipFileInfo info;
|
||||
zipFile.getCurrentFileInfo( &info );
|
||||
|
||||
if ( !fileInZip.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open file inside zip archive:" << info.name << zipFile.getZipName() << "with error:" << zipFile.getZipError();
|
||||
continue;
|
||||
}
|
||||
|
||||
QFile out( resolverDir.absoluteFilePath( fileInZip.getActualFileName() ) );
|
||||
|
||||
QStringList parts = fileInZip.getActualFileName().split( "/" );
|
||||
if ( parts.size() > 1 )
|
||||
{
|
||||
QStringList dirs = parts.mid( 0, parts.size() - 1 );
|
||||
QString dirPath = dirs.join( "/" ); // QDir translates / to \ internally if necessary
|
||||
resolverDir.mkpath( dirPath );
|
||||
}
|
||||
|
||||
// make dir if there is one needed
|
||||
QDir d( fileInZip.getActualFileName() );
|
||||
|
||||
tDebug() << "Writing to output file..." << out.fileName();
|
||||
if ( !out.open( QIODevice::WriteOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open resolver extract file:" << out.errorString() << info.name;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
out.write( fileInZip.readAll() );
|
||||
out.close();
|
||||
fileInZip.close();
|
||||
|
||||
} while ( zipFile.goToNextFile() );
|
||||
|
||||
return resolverDir.absolutePath();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::uninstallResolver( const QString& pathToResolver )
|
||||
{
|
||||
// User manually removed a resolver not through attica dialog, simple remove
|
||||
QRegExp r( ".*([^/]*)/contents/code/main.js" );
|
||||
r.indexIn( pathToResolver );
|
||||
const QString& atticaId = r.cap( 1 );
|
||||
tDebug() << "Got resolver ID to remove:" << atticaId;
|
||||
if ( !atticaId.isEmpty() ) // this is an attica-installed resolver, mark as uninstalled
|
||||
{
|
||||
foreach ( const Content& resolver, m_resolvers )
|
||||
{
|
||||
if ( resolver.id() == atticaId ) // this is the one
|
||||
{
|
||||
m_resolverStates[ atticaId ].state = Uninstalled;
|
||||
TomahawkSettings::instance()->setAtticaResolverState( atticaId, Uninstalled );
|
||||
|
||||
doResolverRemove( atticaId );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::uninstallResolver( const Content& resolver )
|
||||
{
|
||||
if ( m_resolverStates[ resolver.id() ].state != Upgrading )
|
||||
{
|
||||
emit resolverUninstalled( resolver.id() );
|
||||
emit resolverStateChanged( resolver.id() );
|
||||
|
||||
m_resolverStates[ resolver.id() ].state = Uninstalled;
|
||||
TomahawkSettings::instance()->setAtticaResolverState( resolver.id(), Uninstalled );
|
||||
}
|
||||
|
||||
Tomahawk::Pipeline::instance()->removeScriptResolver( pathFromId( resolver.id() ) );
|
||||
doResolverRemove( resolver.id() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::doResolverRemove( const QString& id ) const
|
||||
{
|
||||
// uninstalling is easy... just delete it! :)
|
||||
QDir resolverDir = TomahawkUtils::appDataDir();
|
||||
if ( !resolverDir.cd( QString( "atticaresolvers/%1" ).arg( id ) ) )
|
||||
return;
|
||||
|
||||
if ( id.isEmpty() )
|
||||
return;
|
||||
|
||||
// sanity check
|
||||
if ( !resolverDir.absolutePath().contains( "atticaresolvers" ) ||
|
||||
!resolverDir.absolutePath().contains( id ) )
|
||||
return;
|
||||
|
||||
TomahawkUtils::removeDirectory( resolverDir.absolutePath() );
|
||||
}
|
134
src/libtomahawk/AtticaManager.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ATTICAMANAGER_H
|
||||
#define ATTICAMANAGER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
#ifdef LIBATTICA_FOUND
|
||||
#include <attica/provider.h>
|
||||
#include <attica/providermanager.h>
|
||||
#include <attica/content.h>
|
||||
#endif
|
||||
|
||||
class DLLEXPORT AtticaManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ResolverState {
|
||||
Uninstalled = 0,
|
||||
Installing,
|
||||
Installed,
|
||||
NeedsUpgrade,
|
||||
Upgrading,
|
||||
Failed
|
||||
};
|
||||
|
||||
struct Resolver {
|
||||
QString version, scriptPath;
|
||||
int userRating; // 0-100
|
||||
ResolverState state;
|
||||
QPixmap* pixmap;
|
||||
|
||||
Resolver( const QString& v, const QString& path, int userR, ResolverState s )
|
||||
: version( v ), scriptPath( path ), userRating( userR ), state( s ), pixmap( 0 ) {}
|
||||
Resolver() : userRating( -1 ), state( Uninstalled ), pixmap( 0 ) {}
|
||||
};
|
||||
|
||||
typedef QHash< QString, AtticaManager::Resolver > StateHash;
|
||||
|
||||
static AtticaManager* instance()
|
||||
{
|
||||
if ( !s_instance )
|
||||
s_instance = new AtticaManager();
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
explicit AtticaManager ( QObject* parent = 0 );
|
||||
#ifdef LIBATTICA_FOUND
|
||||
|
||||
virtual ~AtticaManager();
|
||||
#else
|
||||
virtual ~AtticaManager() {}
|
||||
#endif
|
||||
|
||||
#ifdef LIBATTICA_FOUND
|
||||
|
||||
bool resolversLoaded() const;
|
||||
|
||||
Attica::Content::List resolvers() const;
|
||||
ResolverState resolverState( const Attica::Content& resolver ) const;
|
||||
QPixmap iconForResolver( const Attica::Content& id ); // Looks up in icon cache
|
||||
|
||||
void uninstallResolver( const Attica::Content& resolver );
|
||||
void uninstallResolver( const QString& pathToResolver );
|
||||
QString pathFromId( const QString& resolverId ) const;
|
||||
|
||||
void uploadRating( const Attica::Content& c );
|
||||
bool userHasRated( const Attica::Content& c ) const;
|
||||
|
||||
public slots:
|
||||
void installResolver( const Attica::Content& resolver );
|
||||
void upgradeResolver( const Attica::Content& resolver );
|
||||
|
||||
signals:
|
||||
void resolversReloaded( const Attica::Content::List& resolvers );
|
||||
|
||||
void resolverStateChanged( const QString& resolverId );
|
||||
void resolverInstalled( const QString& resolverId );
|
||||
void resolverUninstalled( const QString& resolverId );
|
||||
|
||||
private slots:
|
||||
void providerAdded( const Attica::Provider& );
|
||||
void resolversList( Attica::BaseJob* );
|
||||
void resolverDownloadFinished( Attica::BaseJob* );
|
||||
void payloadFetched();
|
||||
|
||||
void loadPixmapsFromCache();
|
||||
void savePixmapsToCache();
|
||||
void resolverIconFetched();
|
||||
|
||||
void syncServerData();
|
||||
|
||||
private:
|
||||
QString extractPayload( const QString& filename, const QString& resolverId ) const;
|
||||
void doResolverRemove( const QString& id ) const;
|
||||
|
||||
Attica::ProviderManager m_manager;
|
||||
|
||||
Attica::Provider m_resolverProvider;
|
||||
Attica::Content::List m_resolvers;
|
||||
StateHash m_resolverStates;
|
||||
#endif
|
||||
|
||||
static AtticaManager* s_instance;
|
||||
};
|
||||
|
||||
#ifdef LIBATTICA_FOUND
|
||||
Q_DECLARE_METATYPE( Attica::Content );
|
||||
#endif
|
||||
|
||||
#endif // ATTICAMANAGER_H
|
@@ -18,6 +18,7 @@ set( libSources
|
||||
pipeline.cpp
|
||||
|
||||
aclsystem.cpp
|
||||
actioncollection.cpp
|
||||
artist.cpp
|
||||
album.cpp
|
||||
collection.cpp
|
||||
@@ -32,6 +33,10 @@ set( libSources
|
||||
globalactionmanager.cpp
|
||||
contextmenu.cpp
|
||||
dropjob.cpp
|
||||
playlistinterface.cpp
|
||||
LatchManager.cpp
|
||||
|
||||
EchonestCatalogSynchronizer.cpp
|
||||
|
||||
sip/SipPlugin.cpp
|
||||
sip/SipHandler.cpp
|
||||
@@ -64,7 +69,7 @@ set( libSources
|
||||
database/databasecommand_deletefiles.cpp
|
||||
database/databasecommand_dirmtimes.cpp
|
||||
database/databasecommand_filemtimes.cpp
|
||||
database/databasecommand_loadfile.cpp
|
||||
database/databasecommand_loadfiles.cpp
|
||||
database/databasecommand_logplayback.cpp
|
||||
database/databasecommand_addsource.cpp
|
||||
database/databasecommand_sourceoffline.cpp
|
||||
@@ -93,15 +98,25 @@ set( libSources
|
||||
database/databasecommand_socialaction.cpp
|
||||
database/databasecommand_loadsocialactions.cpp
|
||||
database/databasecommand_genericselect.cpp
|
||||
database/databasecommand_setcollectionattributes.cpp
|
||||
database/databasecommand_collectionattributes.cpp
|
||||
database/databasecommand_trackattributes.cpp
|
||||
database/databasecommand_settrackattributes.cpp
|
||||
database/database.cpp
|
||||
|
||||
infobar/infobar.cpp
|
||||
|
||||
infosystem/infosystemcache.cpp
|
||||
infosystem/infosystem.cpp
|
||||
infosystem/infosystemworker.cpp
|
||||
infosystem/infoplugins/generic/echonestplugin.cpp
|
||||
infosystem/infoplugins/generic/lastfmplugin.cpp
|
||||
infosystem/infoplugins/generic/chartsplugin.cpp
|
||||
infosystem/infoplugins/generic/spotifyPlugin.cpp
|
||||
infosystem/infoplugins/generic/hypemPlugin.cpp
|
||||
infosystem/infoplugins/generic/musixmatchplugin.cpp
|
||||
infosystem/infoplugins/generic/musicbrainzPlugin.cpp
|
||||
infosystem/infoplugins/generic/RoviPlugin.cpp
|
||||
|
||||
playlist/treemodel.cpp
|
||||
playlist/treeproxymodel.cpp
|
||||
@@ -129,6 +144,9 @@ set( libSources
|
||||
playlist/albumview.cpp
|
||||
playlist/artistview.cpp
|
||||
playlist/customplaylistview.cpp
|
||||
playlist/ViewHeader.cpp
|
||||
playlist/PlaylistUpdaterInterface.cpp
|
||||
playlist/XspfUpdater.cpp
|
||||
|
||||
playlist/topbar/topbar.cpp
|
||||
playlist/topbar/clearbutton.cpp
|
||||
@@ -136,14 +154,13 @@ set( libSources
|
||||
playlist/topbar/lineedit.cpp
|
||||
playlist/topbar/searchbutton.cpp
|
||||
|
||||
playlist/infobar/infobar.cpp
|
||||
|
||||
playlist/dynamic/DynamicPlaylist.cpp
|
||||
playlist/dynamic/DynamicControl.cpp
|
||||
playlist/dynamic/GeneratorFactory.cpp
|
||||
playlist/dynamic/GeneratorInterface.cpp
|
||||
playlist/dynamic/DynamicView.cpp
|
||||
playlist/dynamic/DynamicModel.cpp
|
||||
playlist/dynamic/DynamicPlaylistRevision.cpp
|
||||
playlist/dynamic/echonest/EchonestGenerator.cpp
|
||||
playlist/dynamic/echonest/EchonestControl.cpp
|
||||
playlist/dynamic/echonest/EchonestSteerer.cpp
|
||||
@@ -158,6 +175,9 @@ set( libSources
|
||||
playlist/dynamic/database/DatabaseControl.cpp
|
||||
playlist/dynamic/database/DatabaseGenerator.cpp
|
||||
|
||||
resolvers/scriptresolver.cpp
|
||||
resolvers/qtscriptresolver.cpp
|
||||
|
||||
network/bufferiodevice.cpp
|
||||
network/msgprocessor.cpp
|
||||
network/streamconnection.cpp
|
||||
@@ -169,22 +189,25 @@ set( libSources
|
||||
network/controlconnection.cpp
|
||||
|
||||
utils/tomahawkutils.cpp
|
||||
utils/querylabel.cpp
|
||||
utils/elidedlabel.cpp
|
||||
utils/imagebutton.cpp
|
||||
utils/logger.cpp
|
||||
utils/proxystyle.cpp
|
||||
utils/widgetdragfilter.cpp
|
||||
utils/animatedsplitter.cpp
|
||||
utils/xspfloader.cpp
|
||||
utils/xspfgenerator.cpp
|
||||
utils/jspfloader.cpp
|
||||
utils/spotifyparser.cpp
|
||||
utils/itunesparser.cpp
|
||||
utils/rdioparser.cpp
|
||||
utils/shortenedlinkparser.cpp
|
||||
utils/stylehelper.cpp
|
||||
utils/dropmenu.cpp
|
||||
utils/qnr_iodevicestream.cpp
|
||||
utils/dropjobnotifier.cpp
|
||||
|
||||
widgets/checkdirtree.cpp
|
||||
widgets/querylabel.cpp
|
||||
widgets/imagebutton.cpp
|
||||
widgets/animatedsplitter.cpp
|
||||
widgets/elidedlabel.cpp
|
||||
widgets/newplaylistwidget.cpp
|
||||
widgets/searchwidget.cpp
|
||||
widgets/SeekSlider.cpp
|
||||
@@ -193,24 +216,30 @@ set( libSources
|
||||
widgets/whatshotwidget.cpp
|
||||
widgets/RecentlyPlayedPlaylistsModel.cpp
|
||||
widgets/RecentPlaylistsModel.cpp
|
||||
widgets/OverlayButton.cpp
|
||||
widgets/overlaywidget.cpp
|
||||
widgets/HeaderLabel.cpp
|
||||
widgets/HeaderWidget.cpp
|
||||
widgets/combobox.cpp
|
||||
widgets/ToggleButton.cpp
|
||||
widgets/SocialPlaylistWidget.cpp
|
||||
widgets/infowidgets/sourceinfowidget.cpp
|
||||
widgets/infowidgets/ArtistInfoWidget.cpp
|
||||
widgets/infowidgets/AlbumInfoWidget.cpp
|
||||
widgets/kbreadcrumbselectionmodel.cpp
|
||||
widgets/breadcrumbbar.cpp
|
||||
widgets/breadcrumbbuttonbase.cpp
|
||||
widgets/headerbreadcrumb.cpp
|
||||
widgets/siblingcrumbbutton.cpp
|
||||
widgets/Breadcrumb.cpp
|
||||
widgets/BreadcrumbButton.cpp
|
||||
|
||||
kdsingleapplicationguard/kdsingleapplicationguard.cpp
|
||||
kdsingleapplicationguard/kdsharedmemorylocker.cpp
|
||||
kdsingleapplicationguard/kdtoolsglobal.cpp
|
||||
kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp
|
||||
jobview/JobStatusView.cpp
|
||||
jobview/JobStatusModel.cpp
|
||||
jobview/JobStatusDelegate.cpp
|
||||
jobview/PipelineStatusItem.cpp
|
||||
jobview/TransferStatusItem.cpp
|
||||
jobview/LatchedStatusItem.cpp
|
||||
|
||||
thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp
|
||||
thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp
|
||||
thirdparty/kdsingleapplicationguard/kdtoolsglobal.cpp
|
||||
thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp
|
||||
)
|
||||
|
||||
set( libHeaders
|
||||
@@ -220,6 +249,7 @@ set( libHeaders
|
||||
functimeout.h
|
||||
|
||||
aclsystem.h
|
||||
actioncollection.h
|
||||
collection.h
|
||||
query.h
|
||||
resolver.h
|
||||
@@ -230,11 +260,15 @@ set( libHeaders
|
||||
globalactionmanager.h
|
||||
contextmenu.h
|
||||
dropjob.h
|
||||
AtticaManager.h
|
||||
LatchManager.h
|
||||
|
||||
artist.h
|
||||
album.h
|
||||
playlist.h
|
||||
|
||||
EchonestCatalogSynchronizer.h
|
||||
|
||||
sip/SipPlugin.h
|
||||
sip/SipHandler.h
|
||||
sip/SipModel.h
|
||||
@@ -264,7 +298,7 @@ set( libHeaders
|
||||
database/databasecommand_deletefiles.h
|
||||
database/databasecommand_dirmtimes.h
|
||||
database/databasecommand_filemtimes.h
|
||||
database/databasecommand_loadfile.h
|
||||
database/databasecommand_loadfiles.h
|
||||
database/databasecommand_logplayback.h
|
||||
database/databasecommand_addsource.h
|
||||
database/databasecommand_sourceoffline.h
|
||||
@@ -295,14 +329,24 @@ set( libHeaders
|
||||
database/databasecommand_socialaction.h
|
||||
database/databasecommand_loadsocialactions.h
|
||||
database/databasecommand_genericselect.h
|
||||
database/databasecommand_setcollectionattributes.h
|
||||
database/databasecommand_collectionattributes.h
|
||||
database/databasecommand_trackattributes.h
|
||||
database/databasecommand_settrackattributes.h
|
||||
|
||||
infobar/infobar.h
|
||||
|
||||
infosystem/infosystem.h
|
||||
infosystem/infosystemworker.h
|
||||
infosystem/infosystemcache.h
|
||||
infosystem/infoplugins/generic/echonestplugin.h
|
||||
infosystem/infoplugins/generic/lastfmplugin.h
|
||||
infosystem/infoplugins/generic/chartsplugin.h
|
||||
infosystem/infoplugins/generic/spotifyPlugin.h
|
||||
infosystem/infoplugins/generic/hypemPlugin.h
|
||||
infosystem/infoplugins/generic/musixmatchplugin.h
|
||||
infosystem/infoplugins/generic/musicbrainzPlugin.h
|
||||
infosystem/infoplugins/generic/RoviPlugin.h
|
||||
|
||||
network/bufferiodevice.h
|
||||
network/msgprocessor.h
|
||||
@@ -340,6 +384,9 @@ set( libHeaders
|
||||
playlist/albumview.h
|
||||
playlist/artistview.h
|
||||
playlist/customplaylistview.h
|
||||
playlist/ViewHeader.h
|
||||
playlist/PlaylistUpdaterInterface.h
|
||||
playlist/XspfUpdater.h
|
||||
|
||||
playlist/topbar/topbar.h
|
||||
playlist/topbar/clearbutton.h
|
||||
@@ -348,8 +395,6 @@ set( libHeaders
|
||||
playlist/topbar/lineedit_p.h
|
||||
playlist/topbar/searchbutton.h
|
||||
|
||||
playlist/infobar/infobar.h
|
||||
|
||||
playlist/dynamic/DynamicPlaylist.h
|
||||
playlist/dynamic/DynamicControl.h
|
||||
playlist/dynamic/GeneratorInterface.h
|
||||
@@ -369,45 +414,59 @@ set( libHeaders
|
||||
playlist/dynamic/database/DatabaseControl.h
|
||||
playlist/dynamic/database/DatabaseGenerator.h
|
||||
|
||||
utils/querylabel.h
|
||||
utils/elidedlabel.h
|
||||
utils/animatedcounterlabel.h
|
||||
utils/imagebutton.h
|
||||
resolvers/scriptresolver.h
|
||||
resolvers/qtscriptresolver.h
|
||||
|
||||
utils/widgetdragfilter.h
|
||||
utils/animatedsplitter.h
|
||||
utils/xspfloader.h
|
||||
utils/xspfgenerator.h
|
||||
utils/jspfloader.h
|
||||
utils/spotifyparser.h
|
||||
utils/itunesparser.h
|
||||
utils/rdioparser.h
|
||||
utils/shortenedlinkparser.h
|
||||
utils/stylehelper.h
|
||||
utils/dropmenu.h
|
||||
utils/qnr_iodevicestream.h
|
||||
utils/dropjobnotifier.h
|
||||
|
||||
widgets/checkdirtree.h
|
||||
widgets/querylabel.h
|
||||
widgets/animatedcounterlabel.h
|
||||
widgets/imagebutton.h
|
||||
widgets/animatedsplitter.h
|
||||
widgets/elidedlabel.h
|
||||
widgets/newplaylistwidget.h
|
||||
widgets/searchwidget.h
|
||||
widgets/SeekSlider.h
|
||||
widgets/playlisttypeselectordlg.h
|
||||
widgets/welcomewidget.h
|
||||
widgets/whatshotwidget.h
|
||||
widgets/whatshotwidget_p.h
|
||||
widgets/RecentlyPlayedPlaylistsModel.h
|
||||
widgets/RecentPlaylistsModel.h
|
||||
widgets/OverlayButton.h
|
||||
widgets/overlaywidget.h
|
||||
widgets/HeaderLabel.h
|
||||
widgets/HeaderWidget.h
|
||||
widgets/combobox.h
|
||||
widgets/ToggleButton.h
|
||||
widgets/SocialPlaylistWidget.h
|
||||
widgets/infowidgets/sourceinfowidget.h
|
||||
widgets/infowidgets/ArtistInfoWidget.h
|
||||
widgets/infowidgets/ArtistInfoWidget_p.h
|
||||
widgets/infowidgets/AlbumInfoWidget.h
|
||||
widgets/kbreadcrumbselectionmodel.h
|
||||
widgets/kbreadcrumbselectionmodel_p.h
|
||||
widgets/breadcrumbbar.h
|
||||
widgets/breadcrumbbuttonbase.h
|
||||
widgets/headerbreadcrumb.h
|
||||
widgets/siblingcrumbbutton.h
|
||||
widgets/Breadcrumb.h
|
||||
widgets/BreadcrumbButton.h
|
||||
|
||||
kdsingleapplicationguard/kdsingleapplicationguard.h
|
||||
jobview/JobStatusView.h
|
||||
jobview/JobStatusModel.h
|
||||
jobview/JobStatusDelegate.h
|
||||
jobview/JobStatusItem.h
|
||||
jobview/PipelineStatusItem.h
|
||||
jobview/TransferStatusItem.h
|
||||
jobview/LatchedStatusItem.h
|
||||
|
||||
thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h
|
||||
thirdparty/Qocoa/qsearchfield.h
|
||||
)
|
||||
|
||||
set( libHeaders_NoMOC
|
||||
@@ -432,9 +491,9 @@ set( libUI ${libUI}
|
||||
widgets/infowidgets/ArtistInfoWidget.ui
|
||||
widgets/infowidgets/AlbumInfoWidget.ui
|
||||
playlist/topbar/topbar.ui
|
||||
playlist/infobar/infobar.ui
|
||||
playlist/queueview.ui
|
||||
context/ContextWidget.ui
|
||||
infobar/infobar.ui
|
||||
)
|
||||
|
||||
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. ..
|
||||
@@ -443,8 +502,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
|
||||
${QJSON_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}/..
|
||||
${CLUCENE_INCLUDE_DIR}
|
||||
${CLUCENE_LIBRARY_DIR}
|
||||
${CLUCENE_INCLUDE_DIRS}
|
||||
${PHONON_INCLUDES}
|
||||
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src
|
||||
|
||||
@@ -452,9 +510,19 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
|
||||
|
||||
${LIBPORTFWD_INCLUDE_DIR}
|
||||
${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb
|
||||
|
||||
${QuaZip_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
IF(QCA2_FOUND)
|
||||
INCLUDE_DIRECTORIES( ${QCA2_INCLUDE_DIR} )
|
||||
ENDIF(QCA2_FOUND)
|
||||
|
||||
IF(LIBATTICA_FOUND)
|
||||
SET( libSources ${libSources} AtticaManager.cpp )
|
||||
SET( libHeaders ${libHeaders} AtticaManager.h )
|
||||
INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} )
|
||||
ENDIF(LIBATTICA_FOUND)
|
||||
|
||||
IF( UNIX AND NOT APPLE )
|
||||
SET( libSources ${libSources}
|
||||
infosystem/infoplugins/unix/mprispluginrootadaptor.cpp
|
||||
@@ -499,7 +567,8 @@ IF( APPLE )
|
||||
SET( libSources ${libSources}
|
||||
infosystem/infoplugins/mac/adium.mm
|
||||
infosystem/infoplugins/mac/adiumplugin.cpp
|
||||
utils/tomahawkutils_mac.mm )
|
||||
utils/tomahawkutils_mac.mm
|
||||
thirdparty/Qocoa/qsearchfield_mac.mm )
|
||||
|
||||
SET( libHeaders ${libHeaders}
|
||||
infosystem/infoplugins/mac/adium.h
|
||||
@@ -515,6 +584,8 @@ IF( APPLE )
|
||||
|
||||
/System/Library/Frameworks/AppKit.framework
|
||||
)
|
||||
ELSE( APPLE )
|
||||
SET( libSources ${libSources} thirdparty/Qocoa/qsearchfield.cpp )
|
||||
ENDIF( APPLE )
|
||||
|
||||
IF(LIBLASTFM_FOUND)
|
||||
@@ -526,9 +597,17 @@ qt4_wrap_cpp( libMoc ${libHeaders} )
|
||||
|
||||
SET( libSources ${libSources} ${libUI_H} ${libHeaders_NoMOC} )
|
||||
|
||||
add_library( tomahawklib SHARED ${libSources} ${libMoc} )
|
||||
ADD_LIBRARY( tomahawklib SHARED ${libSources} ${libMoc} )
|
||||
|
||||
target_link_libraries( tomahawklib
|
||||
IF(QCA2_FOUND)
|
||||
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} )
|
||||
ENDIF(QCA2_FOUND)
|
||||
|
||||
IF(LIBATTICA_FOUND)
|
||||
SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBATTICA_LIBRARIES} ${QuaZip_LIBRARIES} )
|
||||
ENDIF(LIBATTICA_FOUND)
|
||||
|
||||
TARGET_LINK_LIBRARIES( tomahawklib
|
||||
# Thirdparty shipped with tomahawk
|
||||
${LIBPORTFWD_LIBRARIES}
|
||||
|
||||
|
365
src/libtomahawk/EchonestCatalogSynchronizer.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "EchonestCatalogSynchronizer.h"
|
||||
|
||||
#include "collection.h"
|
||||
#include "database/database.h"
|
||||
#include "database/databasecommand_genericselect.h"
|
||||
#include "database/databasecommand_setcollectionattributes.h"
|
||||
#include "database/databasecommand_loadfiles.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include "sourcelist.h"
|
||||
#include "query.h"
|
||||
|
||||
#include <echonest/CatalogUpdateEntry.h>
|
||||
#include <echonest/Config.h>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
EchonestCatalogSynchronizer* EchonestCatalogSynchronizer::s_instance = 0;
|
||||
|
||||
EchonestCatalogSynchronizer::EchonestCatalogSynchronizer( QObject *parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
m_syncing = TomahawkSettings::instance()->enableEchonestCatalogs();
|
||||
|
||||
qRegisterMetaType<QList<QStringList> >("QList<QStringList>");
|
||||
|
||||
connect( TomahawkSettings::instance(), SIGNAL( changed() ), this, SLOT( checkSettingsChanged() ) );
|
||||
connect( SourceList::instance()->getLocal()->collection().data(), SIGNAL( tracksAdded( QList<unsigned int> ) ), this, SLOT( tracksAdded( QList<unsigned int> ) ), Qt::QueuedConnection );
|
||||
connect( SourceList::instance()->getLocal()->collection().data(), SIGNAL( tracksRemoved( QList<unsigned int> ) ), this, SLOT( tracksRemoved( QList<unsigned int> ) ), Qt::QueuedConnection );
|
||||
|
||||
const QByteArray artist = TomahawkSettings::instance()->value( "collection/artistCatalog" ).toByteArray();
|
||||
const QByteArray song = TomahawkSettings::instance()->value( "collection/songCatalog" ).toByteArray();
|
||||
|
||||
if ( !artist.isEmpty() )
|
||||
m_artistCatalog.setId( artist );
|
||||
if ( !song.isEmpty() )
|
||||
m_songCatalog.setId( song );
|
||||
|
||||
// Sanity check
|
||||
if ( !song.isEmpty() && !m_syncing )
|
||||
{
|
||||
// Not syncing but have a catalog id... lets fix this
|
||||
QNetworkReply* r = m_songCatalog.deleteCatalog();
|
||||
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
|
||||
r->setProperty( "type", "song" );
|
||||
}
|
||||
if ( !artist.isEmpty() && !m_syncing )
|
||||
{
|
||||
QNetworkReply* r = m_artistCatalog.deleteCatalog();
|
||||
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
|
||||
r->setProperty( "type", "artist" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::checkSettingsChanged()
|
||||
{
|
||||
if ( TomahawkSettings::instance()->enableEchonestCatalogs() && !m_syncing )
|
||||
{
|
||||
// enable, and upload whole db
|
||||
m_syncing = true;
|
||||
|
||||
tDebug() << "Echonest Catalog sync pref changed, uploading!!";
|
||||
uploadDb();
|
||||
} else if ( !TomahawkSettings::instance()->enableEchonestCatalogs() && m_syncing )
|
||||
{
|
||||
|
||||
tDebug() << "Found echonest change, doing catalog deletes!";
|
||||
// delete all track nums and catalog ids from our peers
|
||||
{
|
||||
DatabaseCommand_SetTrackAttributes* cmd = new DatabaseCommand_SetTrackAttributes( DatabaseCommand_SetTrackAttributes::EchonestCatalogId );
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
}
|
||||
{
|
||||
DatabaseCommand_SetCollectionAttributes* cmd = new DatabaseCommand_SetCollectionAttributes( DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog, true );
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
}
|
||||
|
||||
if ( !m_songCatalog.id().isEmpty() )
|
||||
{
|
||||
QNetworkReply* r = m_songCatalog.deleteCatalog();
|
||||
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
|
||||
r->setProperty( "type", "song" );
|
||||
}
|
||||
if ( !m_artistCatalog.id().isEmpty() )
|
||||
{
|
||||
QNetworkReply* r = m_artistCatalog.deleteCatalog();
|
||||
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
|
||||
r->setProperty( "type", "artist" );
|
||||
}
|
||||
m_syncing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::catalogDeleted()
|
||||
{
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
QString toDel = QString( "collection/%1Catalog" ).arg( r->property( "type" ).toString() );
|
||||
|
||||
try
|
||||
{
|
||||
// HACK libechonest bug, should be a static method but it's not. Doesn't actually use any instance vars though
|
||||
m_songCatalog.parseDelete( r );
|
||||
// If we didn't throw, no errors, so clear our config
|
||||
TomahawkSettings::instance()->setValue( toDel, QString() );
|
||||
} catch ( const Echonest::ParseError& e )
|
||||
{
|
||||
tLog() << "Error in libechonest parsing catalog delete:" << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::uploadDb()
|
||||
{
|
||||
// create two catalogs: uuid_song, and uuid_artist.
|
||||
QNetworkReply* r = Echonest::Catalog::create( QString( "%1_song" ).arg( Database::instance()->dbid() ), Echonest::CatalogTypes::Song );
|
||||
connect( r, SIGNAL( finished() ), this, SLOT( songCreateFinished() ) );
|
||||
|
||||
// r = Echonest::Catalog::create( QString( "%1_artist" ).arg( Database::instance()->dbid() ), Echonest::CatalogTypes::Artist );
|
||||
// connect( r, SIGNAL( finished() ), this, SLOT( artistCreateFinished() ) );
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::songCreateFinished()
|
||||
{
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
tDebug() << "Finished creating song catalog, updating data now!!";
|
||||
try
|
||||
{
|
||||
m_songCatalog = Echonest::Catalog::parseCreate( r );
|
||||
TomahawkSettings::instance()->setValue( "collection/songCatalog", m_songCatalog.id() );
|
||||
QSharedPointer< DatabaseCommand > cmd( new DatabaseCommand_SetCollectionAttributes( DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog,
|
||||
m_songCatalog.id() ) );
|
||||
Database::instance()->enqueue( cmd );
|
||||
} catch ( const Echonest::ParseError& e )
|
||||
{
|
||||
tLog() << "Echonest threw an exception parsing song catalog create:" << e.what();
|
||||
return;
|
||||
}
|
||||
|
||||
QString sql( "SELECT file.id, track.name, artist.name, album.name "
|
||||
"FROM file, artist, track, file_join "
|
||||
"LEFT OUTER JOIN album "
|
||||
"ON file_join.album = album.id "
|
||||
"WHERE file.id = file_join.file "
|
||||
"AND file_join.artist = artist.id "
|
||||
"AND file_join.track = track.id "
|
||||
"AND file.source IS NULL");
|
||||
DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( sql, DatabaseCommand_GenericSelect::Track, true );
|
||||
connect( cmd, SIGNAL( rawData( QList< QStringList > ) ), this, SLOT( rawTracksAdd( QList< QStringList > ) ) );
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::artistCreateFinished()
|
||||
{
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
// We don't support artist catalogs at the moment
|
||||
return;
|
||||
/*
|
||||
try
|
||||
{
|
||||
m_artistCatalog = Echonest::Catalog::parseCreate( r );
|
||||
TomahawkSettings::instance()->setValue( "collection/artistCatalog", m_artistCatalog.id() );
|
||||
|
||||
// QSharedPointer< DatabaseCommand > cmd( new DatabaseCommand_SetCollectionAttributes( SourceList::instance()->getLocal(),
|
||||
// DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog,
|
||||
// m_songCatalog.id() ) );
|
||||
// Database::instance()->enqueue( cmd );
|
||||
} catch ( const Echonest::ParseError& e )
|
||||
{
|
||||
tLog() << "Echonest threw an exception parsing artist catalog create:" << e.what();
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::rawTracksAdd( const QList< QStringList >& tracks )
|
||||
{
|
||||
tDebug() << "Got raw tracks, num:" << tracks.size();
|
||||
|
||||
// int limit = ( tracks.size() < 1000 ) ? tracks.size() : 1000;
|
||||
|
||||
int cur = 0;
|
||||
while ( cur < tracks.size() )
|
||||
{
|
||||
int prev = cur;
|
||||
cur = ( cur + 2000 > tracks.size() ) ? tracks.size() : cur + 2000;
|
||||
|
||||
tDebug() << "Enqueueing a batch of tracks to upload to echonest catalog:" << cur - prev;
|
||||
Echonest::CatalogUpdateEntries entries;
|
||||
for ( int i = prev; i < cur; i++ )
|
||||
{
|
||||
if ( tracks[i][1].isEmpty() || tracks[i][2].isEmpty() )
|
||||
continue;
|
||||
entries.append( entryFromTrack( tracks[i], Echonest::CatalogTypes::Update ) );
|
||||
}
|
||||
tDebug() << "Done queuing:" << entries.size() << "tracks";
|
||||
m_queuedUpdates.enqueue( entries );
|
||||
}
|
||||
|
||||
doUploadJob();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::doUploadJob()
|
||||
{
|
||||
if ( m_queuedUpdates.isEmpty() )
|
||||
return;
|
||||
|
||||
Echonest::CatalogUpdateEntries entries = m_queuedUpdates.dequeue();
|
||||
tDebug() << "Updating number of entries:" << entries.count();
|
||||
|
||||
QNetworkReply* updateJob = m_songCatalog.update( entries );
|
||||
connect( updateJob, SIGNAL( finished() ), this, SLOT( songUpdateFinished() ) );
|
||||
}
|
||||
|
||||
|
||||
Echonest::CatalogUpdateEntry
|
||||
EchonestCatalogSynchronizer::entryFromTrack( const QStringList& track, Echonest::CatalogTypes::Action action ) const
|
||||
{
|
||||
//qDebug() << "UPLOADING:" << track[0] << track[1] << track[2];
|
||||
Echonest::CatalogUpdateEntry entry;
|
||||
entry.setAction( action );
|
||||
entry.setItemId(track[ 0 ].toLatin1() ); // track dbid
|
||||
entry.setSongName( escape( track[ 1 ] ) );
|
||||
entry.setArtistName( escape( track[ 2 ] ) );
|
||||
entry.setRelease( escape( track[ 3 ] ) );
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::songUpdateFinished()
|
||||
{
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
try
|
||||
{
|
||||
QByteArray ticket = m_songCatalog.parseTicket( r );
|
||||
QNetworkReply* tJob = m_songCatalog.status( ticket );
|
||||
connect( tJob, SIGNAL( finished() ), this, SLOT( checkTicket() ) );
|
||||
} catch ( const Echonest::ParseError& e )
|
||||
{
|
||||
tLog() << "Echonest threw an exception parsing catalog update finished:" << e.what();
|
||||
}
|
||||
|
||||
doUploadJob();
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::checkTicket()
|
||||
{
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
try
|
||||
{
|
||||
Echonest::CatalogStatus status = m_songCatalog.parseStatus( r );
|
||||
|
||||
tLog() << "Catalog status update:" << status.status << status.details << status.items;
|
||||
} catch ( const Echonest::ParseError& e )
|
||||
{
|
||||
tLog() << "Echonest threw an exception parsing catalog create:" << e.what();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::tracksAdded( const QList< unsigned int >& tracks )
|
||||
{
|
||||
if ( !m_syncing || m_songCatalog.id().isEmpty() || tracks.isEmpty() )
|
||||
return;
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "Got tracks added from db, fetching metadata" << tracks;
|
||||
// Get the result_ptrs from the tracks
|
||||
DatabaseCommand_LoadFiles* cmd = new DatabaseCommand_LoadFiles( tracks );
|
||||
connect( cmd, SIGNAL( results( QList<Tomahawk::result_ptr> ) ), this, SLOT( loadedResults( QList<Tomahawk::result_ptr> ) ) );
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::loadedResults( const QList<result_ptr>& results )
|
||||
{
|
||||
QList< QStringList > rawTracks;
|
||||
qDebug() << Q_FUNC_INFO << "Got track metadata..." << results.size();
|
||||
|
||||
foreach( const result_ptr& result, results )
|
||||
{
|
||||
if ( result.isNull() )
|
||||
continue;
|
||||
|
||||
qDebug() << "Metadata for item:" << result->fileId();
|
||||
|
||||
const QString artist = result->artist().isNull() ? QString() : result->artist()->name();
|
||||
const QString album = result->album().isNull() ? QString() : result->album()->name();
|
||||
rawTracks << ( QStringList() << QString::number( result->fileId() ) << result->track() << artist << album );
|
||||
}
|
||||
rawTracksAdd( rawTracks );
|
||||
}
|
||||
|
||||
void
|
||||
EchonestCatalogSynchronizer::tracksRemoved( const QList< unsigned int >& trackIds )
|
||||
{
|
||||
|
||||
if ( !m_syncing || m_songCatalog.id().isEmpty() || trackIds.isEmpty() )
|
||||
return;
|
||||
|
||||
|
||||
Echonest::CatalogUpdateEntries entries;
|
||||
entries.reserve( trackIds.size() );
|
||||
|
||||
foreach ( unsigned int id, trackIds )
|
||||
{
|
||||
Echonest::CatalogUpdateEntry e( Echonest::CatalogTypes::Delete );
|
||||
e.setItemId( QString::number( id ).toLatin1() );
|
||||
entries.append( e );
|
||||
}
|
||||
|
||||
QNetworkReply* reply = m_songCatalog.update( entries );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( songUpdateFinished() ) );
|
||||
}
|
||||
|
||||
QByteArray
|
||||
EchonestCatalogSynchronizer::escape( const QString &in ) const
|
||||
{
|
||||
// TODO echonest chokes on some chars in the output. But if we percent-encode those chars it works
|
||||
// We can't percent-encode the whole string, because then any UTF-8 chars that have been url-encoded, fail.
|
||||
// God this sucks. It's going to break...
|
||||
QString clean = in;
|
||||
clean.replace( "&", "%25" );
|
||||
clean.replace( ";", "%3B" );
|
||||
return clean.toUtf8();
|
||||
//return QUrl::toPercentEncoding( in. );
|
||||
}
|
91
src/libtomahawk/EchonestCatalogSynchronizer.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ECHONESTCATALOGSYNCHRONIZER_H
|
||||
#define ECHONESTCATALOGSYNCHRONIZER_H
|
||||
|
||||
#include "dllmacro.h"
|
||||
#include "query.h"
|
||||
#include "database/databasecommand_trackattributes.h"
|
||||
|
||||
#include <echonest/Catalog.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class DLLEXPORT EchonestCatalogSynchronizer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static EchonestCatalogSynchronizer* instance() {
|
||||
if ( !s_instance )
|
||||
{
|
||||
s_instance = new EchonestCatalogSynchronizer;
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
explicit EchonestCatalogSynchronizer(QObject *parent = 0);
|
||||
|
||||
Echonest::Catalog songCatalog() const { return m_songCatalog; }
|
||||
Echonest::Catalog artistCatalog() const { return m_artistCatalog; }
|
||||
|
||||
signals:
|
||||
void knownCatalogsChanged();
|
||||
|
||||
private slots:
|
||||
void checkSettingsChanged();
|
||||
void tracksAdded( const QList<unsigned int>& );
|
||||
void tracksRemoved( const QList<unsigned int>& );
|
||||
|
||||
void loadedResults( const QList<Tomahawk::result_ptr>& results );
|
||||
|
||||
// Echonest slots
|
||||
void songCreateFinished();
|
||||
void artistCreateFinished();
|
||||
void songUpdateFinished();
|
||||
void catalogDeleted();
|
||||
|
||||
void checkTicket();
|
||||
|
||||
void rawTracksAdd( const QList< QStringList >& tracks );
|
||||
private:
|
||||
void uploadDb();
|
||||
QByteArray escape( const QString& in ) const;
|
||||
|
||||
Echonest::CatalogUpdateEntry entryFromTrack( const QStringList&, Echonest::CatalogTypes::Action action ) const;
|
||||
void doUploadJob();
|
||||
|
||||
bool m_syncing;
|
||||
|
||||
Echonest::Catalog m_songCatalog;
|
||||
Echonest::Catalog m_artistCatalog;
|
||||
|
||||
QQueue< Echonest::CatalogUpdateEntries > m_queuedUpdates;
|
||||
|
||||
static EchonestCatalogSynchronizer* s_instance;
|
||||
|
||||
friend class ::DatabaseCommand_SetCollectionAttributes;
|
||||
};
|
||||
|
||||
}
|
||||
#endif // ECHONESTCATALOGSYNCHRONIZER_H
|
139
src/libtomahawk/LatchManager.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LatchManager.h"
|
||||
|
||||
#include "actioncollection.h"
|
||||
#include "audio/audioengine.h"
|
||||
#include "database/database.h"
|
||||
|
||||
#include <QtCore/QStateMachine>
|
||||
#include <QtCore/QState>
|
||||
#include "sourcelist.h"
|
||||
#include "database/databasecommand_socialaction.h"
|
||||
#include "sourceplaylistinterface.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
LatchManager::LatchManager( QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_state( NotLatched )
|
||||
{
|
||||
connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::PlaylistInterface* ) ), this, SLOT( playlistChanged( Tomahawk::PlaylistInterface* ) ) );
|
||||
}
|
||||
|
||||
LatchManager::~LatchManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
LatchManager::isLatched( const source_ptr& src )
|
||||
{
|
||||
return m_state == Latched && m_latchedOnTo == src;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LatchManager::latchRequest( const source_ptr& source )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( isLatched( source ) )
|
||||
return;
|
||||
|
||||
m_state = Latching;
|
||||
m_waitingForLatch = source;
|
||||
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
|
||||
}
|
||||
|
||||
void
|
||||
LatchManager::playlistChanged( PlaylistInterface* )
|
||||
{
|
||||
// If we were latched on and changed, send the listening along stop
|
||||
if ( m_latchedOnTo.isNull() )
|
||||
{
|
||||
if ( m_waitingForLatch.isNull() )
|
||||
return; // Neither latched on nor waiting to be latched on, no-op
|
||||
|
||||
m_latchedOnTo = m_waitingForLatch;
|
||||
m_latchedInterface = m_waitingForLatch->getPlaylistInterface();
|
||||
m_waitingForLatch.clear();
|
||||
m_state = Latched;
|
||||
|
||||
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
|
||||
cmd->setSource( SourceList::instance()->getLocal() );
|
||||
cmd->setAction( "latchOn");
|
||||
cmd->setComment( m_latchedOnTo->userName() );
|
||||
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
|
||||
ActionCollection::instance()->getAction( "latchOn" )->setText( tr( "&Catch Up" ) );
|
||||
|
||||
// If not, then keep waiting
|
||||
return;
|
||||
}
|
||||
|
||||
// We're current latched, and the user changed playlist, so stop
|
||||
SourcePlaylistInterface* origsourcepi = dynamic_cast< SourcePlaylistInterface* >( m_latchedInterface.data() );
|
||||
Q_ASSERT( origsourcepi );
|
||||
const source_ptr source = origsourcepi->source();
|
||||
|
||||
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
|
||||
cmd->setSource( SourceList::instance()->getLocal() );
|
||||
cmd->setAction( "latchOff");
|
||||
cmd->setComment( source->userName() );
|
||||
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
|
||||
if ( !m_waitingForLatch.isNull() &&
|
||||
m_waitingForLatch != m_latchedOnTo )
|
||||
{
|
||||
// We are asked to latch on immediately to another source
|
||||
m_latchedOnTo.clear();
|
||||
m_latchedInterface.clear();
|
||||
|
||||
// call ourselves to hit the "create latch" condition
|
||||
playlistChanged( 0 );
|
||||
return;
|
||||
}
|
||||
m_latchedOnTo.clear();
|
||||
m_waitingForLatch.clear();
|
||||
m_latchedInterface.clear();
|
||||
|
||||
m_state = NotLatched;
|
||||
|
||||
ActionCollection::instance()->getAction( "latchOn" )->setText( tr( "&Listen Along" ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LatchManager::catchUpRequest()
|
||||
{
|
||||
//it's a catch-up -- logic in audioengine should take care of it
|
||||
AudioEngine::instance()->next();
|
||||
}
|
||||
|
||||
void
|
||||
LatchManager::unlatchRequest( const source_ptr& source )
|
||||
{
|
||||
Q_UNUSED( source );
|
||||
AudioEngine::instance()->stop();
|
||||
AudioEngine::instance()->setPlaylist( 0 );
|
||||
|
||||
ActionCollection::instance()->getAction( "latchOn" )->setText( tr( "&Listen Along" ) );
|
||||
}
|