Compare commits
494 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a4d01685cf | ||
|
c6101fb35b | ||
|
467cb26006 | ||
|
8f20c828fa | ||
|
76ccd71c51 | ||
|
bb95e33673 | ||
|
012bb49328 | ||
|
3b083a2535 | ||
|
2f8b23b908 | ||
|
5d54f20bec | ||
|
afba38f9ff | ||
|
0dd2cb5f15 | ||
|
8b42e88a8d | ||
|
70cb7bd92b | ||
|
87fc3563a1 | ||
|
95c48aa722 | ||
|
6fadeab1dd | ||
|
9d03d77068 | ||
|
585009bc16 | ||
|
a19198b206 | ||
|
99d75636a9 | ||
|
eabefe438d | ||
|
7e47d0efcc | ||
|
2236b0ffb3 | ||
|
67611d10d1 | ||
|
97e1d0fe3f | ||
|
a9339caa8b | ||
|
2b4e1c7d92 | ||
|
9eaec0106b | ||
|
36fcbe83b7 | ||
|
003b959482 | ||
|
c7cbb47742 | ||
|
ea3f982415 | ||
|
03121f95ff | ||
|
18c50a3f02 | ||
|
eecceb134a | ||
|
a463c02273 | ||
|
ddfef98e20 | ||
|
0c4db907b3 | ||
|
26509493a2 | ||
|
a70f14e7ab | ||
|
2c3e7492a5 | ||
|
adde983572 | ||
|
527b4906c9 | ||
|
8e7c9d8130 | ||
|
bfb10e385f | ||
|
e28d61935e | ||
|
ea11f7c7be | ||
|
cfbccb85cf | ||
|
643b2374a6 | ||
|
d32307ca0f | ||
|
952c563713 | ||
|
8e91ab63ca | ||
|
d2ed4aeaf8 | ||
|
111f569081 | ||
|
6c7206c147 | ||
|
b35e6ce61d | ||
|
3fbd58fcc9 | ||
|
216759b214 | ||
|
36c8621133 | ||
|
9d6b5e60fc | ||
|
70aa98753b | ||
|
111de47023 | ||
|
c45eec065d | ||
|
55fec99ce3 | ||
|
e62afc6ed7 | ||
|
810c933e93 | ||
|
6861eb3000 | ||
|
8efa33e249 | ||
|
52d5dbaf4d | ||
|
92ae8ea352 | ||
|
ebe7063ec8 | ||
|
a1155cd7fa | ||
|
3d1b7ac4cf | ||
|
c1a1452c2f | ||
|
b642ca136b | ||
|
ab5f2a8b5a | ||
|
1ba3f91cba | ||
|
c8bda2ccbe | ||
|
4a0f91d052 | ||
|
51adf23cb9 | ||
|
deca5bc70d | ||
|
d97274be78 | ||
|
f4b1c5ba9f | ||
|
c2285dba84 | ||
|
5441128473 | ||
|
6790a10615 | ||
|
e46a5f307f | ||
|
7690eddff3 | ||
|
76a8e2b2b2 | ||
|
7d5986e61f | ||
|
813e657ee4 | ||
|
cdfde7ecc3 | ||
|
d5935b632f | ||
|
e50c661496 | ||
|
ecc6b679a7 | ||
|
ee2670b813 | ||
|
95b43964df | ||
|
e67653dbfd | ||
|
125fa25d07 | ||
|
3e315f3a4a | ||
|
ace52b0d28 | ||
|
9449fbf1bf | ||
|
05f58b2dfe | ||
|
85618cc62b | ||
|
b0b7aa426d | ||
|
11bcdc9cb9 | ||
|
c77aecd59f | ||
|
d16ed39dbe | ||
|
63dae07d44 | ||
|
c1df1387f0 | ||
|
6d67b129d2 | ||
|
07d91b1d58 | ||
|
87966d5636 | ||
|
83f9d86e1d | ||
|
7bb1eeb128 | ||
|
b02f8c0d9c | ||
|
f4f5750cd4 | ||
|
3f9046d61d | ||
|
cbc9d48a73 | ||
|
14457750ff | ||
|
05b4f38cb5 | ||
|
990462ddae | ||
|
b903dca9cf | ||
|
454944d089 | ||
|
5738b4f75d | ||
|
6c11a62fa4 | ||
|
33007cb05e | ||
|
a62b09076c | ||
|
a438e08080 | ||
|
53863e9155 | ||
|
d44eb51034 | ||
|
6771d1c7d7 | ||
|
ec10d9f723 | ||
|
4fa77e15c2 | ||
|
6194517eab | ||
|
74d6ccd47d | ||
|
026b257fef | ||
|
bd635d6077 | ||
|
ea497de3c4 | ||
|
b09206d2b9 | ||
|
2a7fabf633 | ||
|
a1f82f38bd | ||
|
90e532395b | ||
|
349509d0b0 | ||
|
cd7efebdf8 | ||
|
ba16ca9a72 | ||
|
a6134533be | ||
|
6626c7f877 | ||
|
9c0a3496a4 | ||
|
0b860abffb | ||
|
1f0c70e071 | ||
|
e38392f129 | ||
|
5be300bd62 | ||
|
d1f6a50e30 | ||
|
a1c8b326ab | ||
|
885c52a042 | ||
|
82ac16feb4 | ||
|
68114e1f59 | ||
|
710e570845 | ||
|
ff44238d06 | ||
|
71eb1e916a | ||
|
0314760451 | ||
|
b9a909eb56 | ||
|
73f05971e4 | ||
|
c0c2cc6234 | ||
|
ba6b14863c | ||
|
d5e6151eee | ||
|
6a4bbb7ec1 | ||
|
124d31c542 | ||
|
98a196192e | ||
|
78aa6606f9 | ||
|
077e9ab84a | ||
|
e21f2a5e87 | ||
|
d06b0e824d | ||
|
6b5ef37724 | ||
|
7ab179e23f | ||
|
a62a4c354f | ||
|
2783651537 | ||
|
aa82c276c9 | ||
|
96c6ebfe99 | ||
|
bd0e347281 | ||
|
4eb3359422 | ||
|
fedb669041 | ||
|
b39dbe6880 | ||
|
14df0aef4a | ||
|
ab574a2a1c | ||
|
d1e230121e | ||
|
06a5cbc8bb | ||
|
d2d2678496 | ||
|
bd071f472c | ||
|
20759b9b1c | ||
|
eef79f6fc2 | ||
|
1d63867f58 | ||
|
866bf93721 | ||
|
4e3febcb5b | ||
|
479262c846 | ||
|
5c2da3d835 | ||
|
309a6843f0 | ||
|
6ee2e0fe14 | ||
|
abf552e3a1 | ||
|
c064d27fb8 | ||
|
a8fffe6fdc | ||
|
f39722c2f8 | ||
|
ad3f981c9f | ||
|
3d3c381dd7 | ||
|
6901a9f47e | ||
|
a89d20665f | ||
|
f239473f0c | ||
|
c09dcc74e3 | ||
|
3f50bace71 | ||
|
54e4391576 | ||
|
daf895c53d | ||
|
a9dff282e3 | ||
|
f3d3f19ef8 | ||
|
81b9af0dc9 | ||
|
5f907258eb | ||
|
09d89c3663 | ||
|
26e5c302d8 | ||
|
c3474833b9 | ||
|
d2a5092862 | ||
|
e9314775aa | ||
|
8dcf7d0db2 | ||
|
97ff1100d1 | ||
|
7b36ea323f | ||
|
c7e4fc777f | ||
|
e3165d8928 | ||
|
976a2eeb0a | ||
|
f7ffead6c2 | ||
|
6dea6dc0a5 | ||
|
1045269e6e | ||
|
c7002a1364 | ||
|
3d5c737651 | ||
|
8c8de62271 | ||
|
5e41e052ba | ||
|
a8a8218e93 | ||
|
c60e96b365 | ||
|
f8d364af0f | ||
|
be2847740e | ||
|
d24ff66696 | ||
|
3e1310eac4 | ||
|
375ae62f64 | ||
|
ebb59b50c6 | ||
|
6dc8e98003 | ||
|
0e36f77dd4 | ||
|
5e0390bd87 | ||
|
493cf75470 | ||
|
a2e94ef4a7 | ||
|
64be53ab8a | ||
|
18329b122d | ||
|
7e6931f25a | ||
|
269488fdb7 | ||
|
a8c58705f4 | ||
|
ef98ac41ce | ||
|
56db97fea5 | ||
|
cefd96664b | ||
|
f6657845df | ||
|
b1955dd9b7 | ||
|
d571a79746 | ||
|
78e1f8236c | ||
|
457c916101 | ||
|
d4def82cd1 | ||
|
06c5f2e84b | ||
|
2004977b09 | ||
|
ad0be3aa3c | ||
|
35a0db7a07 | ||
|
427a26e034 | ||
|
b4fa46c3c7 | ||
|
7030d43e32 | ||
|
1a1106012b | ||
|
56e73fb274 | ||
|
56dd8d47db | ||
|
841cef878d | ||
|
6f4782ba71 | ||
|
5960da1722 | ||
|
4ca5cf456a | ||
|
97e5b3a5c4 | ||
|
0e5dd14bcf | ||
|
3c942b1249 | ||
|
68de791e8c | ||
|
41a37b4690 | ||
|
9e6dbcc7b1 | ||
|
64f4445a01 | ||
|
e29dc4a8a6 | ||
|
0a1f2304e9 | ||
|
1d84f6ede6 | ||
|
8f465b2984 | ||
|
2d32a2db90 | ||
|
138381a61d | ||
|
f5b3c20c4c | ||
|
abb8217286 | ||
|
4bc38491e4 | ||
|
4973768078 | ||
|
bbf7555089 | ||
|
b48896157d | ||
|
cd2fd37f84 | ||
|
97a3d6fcd3 | ||
|
1309334f99 | ||
|
c99cfe54ed | ||
|
d73cd9479c | ||
|
2bb7f91e7d | ||
|
a8105c3347 | ||
|
f23543217e | ||
|
080b1b1817 | ||
|
1f19a618a1 | ||
|
f42a412bcc | ||
|
8ddb295f06 | ||
|
3cc9da298d | ||
|
4ff1812526 | ||
|
692a4043e8 | ||
|
e81baf0eb7 | ||
|
118e6867ff | ||
|
bbdb15c53e | ||
|
7fcb31dda7 | ||
|
2a53f266fc | ||
|
452ac9630a | ||
|
5f61e3b1bd | ||
|
6bc9f88189 | ||
|
92d7757e47 | ||
|
2fb8b57e25 | ||
|
c295514598 | ||
|
fc36c5ae91 | ||
|
c05bae9e8c | ||
|
9e5f5eb750 | ||
|
3c30b08c36 | ||
|
658f0bf9bc | ||
|
5991467d40 | ||
|
392197608f | ||
|
2278f5d668 | ||
|
b0c14d6217 | ||
|
c32800c119 | ||
|
b8cc0ddbcd | ||
|
6a23954539 | ||
|
dc0316018a | ||
|
752c1b38a0 | ||
|
f5512d7b95 | ||
|
a2f880d160 | ||
|
f500efdaf9 | ||
|
ba34fd75a9 | ||
|
1761f7af0c | ||
|
01fb91ac59 | ||
|
bd629e6178 | ||
|
1860d7732a | ||
|
27df8fd3dc | ||
|
690c480462 | ||
|
868779c40c | ||
|
a1b24c1244 | ||
|
051282be06 | ||
|
fb0a88aa98 | ||
|
fc69e7d08d | ||
|
02708629ca | ||
|
558b902b62 | ||
|
d894116e8e | ||
|
8fcfed61bb | ||
|
6448a91d5c | ||
|
9c0a608e3e | ||
|
48961a822c | ||
|
c47c8894b0 | ||
|
eaf48bcf51 | ||
|
53b00db602 | ||
|
5c47ae96ab | ||
|
bbec1dfbbe | ||
|
064efb4570 | ||
|
0ef5a6675d | ||
|
2d4f7c8898 | ||
|
7946362dcf | ||
|
c1e7ef2ea3 | ||
|
faadb41054 | ||
|
a928436eb5 | ||
|
7f5c78ec9f | ||
|
8b9540cf9d | ||
|
afb624f8eb | ||
|
ac93b7e9f6 | ||
|
becb263635 | ||
|
4d188af33e | ||
|
c1cb85fee6 | ||
|
76f7c303a1 | ||
|
238c07b8bd | ||
|
01d17bde9b | ||
|
51a956ec77 | ||
|
3ff0897d72 | ||
|
1a333d85d6 | ||
|
ba54b5ce8e | ||
|
4b6e1ea0d7 | ||
|
5ad53e0af5 | ||
|
6e612fa9dd | ||
|
c1ec90b825 | ||
|
e7dda25cac | ||
|
b0c9b86b3a | ||
|
a674570efd | ||
|
67e18c3b9d | ||
|
5547a9741d | ||
|
9e62b812f7 | ||
|
22732d5c68 | ||
|
c5691fce9a | ||
|
76600e015c | ||
|
ceba1431f7 | ||
|
900b836b1e | ||
|
d786f5c13b | ||
|
4f26b805d7 | ||
|
ca22cfd31d | ||
|
028f6b969e | ||
|
90de0237e0 | ||
|
a846d91bef | ||
|
0b3c794cc9 | ||
|
d890ea3b14 | ||
|
5ed6bb52b5 | ||
|
295f059e19 | ||
|
b25b611685 | ||
|
6ec80761eb | ||
|
d907a9fbc8 | ||
|
0c00cccc1f | ||
|
a9bf18e17f | ||
|
47cb8deab1 | ||
|
bbc851fca2 | ||
|
fdcd2aa728 | ||
|
5827974b45 | ||
|
9bfc9d3f0f | ||
|
e7c7737500 | ||
|
dee2dad874 | ||
|
363becf9b9 | ||
|
95fa9a2b89 | ||
|
35c9509477 | ||
|
4a97e057be | ||
|
d7d8c5940f | ||
|
23f47f82a6 | ||
|
393ec8a53d | ||
|
7ba97a817d | ||
|
dbeb46d513 | ||
|
ef80237d39 | ||
|
06e081b7a0 | ||
|
403f80d721 | ||
|
9505e433bc | ||
|
239601f637 | ||
|
8909108516 | ||
|
fac37debad | ||
|
cd9ba367af | ||
|
e1416fce06 | ||
|
a7d90b16e7 | ||
|
4ef0d23900 | ||
|
937908766c | ||
|
9b09cbd11e | ||
|
cb578a607a | ||
|
856b6cc164 | ||
|
2302f0eb41 | ||
|
c14984c647 | ||
|
1369e838eb | ||
|
09f84fe9e6 | ||
|
31fda52bcf | ||
|
cede202e96 | ||
|
7efaa62038 | ||
|
f303fcbebc | ||
|
d0fdff760e | ||
|
3a5acb721c | ||
|
03695c2bc4 | ||
|
3a580faa1d | ||
|
6fc4f2a89a | ||
|
dbd137a561 | ||
|
fa52f8a75c | ||
|
5bd616e59d | ||
|
e4e3b0f825 | ||
|
035e59e0b5 | ||
|
e316534dc0 | ||
|
8fc89f3a2b | ||
|
972a57bfeb | ||
|
0dad8b9218 | ||
|
2f07c92fdd | ||
|
e5439c7775 | ||
|
dc9e3728f5 | ||
|
0f7291368f | ||
|
18be2f5f7e | ||
|
ee6e3c9e69 | ||
|
b453d80808 | ||
|
7fb6701e3e | ||
|
a9e0c3c460 | ||
|
2fd970d24d | ||
|
d39378b599 | ||
|
037a5dab12 | ||
|
38735cb248 | ||
|
cf01330778 | ||
|
6f8676feec | ||
|
f9de027557 | ||
|
f2101c2986 | ||
|
746914844e | ||
|
021546cb73 | ||
|
7dd88208a7 | ||
|
f134e48a49 | ||
|
88da871f6a | ||
|
a54e5fbf46 | ||
|
d3eb5c3f88 | ||
|
0a3a9a7e97 | ||
|
9171de999b | ||
|
f8ca1ac994 | ||
|
5cc86b7876 |
2
.gitignore
vendored
@@ -5,6 +5,8 @@ build/*
|
||||
*.o
|
||||
._*
|
||||
*.user
|
||||
*.swp
|
||||
*.swo
|
||||
Makefile*
|
||||
moc_*
|
||||
*~
|
||||
|
@@ -13,7 +13,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 5 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 4 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 99 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
@@ -88,7 +88,7 @@ IF( NOT BUILD_GUI )
|
||||
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} in HEADLESS mode ***" )
|
||||
ELSE()
|
||||
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} full GUI version ***" )
|
||||
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" )
|
||||
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" "QtDeclarative" )
|
||||
ENDIF()
|
||||
|
||||
IF( BUILD_GUI AND UNIX AND NOT APPLE )
|
||||
@@ -104,8 +104,8 @@ if(PHONON_FOUND)
|
||||
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
|
||||
endif()
|
||||
|
||||
macro_optional_find_package(LibEchonest 1.2.1)
|
||||
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.2.1 is needed for dynamic playlists and the infosystem")
|
||||
macro_optional_find_package(Echonest 2.0.0)
|
||||
macro_log_feature(ECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 2.0.0 is needed for dynamic playlists and the infosystem")
|
||||
|
||||
macro_optional_find_package(CLucene 0.9.23)
|
||||
macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" "http://clucene.sf.net" TRUE "" "CLucene is used for indexing the collection")
|
||||
@@ -118,11 +118,11 @@ macro_log_feature(TAGLIB_FOUND "TagLib" "Audio Meta-Data Library" "http://develo
|
||||
include( CheckTagLibFileName )
|
||||
check_taglib_filename( COMPLEX_TAGLIB_FILENAME )
|
||||
|
||||
macro_optional_find_package(Boost)
|
||||
macro_optional_find_package( Boost )
|
||||
macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++ source libraries" "http://www.boost.org" TRUE "" "") #FIXME: give useful explaination
|
||||
|
||||
macro_optional_find_package(QCA2)
|
||||
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "")
|
||||
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" TRUE "" "")
|
||||
|
||||
macro_optional_find_package(LibAttica 0.4.0)
|
||||
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" TRUE "" "")
|
||||
|
147
CMakeLists.txt.user.2.3pre1
Normal file
@@ -0,0 +1,147 @@
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value key="EditorConfiguration.AutoIndent" type="bool">true</value>
|
||||
<value key="EditorConfiguration.AutoSpacesForTabs" type="bool">false</value>
|
||||
<value key="EditorConfiguration.Codec" type="QByteArray">UTF-8</value>
|
||||
<value key="EditorConfiguration.DoubleIndentBlocks" type="bool">false</value>
|
||||
<value key="EditorConfiguration.IndentBraces" type="bool">false</value>
|
||||
<value key="EditorConfiguration.IndentSize" type="int">4</value>
|
||||
<value key="EditorConfiguration.MouseNavigation" type="bool">true</value>
|
||||
<value key="EditorConfiguration.PaddingMode" type="int">1</value>
|
||||
<value key="EditorConfiguration.ScrollWheelZooming" type="bool">true</value>
|
||||
<value key="EditorConfiguration.SmartBackspace" type="bool">false</value>
|
||||
<value key="EditorConfiguration.SpacesForTabs" type="bool">true</value>
|
||||
<value key="EditorConfiguration.TabKeyBehavior" type="int">0</value>
|
||||
<value key="EditorConfiguration.TabSize" type="int">8</value>
|
||||
<value key="EditorConfiguration.UseGlobal" type="bool">true</value>
|
||||
<value key="EditorConfiguration.Utf8BomBehavior" type="int">1</value>
|
||||
<value key="EditorConfiguration.addFinalNewLine" type="bool">true</value>
|
||||
<value key="EditorConfiguration.cleanIndentation" type="bool">true</value>
|
||||
<value key="EditorConfiguration.cleanWhitespace" type="bool">true</value>
|
||||
<value key="EditorConfiguration.inEntireDocument" type="bool">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Desktop</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.DefaultCMakeTarget</value>
|
||||
<value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value>
|
||||
<value key="ProjectExplorer.Target.ActiveDeployConfiguration" type="int">0</value>
|
||||
<value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
|
||||
<valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
|
||||
<value key="CMakeProjectManager.CMakeBuildConfiguration.BuildDirectory" type="QString">/home/micha/Develop/tomahawk-build</value>
|
||||
<value key="CMakeProjectManager.CMakeBuildConfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit.</value>
|
||||
<value key="ProjectExplorer.BuildCOnfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit.</value>
|
||||
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
|
||||
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
|
||||
<value key="CMakeProjectManager.MakeStep.AdditionalArguments" type="QString"></value>
|
||||
<valuelist key="CMakeProjectManager.MakeStep.BuildTargets" type="QVariantList"/>
|
||||
<value key="CMakeProjectManager.MakeStep.Clean" type="bool">false</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Make</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">1</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Build</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.1" type="QVariantMap">
|
||||
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
|
||||
<value key="CMakeProjectManager.MakeStep.AdditionalArguments" type="QString">clean</value>
|
||||
<valuelist key="CMakeProjectManager.MakeStep.BuildTargets" type="QVariantList"/>
|
||||
<value key="CMakeProjectManager.MakeStep.Clean" type="bool">true</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Make</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.MakeStep</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">1</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Clean</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.BuildConfiguration.BuildStepListCount" type="int">2</value>
|
||||
<value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
|
||||
<valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">all</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.CMakeBuildConfiguration</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">1</value>
|
||||
<valuemap key="ProjectExplorer.Target.DeployConfiguration.0" type="QVariantMap">
|
||||
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
|
||||
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">0</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Deploy</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.BuildConfiguration.BuildStepListCount" type="int">1</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">No deployment</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.Target.DeployConfigurationCount" type="int">1</value>
|
||||
<valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
|
||||
<valuelist key="Analyzer.Valgrind.AddedSupressionFiles" type="QVariantList"/>
|
||||
<value key="Analyzer.Valgrind.FilterExternalIssues" type="bool">true</value>
|
||||
<value key="Analyzer.Valgrind.NumCallers" type="int">25</value>
|
||||
<valuelist key="Analyzer.Valgrind.RemovedSupressionFiles" type="QVariantList"/>
|
||||
<value key="Analyzer.Valgrind.TrackOrigins" type="bool">true</value>
|
||||
<value key="Analyzer.Valgrind.ValgrindExecutable" type="QString">valgrind</value>
|
||||
<valuelist key="Analyzer.Valgrind.VisibleErrorKinds" type="QVariantList">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value key="CMakeProjectManager.BaseEnvironmentBase" type="int">2</value>
|
||||
<value key="CMakeProjectManager.CMakeRunConfiguation.Title" type="QString">tomahawk</value>
|
||||
<value key="CMakeProjectManager.CMakeRunConfiguration.Arguments" type="QString">--verbose</value>
|
||||
<value key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal" type="bool">false</value>
|
||||
<valuelist key="CMakeProjectManager.CMakeRunConfiguration.UserEnvironmentChanges" type="QVariantList">
|
||||
<value type="QString">Q_FATAL_WARNINGS=1</value>
|
||||
</valuelist>
|
||||
<value key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">tomahawk</value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
|
||||
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.CMakeRunConfiguration.</value>
|
||||
<value key="RunConfiguration.QmlDebugServerPort" type="uint">3768</value>
|
||||
<value key="RunConfiguration.UseCppDebugger" type="bool">true</value>
|
||||
<value key="RunConfiguration.UseQmlDebugger" type="bool">false</value>
|
||||
</valuemap>
|
||||
<value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
|
||||
<value type="QString">{6caf061d-47d5-4e4f-a8d8-0d83c14e4267}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">9</value>
|
||||
</data>
|
||||
</qtcreator>
|
36
CMakeModules/FindEchonest.cmake
Normal file
@@ -0,0 +1,36 @@
|
||||
# - Find libechonest
|
||||
# Find the libechonest includes and the libechonest libraries
|
||||
# This module defines
|
||||
# ECHONEST_INCLUDE_DIR, root echonest include dir. Include echonest includes with echonest/foo.h
|
||||
# ECHONEST_LIBRARIES, the path to libechonest
|
||||
# ECHONEST_FOUND, whether libechonest was found
|
||||
|
||||
FIND_PACKAGE(PkgConfig QUIET)
|
||||
PKG_CHECK_MODULES(PC_ECHONEST QUIET libechonest)
|
||||
|
||||
FIND_PATH(ECHONEST_INCLUDE_DIR NAMES echonest/Track.h
|
||||
HINTS
|
||||
${PC_ECHONEST_INCLUDEDIR}
|
||||
${PC_ECHONEST_INCLUDE_DIRS}
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
${KDE4_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ECHONEST_LIBRARIES NAMES echonest
|
||||
HINTS
|
||||
${PC_ECHONEST_LIBDIR}
|
||||
${PC_ECHONEST_LIBRARY_DIRS}
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
${KDE4_LIB_DIR}
|
||||
)
|
||||
|
||||
IF(ECHONEST_LIBRARIES AND ECHONEST_INCLUDE_DIR AND NOT PC_ECHONEST_VERSION)
|
||||
MESSAGE(WARNING "You don't have pkg-config and so the libechonest version check does not work!")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Echonest
|
||||
REQUIRED_VARS ECHONEST_LIBRARIES ECHONEST_INCLUDE_DIR
|
||||
VERSION_VAR PC_ECHONEST_VERSION)
|
||||
|
||||
MARK_AS_ADVANCED(ECHONEST_INCLUDE_DIR ECHONEST_LIBRARIES)
|
@@ -1,42 +0,0 @@
|
||||
# - Find libechonest
|
||||
# Find the libechonest includes and the libechonest libraries
|
||||
# This module defines
|
||||
# LIBECHONEST_INCLUDE_DIR, root echonest include dir. Include echonest includes with echonest/foo.h
|
||||
# LIBECHONEST_LIBRARY, the path to libechonest
|
||||
# LIBECHONEST_FOUND, whether libechonest was found
|
||||
|
||||
|
||||
find_path(LIBECHONEST_INCLUDE_DIR NAMES echonest_export.h
|
||||
HINTS
|
||||
~/usr/include
|
||||
/opt/local/include
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/kde4/include
|
||||
${KDE4_INCLUDE_DIR}
|
||||
PATH_SUFFIXES echonest
|
||||
)
|
||||
|
||||
find_library( LIBECHONEST_LIBRARY NAMES echonest
|
||||
PATHS
|
||||
~/usr/lib
|
||||
/opt/local/lib
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib
|
||||
/opt/kde4/lib
|
||||
${KDE4_LIB_DIR}
|
||||
)
|
||||
|
||||
|
||||
if(LIBECHONEST_INCLUDE_DIR AND LIBECHONEST_LIBRARY)
|
||||
set(LIBECHONEST_FOUND TRUE)
|
||||
message(STATUS "Found libechonest: ${LIBECHONEST_INCLUDE_DIR}, ${LIBECHONEST_LIBRARY}")
|
||||
else(LIBECHONEST_INCLUDE_DIR AND LIBECHONEST_LIBRARY)
|
||||
set(LIBECHONEST_FOUND FALSE)
|
||||
if (LIBECHONEST_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could NOT find required package libechonest")
|
||||
endif(LIBECHONEST_FIND_REQUIRED)
|
||||
endif(LIBECHONEST_INCLUDE_DIR AND LIBECHONEST_LIBRARY)
|
||||
|
||||
mark_as_advanced(LIBECHONEST_INCLUDE_DIR LIBECHONEST_LIBRARY)
|
18
ChangeLog
@@ -1,3 +1,21 @@
|
||||
Version 0.6.0:
|
||||
* Access Control queries now stay on the bottom of the job view,
|
||||
removing the tendency to jump away from the mouse.
|
||||
|
||||
Version 0.5.5:
|
||||
* Changed the Spotify config dialog to indicate when the user
|
||||
is logged in.
|
||||
* Fixed bug where the wrong avatar could be shown for a user.
|
||||
* Fixed shortcuts not working in the global search field on OS X.
|
||||
* Fixed The Echo Nest stations.
|
||||
* Code-signed executable on OS X for GateKeeper.
|
||||
* Fixed logging in to Spotify when pressing return in the config dialog.
|
||||
* Fixed queue not auto-collapsing when playing the last track.
|
||||
* Fixed bug where album listings would fail to show up.
|
||||
* Improved stability.
|
||||
* Fixed bug where it was not possible to drop a mixture of resolved
|
||||
and unresolved tracks onto a playlist.
|
||||
|
||||
Version 0.5.4:
|
||||
* Improved stability.
|
||||
* Added support for Spotify album lookups.
|
||||
|
2
README
@@ -34,7 +34,7 @@ Dependencies
|
||||
TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html
|
||||
Boost 1.3 - http://www.boost.org/
|
||||
CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml
|
||||
libechonest 1.2.1 - http://projects.kde.org/projects/playground/libs/libechonest/
|
||||
libechonest 2.0.0 - http://projects.kde.org/projects/playground/libs/libechonest/
|
||||
Attica 0.4.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
|
||||
QuaZip 0.4.3 - http://quazip.sourceforge.net/
|
||||
|
||||
|
@@ -45,6 +45,9 @@ VERSION=$1
|
||||
header "Creating DMG"
|
||||
cd ..
|
||||
|
||||
header "Signing bundle"
|
||||
codesign -s "Developer ID Application: Leonardo Franchi" -f -v ./Tomahawk.app
|
||||
|
||||
$ROOT/../admin/mac/create-dmg.sh Tomahawk.app
|
||||
mv Tomahawk.dmg Tomahawk-$VERSION.dmg
|
||||
|
||||
|
@@ -49,10 +49,33 @@ tar xvjf pvlc.tar.bz2
|
||||
# libtaglib_plugin.dll
|
||||
|
||||
|
||||
# this is for vlc-1.2
|
||||
# rm -rvf video_*/ gui/ */libold* */libvcd* */libdvd* */liblibass* */libx264* */libschroe* */liblibmpeg2* \
|
||||
# */libstream_out_* */libmjpeg_plugin* */libh264_plugin* */libzvbi_plugin* */lib*sub* \
|
||||
# services_discover/ visualization/ control/ misc/
|
||||
# this is for vlc-2.x
|
||||
rm -rvf \
|
||||
video_*/ \
|
||||
gui/ \
|
||||
**/libold* \
|
||||
**/libvcd* \
|
||||
**/libdvd* \
|
||||
**/liblibass* \
|
||||
**/libx264* \
|
||||
**/libschroe* \
|
||||
**/liblibmpeg2* \
|
||||
**/libstream_out_* \
|
||||
**/libmjpeg_plugin* \
|
||||
**/libh264_plugin* \
|
||||
**/libzvbi_plugin* \
|
||||
**/lib*sub* \
|
||||
services_discovery/ \
|
||||
visualization/ \
|
||||
control/ \
|
||||
misc/ \
|
||||
**/libi420* \
|
||||
**/libi422* \
|
||||
mux/ \
|
||||
stream_filter/ \
|
||||
**/libtheora_plugin* \
|
||||
**/liblibbluray_plugin* \
|
||||
**/libdtv_plugin*
|
||||
|
||||
|
||||
echo "Downloaded and stripped VLC"
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 6.3 KiB |
@@ -1,80 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="606.2478"
|
||||
height="595.49866"
|
||||
viewBox="0 0 606.24779 595.49863"
|
||||
enable-background="new 0 0 841.89 595.28"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="tomahawk-icon.svg"><metadata
|
||||
id="metadata15"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs13" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="794"
|
||||
id="namedview11"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="431.12548"
|
||||
inkscape:cy="336.94553"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:snap-page="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"><sodipodi:guide
|
||||
position="-3.5728101e-05,-1.501866e-05"
|
||||
orientation="0,841.89001"
|
||||
id="guide2994" /><sodipodi:guide
|
||||
position="841.88997,-1.501866e-05"
|
||||
orientation="-595.28003,0"
|
||||
id="guide2996" /><sodipodi:guide
|
||||
position="841.88997,595.28001"
|
||||
orientation="0,-841.89001"
|
||||
id="guide2998" /><sodipodi:guide
|
||||
position="-3.5728101e-05,595.28001"
|
||||
orientation="595.28003,0"
|
||||
id="guide3000" /></sodipodi:namedview>
|
||||
<g
|
||||
id="g3"
|
||||
transform="matrix(7.3080643,0,0,7.1790074,-2773.1692,-1839.0104)">
|
||||
<g
|
||||
id="g5">
|
||||
<path
|
||||
d="m 420.947,265.168 c -17.911,0 -32.477,14.565 -32.477,32.472 0,17.906 14.565,32.476 32.477,32.476 2.568,0 5.06,-0.318 7.459,-0.888 v -28.011 l -22.338,15.806 c -0.198,0.135 -0.444,0.213 -0.681,0.213 -0.184,0 -0.372,-0.039 -0.541,-0.136 -0.396,-0.202 -0.642,-0.608 -0.642,-1.043 v -37.053 c 0,-0.435 0.246,-0.845 0.642,-1.053 0.396,-0.193 0.864,-0.159 1.222,0.092 l 22.338,15.807 v -16.028 h 0.951 8.945 v 47.234 c 9.076,-5.764 15.121,-15.888 15.121,-27.417 10e-4,-17.905 -14.569,-32.471 -32.476,-32.471 z"
|
||||
id="path7"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none" />
|
||||
<path
|
||||
d="m 420.947,256.165 c -22.874,0 -41.48,18.606 -41.48,41.475 0,22.87 18.606,41.475 41.48,41.475 22.869,0 41.476,-18.605 41.476,-41.475 0,-22.869 -18.607,-41.475 -41.476,-41.475 z m 17.356,68.892 v -47.234 h -8.945 -0.951 v 16.028 l -22.338,-15.807 c -0.357,-0.251 -0.826,-0.285 -1.222,-0.092 -0.396,0.208 -0.642,0.618 -0.642,1.053 v 37.053 c 0,0.435 0.246,0.841 0.642,1.043 0.169,0.097 0.357,0.136 0.541,0.136 0.236,0 0.482,-0.078 0.681,-0.213 l 22.338,-15.806 v 28.011 c -2.399,0.569 -4.891,0.888 -7.459,0.888 -17.911,0 -32.477,-14.57 -32.477,-32.476 0,-17.906 14.565,-32.472 32.477,-32.472 17.906,0 32.477,14.565 32.477,32.472 -0.001,11.528 -6.046,21.652 -15.122,27.416 z"
|
||||
id="path9"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#e63e30" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="606.248px" height="595.5px" viewBox="0 0 606.248 595.5" enable-background="new 0 0 606.248 595.5" xml:space="preserve">
|
||||
<g id="Layer_3">
|
||||
<rect x="-20.376" y="-15.75" stroke="#E63E30" stroke-miterlimit="10" width="688" height="700"/>
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<path id="path9_1_" inkscape:connector-curvature="0" fill="none" stroke="#E63E30" stroke-miterlimit="10" d="M429.977,493.576
|
||||
V154.483h-65.371h-6.949v115.065L194.409,156.07c-2.608-1.802-6.036-2.046-8.93-0.661c-2.895,1.493-4.692,4.437-4.692,7.56v266.003
|
||||
c0,3.123,1.798,6.037,4.692,7.488c1.234,0.695,2.608,0.977,3.953,0.977c1.725,0,3.522-0.561,4.977-1.529l163.248-113.472v201.091
|
||||
c-17.532,4.084-35.744,6.375-54.511,6.375c-130.896,0-237.345-104.598-237.345-233.146c0-128.547,106.442-233.117,237.345-233.117
|
||||
c130.858,0,237.344,104.562,237.344,233.116C540.482,379.515,496.305,452.197,429.977,493.576L429.977,493.576z"/>
|
||||
<ellipse fill="#FFFFFF" stroke="#E63E30" stroke-miterlimit="10" cx="318.624" cy="295.75" rx="286" ry="270.5"/>
|
||||
</g>
|
||||
<g id="Layer_1" sodipodi:docname="tomahawk-icon.svg" inkscape:version="0.48.2 r9819" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
|
||||
|
||||
<sodipodi:namedview fit-margin-bottom="0" fit-margin-right="0" inkscape:snap-page="false" inkscape:current-layer="Layer_1" inkscape:window-maximized="0" inkscape:window-y="0" inkscape:window-x="0" inkscape:window-height="794" inkscape:window-width="1440" inkscape:pageshadow="2" inkscape:pageopacity="0" fit-margin-left="0" fit-margin-top="0" inkscape:cy="336.94553" inkscape:cx="431.12548" inkscape:zoom="1" showgrid="false" guidetolerance="10" gridtolerance="10" objecttolerance="10" bordercolor="#666666" pagecolor="#ffffff" borderopacity="1" id="namedview11">
|
||||
<sodipodi:guide orientation="0,841.89001" position="-3.5728101e-05,-1.501866e-05" id="guide2994"></sodipodi:guide>
|
||||
<sodipodi:guide orientation="-595.28003,0" position="841.88997,-1.501866e-05" id="guide2996"></sodipodi:guide>
|
||||
<sodipodi:guide orientation="0,-841.89001" position="841.88997,595.28001" id="guide2998"></sodipodi:guide>
|
||||
<sodipodi:guide orientation="595.28003,0" position="-3.5728101e-05,595.28001" id="guide3000"></sodipodi:guide>
|
||||
</sodipodi:namedview>
|
||||
<g id="g3_1_" transform="matrix(7.3080643,0,0,7.1790074,-2773.1692,-1839.0104)">
|
||||
<g>
|
||||
<g enable-background="new ">
|
||||
<g>
|
||||
<polygon fill="#4C1410" points="430.355,293.516 429.444,293.909 429.416,279.061 430.323,277.603 "/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon fill="#4C1410" points="430.428,328.913 429.507,326.921 429.457,300.757 430.371,300.856 "/>
|
||||
</g>
|
||||
<g enable-background="new ">
|
||||
<defs>
|
||||
<path id="SVGID_1_" enable-background="new " d="M440.229,324.595l-1.574-1.692c2.083-1.367,3.987-2.983,5.669-4.803
|
||||
c1.678-1.816,3.136-3.836,4.332-6.018c1.194-2.177,2.127-4.516,2.758-6.973c0.63-2.454,0.959-5.028,0.945-7.679
|
||||
c-0.022-4.114-0.867-8.035-2.377-11.605c-1.51-3.571-3.686-6.797-6.372-9.519c-2.69-2.726-5.895-4.949-9.458-6.505
|
||||
c-3.573-1.561-7.51-2.454-11.652-2.511c-4.16-0.058-8.14,0.731-11.777,2.212c-3.65,1.486-6.953,3.668-9.739,6.386
|
||||
c-2.795,2.728-5.069,5.995-6.649,9.637c-1.584,3.651-2.47,7.677-2.486,11.907c-0.016,4.236,0.842,8.276,2.405,11.95
|
||||
c1.563,3.673,3.829,6.974,6.627,9.736c2.794,2.757,6.114,4.973,9.791,6.483c3.666,1.506,7.683,2.31,11.88,2.251
|
||||
c0.601-0.008,1.197-0.036,1.787-0.08c0.59-0.045,1.176-0.107,1.756-0.186c0.58-0.079,1.154-0.174,1.723-0.286
|
||||
c0.569-0.111,1.132-0.238,1.689-0.379l0.921,1.992c-0.597,0.152-1.201,0.288-1.81,0.408c-0.61,0.12-1.226,0.223-1.847,0.308
|
||||
c-0.622,0.085-1.249,0.153-1.883,0.201c-0.634,0.049-1.272,0.078-1.917,0.088c-4.502,0.068-8.811-0.79-12.745-2.404
|
||||
c-3.946-1.618-7.511-3.994-10.51-6.951c-3.004-2.963-5.437-6.506-7.115-10.448c-1.678-3.944-2.599-8.28-2.58-12.827
|
||||
c0.018-4.54,0.971-8.86,2.673-12.777c1.698-3.907,4.139-7.409,7.141-10.333c2.99-2.913,6.534-5.249,10.45-6.838
|
||||
c3.9-1.583,8.167-2.424,12.626-2.357c4.439,0.066,8.656,1.027,12.483,2.703c3.815,1.671,7.247,4.055,10.127,6.976
|
||||
c2.875,2.916,5.205,6.373,6.822,10.198c1.616,3.824,2.522,8.023,2.548,12.43c0.016,2.84-0.335,5.597-1.008,8.226
|
||||
c-0.674,2.633-1.672,5.139-2.949,7.472c-1.279,2.338-2.839,4.504-4.636,6.452C444.498,321.393,442.46,323.127,440.229,324.595
|
||||
z"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" overflow="visible"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#SVGID_2_)" enable-background="new ">
|
||||
<path fill="#4D1510" d="M440.229,324.595l-1.574-1.692c2.083-1.367,3.987-2.983,5.669-4.803
|
||||
c1.678-1.816,3.136-3.836,4.332-6.018c1.194-2.177,2.127-4.516,2.758-6.973c0.63-2.454,0.959-5.028,0.945-7.679
|
||||
c-0.022-4.114-0.867-8.035-2.377-11.605c-1.51-3.571-3.686-6.797-6.372-9.519c-2.69-2.726-5.895-4.949-9.458-6.505
|
||||
c-3.573-1.561-7.51-2.454-11.652-2.511c-4.16-0.058-8.14,0.731-11.777,2.212c-3.65,1.486-6.953,3.668-9.739,6.386
|
||||
c-2.795,2.728-5.069,5.995-6.649,9.637c-1.584,3.651-2.47,7.677-2.486,11.907c-0.016,4.236,0.842,8.276,2.405,11.95
|
||||
c1.563,3.673,3.829,6.974,6.627,9.736c2.794,2.757,6.114,4.973,9.791,6.483c3.666,1.506,7.683,2.31,11.88,2.251
|
||||
c0.601-0.008,1.197-0.036,1.787-0.08c0.59-0.045,1.176-0.107,1.756-0.186c0.58-0.079,1.154-0.174,1.723-0.286
|
||||
c0.569-0.111,1.132-0.238,1.689-0.379l0.921,1.992c-0.597,0.152-1.201,0.288-1.81,0.408c-0.61,0.12-1.226,0.223-1.847,0.308
|
||||
c-0.622,0.085-1.249,0.153-1.883,0.201c-0.634,0.049-1.272,0.078-1.917,0.088c-4.502,0.068-8.811-0.79-12.745-2.404
|
||||
c-3.946-1.618-7.511-3.994-10.51-6.951c-3.004-2.963-5.437-6.506-7.115-10.448c-1.678-3.944-2.599-8.28-2.58-12.827
|
||||
c0.018-4.54,0.971-8.86,2.673-12.777c1.698-3.907,4.139-7.409,7.141-10.333c2.99-2.913,6.534-5.249,10.45-6.838
|
||||
c3.9-1.583,8.167-2.424,12.626-2.357c4.439,0.066,8.656,1.027,12.483,2.703c3.815,1.671,7.247,4.055,10.127,6.976
|
||||
c2.875,2.916,5.205,6.373,6.822,10.198c1.616,3.824,2.522,8.023,2.548,12.43c0.016,2.84-0.335,5.597-1.008,8.226
|
||||
c-0.674,2.633-1.672,5.139-2.949,7.472c-1.279,2.338-2.839,4.504-4.636,6.452C444.498,321.393,442.46,323.127,440.229,324.595
|
||||
"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#E53E30" d="M422.903,256.08c5.658,0.108,11.029,1.353,15.897,3.504c4.85,2.143,9.21,5.189,12.868,8.915
|
||||
c3.65,3.717,6.608,8.117,8.662,12.983c2.053,4.864,3.208,10.204,3.247,15.808c0.04,5.613-1.043,10.98-3.039,15.883
|
||||
c-2.002,4.92-4.927,9.381-8.565,13.159c-3.654,3.795-8.032,6.904-12.92,9.095c-4.913,2.202-10.344,3.478-16.073,3.588
|
||||
c-5.761,0.111-11.281-0.966-16.325-3.014c-5.064-2.056-9.641-5.088-13.494-8.871c-3.862-3.792-6.988-8.332-9.143-13.388
|
||||
c-2.155-5.058-3.333-10.622-3.302-16.455c0.032-5.822,1.266-11.358,3.463-16.374c2.19-4.998,5.333-9.474,9.191-13.203
|
||||
c3.84-3.711,8.385-6.68,13.4-8.69C411.761,257.022,417.213,255.972,422.903,256.08z M440.229,324.595
|
||||
c2.231-1.468,4.269-3.201,6.069-5.154c1.796-1.948,3.356-4.114,4.636-6.452c1.277-2.334,2.274-4.84,2.949-7.472
|
||||
c0.673-2.629,1.024-5.386,1.008-8.226c-0.025-4.407-0.931-8.606-2.548-12.43c-1.617-3.826-3.947-7.282-6.822-10.198
|
||||
c-2.88-2.922-6.312-5.305-10.127-6.976c-3.827-1.676-8.044-2.637-12.483-2.703c-4.458-0.067-8.726,0.775-12.626,2.357
|
||||
c-3.916,1.589-7.46,3.925-10.45,6.838c-3.001,2.924-5.443,6.426-7.141,10.333c-1.702,3.917-2.655,8.237-2.673,12.777
|
||||
c-0.018,4.547,0.902,8.884,2.58,12.827c1.678,3.942,4.111,7.485,7.115,10.448c2.999,2.957,6.563,5.333,10.51,6.951
|
||||
c3.934,1.613,8.243,2.471,12.745,2.404c0.644-0.01,1.283-0.039,1.917-0.088c0.633-0.049,1.261-0.116,1.883-0.201
|
||||
c0.622-0.085,1.237-0.188,1.847-0.308c0.609-0.12,1.213-0.256,1.81-0.408l-0.057-28.056l-22.413,16.004
|
||||
c-0.051,0.034-0.104,0.065-0.16,0.092c-0.056,0.027-0.113,0.05-0.172,0.069c-0.059,0.019-0.119,0.033-0.179,0.043
|
||||
c-0.06,0.01-0.121,0.016-0.18,0.016c-0.047,0.001-0.094-0.001-0.141-0.006c-0.047-0.005-0.094-0.012-0.14-0.023
|
||||
c-0.046-0.011-0.092-0.024-0.137-0.041c-0.045-0.017-0.089-0.037-0.132-0.061c-0.1-0.05-0.191-0.114-0.271-0.187
|
||||
c-0.08-0.074-0.149-0.157-0.205-0.249c-0.056-0.091-0.1-0.19-0.13-0.294s-0.045-0.212-0.045-0.322l0.06-37.332
|
||||
c0-0.109,0.016-0.216,0.046-0.319c0.03-0.103,0.074-0.201,0.13-0.292c0.056-0.091,0.125-0.175,0.205-0.249
|
||||
c0.08-0.074,0.17-0.138,0.27-0.189c0.043-0.02,0.087-0.038,0.131-0.053s0.09-0.028,0.135-0.037
|
||||
c0.046-0.01,0.091-0.017,0.137-0.022c0.046-0.005,0.092-0.007,0.138-0.006c0.061,0.001,0.122,0.006,0.183,0.015
|
||||
c0.06,0.01,0.12,0.024,0.178,0.042c0.058,0.018,0.116,0.042,0.171,0.069c0.055,0.027,0.109,0.059,0.161,0.095l22.346,15.897
|
||||
l-0.033-15.913l0.94,0.009l8.801,0.081L440.229,324.595"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 9.1 KiB |
BIN
data/images/playlist-subscribed.png
Executable file
After Width: | Height: | Size: 1.4 KiB |
BIN
data/images/subscribe-off.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
data/images/subscribe-on.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
data/images/view-toggle-icon-grid-active.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
data/images/view-toggle-icon-grid-inactive.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
139
data/qml/ArtistInfoScene.qml
Normal file
@@ -0,0 +1,139 @@
|
||||
import QtQuick 1.1
|
||||
|
||||
Rectangle {
|
||||
color: "black"
|
||||
anchors.fill: parent
|
||||
// height: 200
|
||||
// width: 200
|
||||
|
||||
|
||||
Component {
|
||||
id: pathDelegate
|
||||
Item {
|
||||
width: 100; height: 100
|
||||
scale: PathView.iconScale
|
||||
|
||||
// TODO: Use Image provider here
|
||||
Image {
|
||||
id: originalImage
|
||||
width: 80
|
||||
height: 80
|
||||
source: index % 2 === 0 ? "http://www.muktware.com/sites/default/files/images/applications/tomahawk_icon.png" : "http://cloud.ohloh.net/attachments/53867/tomahawk-icon-64x64_med.png"
|
||||
}
|
||||
|
||||
// mirror image - album art and a gradient filled rectangle for darkening
|
||||
Item {
|
||||
width: originalImage.width; height: originalImage.height
|
||||
anchors.horizontalCenter: originalImage.horizontalCenter
|
||||
|
||||
// transform this item (the image and rectangle) to create the
|
||||
// mirror image using the values from the Path
|
||||
transform : [
|
||||
Rotation {
|
||||
angle: 180; origin.y: originalImage.height
|
||||
axis.x: 1; axis.y: 0; axis.z: 0
|
||||
},
|
||||
Rotation {
|
||||
angle: PathView.rotateY; origin.x: originalImage.width/2
|
||||
axis.x: 0; axis.y: 1; axis.z: 0
|
||||
},
|
||||
Scale {
|
||||
xScale: PathView.scaleArt; yScale: PathView.scaleArt
|
||||
origin.x: originalImage.width/2; origin.y: originalImage.height/2
|
||||
}
|
||||
]
|
||||
|
||||
// mirror image
|
||||
Image {
|
||||
width: originalImage.width; height: originalImage.height
|
||||
source: originalImage.source
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
// mirror image dimming gradient filled rectangle
|
||||
Rectangle {
|
||||
width: originalImage.width+4; height: originalImage.height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
gradient: Gradient {
|
||||
// TODO: no clue how to get the RGB component of the container rectangle color
|
||||
GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.4) }
|
||||
GradientStop { position: 0.3; color: reflectionContainer.color }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
|
||||
text: label
|
||||
smooth: true
|
||||
color: "white"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: view.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PathView {
|
||||
id: view
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
height: 300
|
||||
preferredHighlightBegin: 0.5
|
||||
preferredHighlightEnd: 0.5
|
||||
focus: true
|
||||
model: albumsModel
|
||||
delegate: pathDelegate
|
||||
pathItemCount: 8
|
||||
path: Path {
|
||||
startX: 10
|
||||
startY: 50
|
||||
PathAttribute { name: "iconScale"; value: 0.5 }
|
||||
PathQuad { x: view.width/2; y: 150; controlX: 50; controlY: 200 }
|
||||
PathAttribute { name: "iconScale"; value: 1.0 }
|
||||
PathQuad { x: view.width; y: 50; controlX: view.width; controlY: 200 }
|
||||
PathAttribute { name: "iconScale"; value: 0.5 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: gridDelegate
|
||||
Item {
|
||||
width: 100; height: 100
|
||||
scale: PathView.iconScale
|
||||
|
||||
// TODO: Use Image provider here
|
||||
Image {
|
||||
id: originalImage
|
||||
width: 80
|
||||
height: 80
|
||||
source: index % 2 === 0 ? "http://www.muktware.com/sites/default/files/images/applications/tomahawk_icon.png" : "http://cloud.ohloh.net/attachments/53867/tomahawk-icon-64x64_med.png"
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
|
||||
text: label
|
||||
smooth: true
|
||||
color: "white"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: view.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GridView {
|
||||
id: grid
|
||||
anchors { left: parent.left; top: view.bottom; right: parent.right; bottom: parent.bottom }
|
||||
|
||||
model: albumsModel
|
||||
|
||||
delegate: gridDelegate
|
||||
}
|
||||
|
||||
}
|
155
data/qml/CoverImage.qml
Normal file
@@ -0,0 +1,155 @@
|
||||
import QtQuick 1.1
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Should the artist + track labels be painted
|
||||
property bool showLabels: true
|
||||
// Should the play button be painted on mouse hover?
|
||||
property bool showPlayButton: false
|
||||
// Should the mirror be painted?
|
||||
property bool showMirror: false
|
||||
|
||||
// Labels & Cover
|
||||
property string artistName
|
||||
property string trackName
|
||||
property string artworkId
|
||||
|
||||
onArtworkIdChanged: print("!*!*!*!*!* artworkId", artworkId)
|
||||
|
||||
// The border color for the cover image
|
||||
property color borderColor: "black"
|
||||
// The border width for the cover image
|
||||
property int borderWidth: 2
|
||||
|
||||
// needed to adjust the shadow
|
||||
property color backgroundColor: "black"
|
||||
|
||||
// sets the brightness for the item and its mirror (1: brightest, 0: darkest)
|
||||
property double itemBrightness: 1
|
||||
property double mirrorBrightness: .5
|
||||
|
||||
// will be emitted when the on hower play button is clicked
|
||||
signal playClicked()
|
||||
// will be emitted when the cover is clicked
|
||||
signal clicked()
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: root.clicked();
|
||||
|
||||
}
|
||||
|
||||
Component {
|
||||
id: coverImage
|
||||
|
||||
Rectangle {
|
||||
color: "white"
|
||||
border.color: borderColor
|
||||
border.width: borderWidth
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
//anchors.margins: borderWidth
|
||||
source: "image://albumart/" + artworkId
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: textBackground
|
||||
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
|
||||
height: 32
|
||||
anchors.margins: 5
|
||||
color: "black"
|
||||
opacity: showLabels ? 0.5 : 0
|
||||
radius: 3
|
||||
}
|
||||
|
||||
Text {
|
||||
color: "white"
|
||||
font.bold: true
|
||||
text: trackName
|
||||
anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top }
|
||||
anchors.margins: 2
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
opacity: showLabels ? 1 : 0
|
||||
}
|
||||
Text {
|
||||
color: "white"
|
||||
text: artistName
|
||||
anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom }
|
||||
anchors.margins: 2
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
opacity: showLabels ? 1 : 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loader {
|
||||
sourceComponent: coverImage
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: mirroredCover
|
||||
sourceComponent: parent.showMirror ? coverImage : undefined
|
||||
anchors.fill: parent
|
||||
transform : [
|
||||
Rotation {
|
||||
angle: 180; origin.y: root.height
|
||||
axis.x: 1; axis.y: 0; axis.z: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: itemShadow
|
||||
color: backgroundColor
|
||||
anchors.fill: parent
|
||||
anchors.bottomMargin: - parent.height
|
||||
|
||||
// scaling might be off a pixel... make sure that the shadow is at least as large as the image
|
||||
anchors.leftMargin: -2
|
||||
anchors.rightMargin: -2
|
||||
anchors.topMargin: -2
|
||||
|
||||
opacity: 1 - itemBrightness + (mouseArea.containsMouse ? .2 : 0)
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { easing.type: Easing.Linear; duration: 300 }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mirrorShadow
|
||||
color: parent.backgroundColor
|
||||
height: parent.height + 2
|
||||
width: parent.width + 4
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: parent.height
|
||||
|
||||
gradient: Gradient {
|
||||
// TODO: no clue how to get the RGB component of the container rectangle color
|
||||
// For now the Qt.rgba needs to be manually updated to match the backgroundColor
|
||||
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, 1-mirrorBrightness) }
|
||||
GradientStop { position: 0.5; color: backgroundColor }
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: playButton
|
||||
visible: showPlayButton ? mouseArea.containsMouse : false
|
||||
source: "../images/play-rest.png"
|
||||
anchors.centerIn: parent
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.playClicked();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
79
data/qml/StationConfig.qml
Normal file
@@ -0,0 +1,79 @@
|
||||
import QtQuick 1.1
|
||||
import tomahawk 1.0
|
||||
import "tomahawkimports"
|
||||
|
||||
Item {
|
||||
id: fineTuneView
|
||||
|
||||
property color textColor: "white"
|
||||
|
||||
signal done();
|
||||
|
||||
Grid {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: scene.width / 2
|
||||
spacing: 50
|
||||
columns: 2
|
||||
|
||||
Text {
|
||||
color: fineTuneView.textColor
|
||||
text: "Name:"
|
||||
|
||||
}
|
||||
InputField {
|
||||
text: echonestStation.name
|
||||
|
||||
onAccepted: {
|
||||
print("text changed!!!")
|
||||
echonestStation.name = text;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: tempoText
|
||||
text: "Tempo:"
|
||||
color: "white"
|
||||
}
|
||||
DoubleSlider {
|
||||
width: 500
|
||||
height: tempoText.height
|
||||
min: 0
|
||||
max: 500
|
||||
lowerSliderPos: echonestStation.minTempo
|
||||
upperSliderPos: echonestStation.maxTempo
|
||||
onValueChanged: echonestStation.setTempo( lowerSliderPos, upperSliderPos )
|
||||
}
|
||||
|
||||
Text {
|
||||
id: hotnessText
|
||||
text: "Hotness:"
|
||||
color: "white"
|
||||
}
|
||||
DoubleSlider {
|
||||
width: 500
|
||||
height: hotnessText.height
|
||||
min: 0
|
||||
max: 100
|
||||
minLabel: "Less"
|
||||
maxLabel: "More"
|
||||
showFloatingLabel: false
|
||||
lowerSliderPos: echonestStation.minHotttness * 100
|
||||
upperSliderPos: echonestStation.maxHotttness * 100
|
||||
onValueChanged: echonestStation.setHotttness( 1.0 * lowerSliderPos / 100, 1.0 * upperSliderPos / 100 )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button {
|
||||
id: configureButton
|
||||
onClicked: fineTuneView.done();
|
||||
text: "configure"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
}
|
158
data/qml/StationScene.qml
Normal file
@@ -0,0 +1,158 @@
|
||||
import QtQuick 1.1
|
||||
import tomahawk 1.0
|
||||
import "tomahawkimports"
|
||||
|
||||
Rectangle {
|
||||
id: scene
|
||||
color: "black"
|
||||
anchors.fill: parent
|
||||
state: echonestStation.configured ? "list" : "configure"
|
||||
|
||||
ListModel {
|
||||
id: styleModel
|
||||
ListElement { modelData: "acoustic" }
|
||||
ListElement { modelData: "alternative" }
|
||||
ListElement { modelData: "alternative rock" }
|
||||
ListElement { modelData: "classic" }
|
||||
ListElement { modelData: "folk" }
|
||||
ListElement { modelData: "indie" }
|
||||
ListElement { modelData: "pop" }
|
||||
ListElement { modelData: "rock" }
|
||||
ListElement { modelData: "hip-hop" }
|
||||
ListElement { modelData: "punk" }
|
||||
ListElement { modelData: "grunge" }
|
||||
ListElement { modelData: "indie" }
|
||||
ListElement { modelData: "electronic" }
|
||||
ListElement { modelData: "country" }
|
||||
ListElement { modelData: "jazz" }
|
||||
ListElement { modelData: "psychodelic" }
|
||||
ListElement { modelData: "soundtrack" }
|
||||
ListElement { modelData: "reggae" }
|
||||
ListElement { modelData: "house" }
|
||||
ListElement { modelData: "drum and base" }
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: dummyArtistModel
|
||||
ListElement { modelData: "Pink Floyd" }
|
||||
ListElement { modelData: "Tool" }
|
||||
ListElement { modelData: "Cake" }
|
||||
ListElement { modelData: "Metallica" }
|
||||
ListElement { modelData: "Red Hot Chili Peppers" }
|
||||
ListElement { modelData: "Korn" }
|
||||
ListElement { modelData: "Prodigy" }
|
||||
ListElement { modelData: "Otto Waalkes" }
|
||||
}
|
||||
|
||||
VisualItemModel {
|
||||
id: stationVisualModel
|
||||
|
||||
|
||||
Column {
|
||||
height: scene.height
|
||||
width: scene.width
|
||||
|
||||
Row {
|
||||
height: scene.height / 2
|
||||
width: scene.width
|
||||
spacing: width * .1
|
||||
|
||||
Item {
|
||||
height: parent.height
|
||||
width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3
|
||||
GridView {
|
||||
id: gridView
|
||||
anchors.fill: parent
|
||||
anchors.margins: cellWidth / 2
|
||||
model: dummyArtistModel
|
||||
|
||||
cellWidth: gridView.width / 4 - 1 // -1 to make sure there is space for 4 items even with rounding error
|
||||
cellHeight: cellWidth
|
||||
|
||||
delegate: Item {
|
||||
height: gridView.cellHeight * .9
|
||||
width: height
|
||||
|
||||
CoverImage {
|
||||
artistName: modelData
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
echonestStation.setMainControl( EchonestStation.StationTypeArtist, modelData );
|
||||
stationListView.incrementCurrentIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
height: scene.height / 2
|
||||
width: scene.width * .9
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: width * .1
|
||||
|
||||
TagCloud {
|
||||
height: parent.height
|
||||
width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3
|
||||
model: styleModel//generator.styles()
|
||||
opacity: echonestStation.configured ? 0 : 1
|
||||
|
||||
onTagClicked: {
|
||||
echonestStation.setMainControl( EchonestStation.StationTypeStyle, item );
|
||||
stationListView.incrementCurrentIndex();
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 300 }
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: orText
|
||||
text: "or"
|
||||
color: "white"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
InputField {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: (parent.width - orText.width - parent.spacing * 2 ) * 1 / 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StationView {
|
||||
coverSize: Math.min(scene.height, scene.width) / 2
|
||||
height: scene.height
|
||||
width: scene.width
|
||||
|
||||
onConfigure: stationListView.incrementCurrentIndex();
|
||||
}
|
||||
|
||||
|
||||
StationConfig {
|
||||
height: scene.height
|
||||
width: scene.width
|
||||
|
||||
onDone: stationListView.decrementCurrentIndex();
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: stationListView
|
||||
anchors.fill: parent
|
||||
contentHeight: scene.height
|
||||
contentWidth: scene.width
|
||||
orientation: ListView.Horizontal
|
||||
model: stationVisualModel
|
||||
interactive: false
|
||||
highlightMoveDuration: 400
|
||||
|
||||
Component.onCompleted: {
|
||||
if ( echonestStation.configured ) {
|
||||
currentIndex = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
188
data/qml/StationView.qml
Normal file
@@ -0,0 +1,188 @@
|
||||
import QtQuick 1.1
|
||||
import tomahawk 1.0
|
||||
import "tomahawkimports"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property int coverSize
|
||||
|
||||
signal configure()
|
||||
|
||||
PathView {
|
||||
id: coverView
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: parent.width / 3
|
||||
|
||||
preferredHighlightBegin: 0.2 // scene.width / 11000
|
||||
preferredHighlightEnd: preferredHighlightBegin
|
||||
pathItemCount: 5
|
||||
//highlightMoveDuration: 500
|
||||
|
||||
model: dynamicModel
|
||||
currentIndex: currentlyPlayedIndex
|
||||
|
||||
property int pathStartX: width / 2
|
||||
property int pathStartY: height / 2
|
||||
|
||||
delegate: CoverImage {
|
||||
height: root.coverSize
|
||||
width: root.coverSize
|
||||
|
||||
showLabels: false
|
||||
showMirror: true
|
||||
//artistName: model.artistName
|
||||
//trackName: model.trackName
|
||||
artworkId: model.coverID
|
||||
|
||||
scale: PathView.itemScale
|
||||
itemBrightness: PathView.itemBrightness
|
||||
opacity: PathView.itemOpacity
|
||||
z: x
|
||||
|
||||
onClicked: {
|
||||
if ( currentlyPlayedIndex !==-1 ) {
|
||||
echonestStation.playItem( index )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path: Path {
|
||||
startX: coverView.pathStartX
|
||||
startY: coverView.pathStartY
|
||||
|
||||
PathAttribute { name: "itemOpacity"; value: 0 }
|
||||
PathAttribute { name: "itemBrightness"; value: 0 }
|
||||
PathAttribute { name: "itemScale"; value: 1.5 }
|
||||
PathLine { x: coverView.pathStartX * 0.9 ; y: coverView.pathStartY * 0.9 }
|
||||
PathPercent { value: .2 }
|
||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||
PathAttribute { name: "itemBrightness"; value: 1 }
|
||||
PathAttribute { name: "itemScale"; value: 1 }
|
||||
PathLine { x: coverView.pathStartX * .5; y: coverView.pathStartY * .5}
|
||||
PathPercent { value: .3 }
|
||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||
PathAttribute { name: "itemBrightness"; value: 1 }
|
||||
PathAttribute { name: "itemScale"; value: 0.5 }
|
||||
// PathLine { x: coverView.pathStartX * .25 ; y: coverView.pathStartY * .25 }
|
||||
// PathPercent { value: .75 }
|
||||
// PathAttribute { name: "itemOpacity"; value: 1 }
|
||||
// PathAttribute { name: "itemBrightness"; value: .5 }
|
||||
// PathAttribute { name: "itemScale"; value: 0.4 }
|
||||
PathLine { x: 0; y: 0 }
|
||||
PathPercent { value: 1 }
|
||||
PathAttribute { name: "itemOpacity"; value: 1 }
|
||||
PathAttribute { name: "itemBrightness"; value: 0 }
|
||||
PathAttribute { name: "itemScale"; value: 0.1 }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
|
||||
anchors.margins: 50
|
||||
width: scene.width / 3
|
||||
|
||||
Column {
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: 12
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: "Station:"
|
||||
}
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: 14
|
||||
font.bold: true
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: echonestStation.name
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: scene.width / 3
|
||||
|
||||
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: 12
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: "Now Playing:"
|
||||
visible: currentlyPlayedIndex !== -1
|
||||
}
|
||||
Rectangle {
|
||||
height: image.height + image.height / 5
|
||||
width: image.width + startPlayingText.width * 1.2
|
||||
radius: height / 2
|
||||
border.width: 2
|
||||
border.color: "white"
|
||||
color: startPlayingMouseArea.containsMouse ? "blue" : "gray"
|
||||
visible: currentlyPlayedIndex === -1
|
||||
Image {
|
||||
id: image
|
||||
source: "../images/play-rest.png"
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
id: startPlayingText
|
||||
color: "white"
|
||||
font.pointSize: 20
|
||||
anchors.left: image.right
|
||||
anchors.margins: height / 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
//width: parent.width - 30 - image.width
|
||||
elide: Text.ElideRight
|
||||
text: "Start playing"
|
||||
}
|
||||
MouseArea {
|
||||
id: startPlayingMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: echonestStation.playItem( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: 16
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).name : ""
|
||||
}
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: 14
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).artistName : ""
|
||||
}
|
||||
Text {
|
||||
color: "white"
|
||||
font.pointSize: 14
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).albumName : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: configureButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "configure"
|
||||
onClicked: root.configure();
|
||||
}
|
||||
|
||||
}
|
||||
|
53
data/qml/TagCloud.qml
Normal file
@@ -0,0 +1,53 @@
|
||||
import QtQuick 1.1
|
||||
import tomahawk 1.0
|
||||
|
||||
Item {
|
||||
id: tagCloud
|
||||
|
||||
property variant model: 10
|
||||
|
||||
signal tagClicked( string item )
|
||||
|
||||
function randomNumber(min, max) {
|
||||
var date = new Date();
|
||||
return (max - min) * Math.random(date.getSeconds()) + min
|
||||
}
|
||||
|
||||
Flow {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
spacing: 3
|
||||
|
||||
Repeater {
|
||||
id: cloudRepeater
|
||||
model: tagCloud.model
|
||||
|
||||
delegate: Item {
|
||||
id: cloudItem
|
||||
width: delegateText.width * 1.1
|
||||
height: delegateText.height
|
||||
property double itemScale: Math.random() + .3
|
||||
scale: itemScale
|
||||
Text {
|
||||
id: delegateText
|
||||
color: "white"
|
||||
//text: controlModel.controlAt( index ).summary
|
||||
text: modelData
|
||||
font.pointSize: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: tagCloud.randomNumber(0, 15)
|
||||
}
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
onClicked: tagCloud.tagClicked( modelData )
|
||||
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { easing: Easing.Linear; duration: 1000 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
data/qml/tomahawkimports/Button.qml
Normal file
@@ -0,0 +1,29 @@
|
||||
import QtQuick 1.1
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: buttonMouseArea.containsMouse ? "blue" : "gray"
|
||||
border.width: 2
|
||||
border.color: "white"
|
||||
radius: height/2
|
||||
height: buttonText.height * 1.2
|
||||
width: buttonText.width * 1.5
|
||||
|
||||
property alias text: buttonText.text
|
||||
property color textColor: "white"
|
||||
|
||||
signal clicked()
|
||||
|
||||
Text {
|
||||
id: buttonText
|
||||
anchors.centerIn: parent
|
||||
color: root.textColor
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: buttonMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: root.clicked();
|
||||
}
|
||||
}
|
151
data/qml/tomahawkimports/DoubleSlider.qml
Normal file
@@ -0,0 +1,151 @@
|
||||
import QtQuick 1.1
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 500
|
||||
height: 10
|
||||
|
||||
property int min: 0
|
||||
property int max: 100
|
||||
|
||||
/** The labels next to the slider
|
||||
* if empty, min and max values are used
|
||||
*/
|
||||
property string minLabel: ""
|
||||
property string maxLabel: ""
|
||||
|
||||
/** Should the floating label indicating the current position be shown? */
|
||||
property bool showFloatingLabel: true
|
||||
|
||||
property int lowerSliderPos: 25
|
||||
property int upperSliderPos: 75
|
||||
|
||||
signal valueChanged()
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Text {
|
||||
id: minText
|
||||
text: root.minLabel.length > 0 ? root.minLabel : min
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Item {
|
||||
id: sliderRect
|
||||
height: root.height
|
||||
width: parent.width - minText.width - maxText.width - parent.spacing * 2
|
||||
|
||||
function sliderPosToValue( sliderPos ) {
|
||||
var percent = sliderPos * 100 / (sliderRect.width - lowerSlider.width);
|
||||
return Math.floor(percent * (root.max - root.min) / 100) + root.min
|
||||
}
|
||||
|
||||
function valueToSloderPos( value ) {
|
||||
var percent = (value - root.min) * 100 / (root.max - root.min)
|
||||
return percent * (sliderRect.width - lowerSlider.width) / 100
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: sliderBase
|
||||
height: root.height / 5
|
||||
width: parent.width
|
||||
color: "white"
|
||||
radius: height / 2
|
||||
anchors.centerIn: parent
|
||||
|
||||
}
|
||||
Rectangle {
|
||||
id: lowerSlider
|
||||
height: root.height
|
||||
width: height
|
||||
anchors.top: root.top
|
||||
radius: height/2
|
||||
border.color: "black"
|
||||
border.width: 2
|
||||
x: sliderRect.valueToSloderPos(root.lowerSliderPos)
|
||||
|
||||
Rectangle {
|
||||
id: lowerFloatingRect
|
||||
color: "white"
|
||||
anchors.bottom: lowerSlider.top
|
||||
anchors.bottomMargin: 10
|
||||
visible: root.showFloatingLabel && lowerSliderMouseArea.pressed
|
||||
width: lowerFloatingText.width * 1.2
|
||||
height: lowerFloatingText.height + height * 1.2
|
||||
x: -(width - lowerSlider.width) / 2
|
||||
radius: height / 4
|
||||
|
||||
Text {
|
||||
id: lowerFloatingText
|
||||
anchors.centerIn: parent
|
||||
text: sliderRect.sliderPosToValue(lowerSlider.x)
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: lowerSliderMouseArea
|
||||
anchors.fill: lowerSlider
|
||||
drag.target: lowerSlider
|
||||
drag.axis: "XAxis"
|
||||
drag.minimumX: 0
|
||||
drag.maximumX: upperSlider.x - lowerSlider.width
|
||||
onReleased: {
|
||||
root.lowerSliderPos = sliderRect.sliderPosToValue( lowerSlider.x );
|
||||
root.valueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: upperSlider
|
||||
height: root.height
|
||||
width: height
|
||||
anchors.top: root.top
|
||||
radius: height/2
|
||||
border.color: "black"
|
||||
border.width: 2
|
||||
x: sliderRect.valueToSloderPos(root.upperSliderPos)
|
||||
Rectangle {
|
||||
id: upperFloatingRect
|
||||
color: "white"
|
||||
anchors.bottom: upperSlider.top
|
||||
anchors.bottomMargin: 10
|
||||
visible: root.showFloatingLabel && upperSliderMouseArea.pressed
|
||||
width: upperFloatingText.width * 1.2
|
||||
height: upperFloatingText.height + height * 1.2
|
||||
radius: height / 4
|
||||
x: -(width - upperSlider.width) / 2
|
||||
|
||||
Text {
|
||||
id: upperFloatingText
|
||||
anchors.centerIn: parent
|
||||
text: sliderRect.sliderPosToValue(upperSlider.x)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MouseArea {
|
||||
id: upperSliderMouseArea
|
||||
anchors.fill: upperSlider
|
||||
onClicked: print("button pressed")
|
||||
drag.target: upperSlider
|
||||
drag.axis: "XAxis"
|
||||
drag.minimumX: lowerSlider.x + lowerSlider.width
|
||||
drag.maximumX: parent.width - upperSlider.width
|
||||
onReleased: {
|
||||
root.upperSliderPos = sliderRect.sliderPosToValue( upperSlider.x );
|
||||
root.valueChanged();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Text {
|
||||
id: maxText
|
||||
text: root.maxLabel.length > 0 ? root.maxLabel : max
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
23
data/qml/tomahawkimports/InputField.qml
Normal file
@@ -0,0 +1,23 @@
|
||||
import QtQuick 1.1
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "white"
|
||||
border.color: "black"
|
||||
border.width: 2
|
||||
|
||||
height: textInput.height + 4
|
||||
width: 300
|
||||
|
||||
property alias text: textInput.text
|
||||
|
||||
signal accepted( string text )
|
||||
|
||||
TextInput {
|
||||
id: textInput
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
|
||||
onAccepted: root.accepted( text );
|
||||
}
|
||||
}
|
@@ -10,7 +10,7 @@ QRadioButton {
|
||||
padding:0;
|
||||
background-repeat: none;
|
||||
/*width:0; height:0;*/
|
||||
}
|
||||
}
|
||||
|
||||
QRadioButton::indicator {
|
||||
width: 29px;
|
||||
@@ -18,15 +18,15 @@ QRadioButton::indicator {
|
||||
}
|
||||
|
||||
QRadioButton::indicator::unchecked {
|
||||
background-image: url(:/data/images/view-toggle-inactive-right.png);
|
||||
background-image: url(:/data/images/view-toggle-inactive-centre.png);
|
||||
image: url(:/data/images/view-toggle-icon-list-inactive.png);
|
||||
}
|
||||
QRadioButton::indicator::checked {
|
||||
background-image: url(:/data/images/view-toggle-active-right.png);
|
||||
background-image: url(:/data/images/view-toggle-active-centre.png);
|
||||
image: url(:/data/images/view-toggle-icon-list-active.png);
|
||||
}
|
||||
QRadioButton::indicator::pressed {
|
||||
background-image: url(:/data/images/view-toggle-pressed-right.png);
|
||||
background-image: url(:/data/images/view-toggle-pressed-centre.png);
|
||||
image: url(:/data/images/view-toggle-icon-list-active.png);
|
||||
}
|
||||
QRadioButton#radioNormal::indicator::unchecked {
|
||||
@@ -43,13 +43,13 @@ QRadioButton#radioNormal::indicator::pressed {
|
||||
}
|
||||
QRadioButton#radioCloud::indicator::unchecked {
|
||||
background-image: url(:/data/images/view-toggle-inactive-right.png);
|
||||
image: url(:/data/images/view-toggle-icon-cloud-inactive.png);
|
||||
image: url(:/data/images/view-toggle-icon-grid-inactive.png);
|
||||
}
|
||||
QRadioButton#radioCloud::indicator::checked {
|
||||
background-image: url(:/data/images/view-toggle-active-right.png);
|
||||
image: url(:/data/images/view-toggle-icon-cloud-active.png);
|
||||
image: url(:/data/images/view-toggle-icon-grid-active.png);
|
||||
}
|
||||
QRadioButton#radioCloud::indicator::pressed {
|
||||
background-image: url(:/data/images/view-toggle-pressed-right.png);
|
||||
image: url(:/data/images/view-toggle-icon-cloud-active.png);
|
||||
image: url(:/data/images/view-toggle-icon-grid-active.png);
|
||||
}
|
||||
|
4096
lang/tomahawk_lt.ts
Normal file
@@ -45,6 +45,8 @@
|
||||
<file>data/images/view-toggle-icon-artist-inactive.png</file>
|
||||
<file>data/images/view-toggle-icon-cloud-active.png</file>
|
||||
<file>data/images/view-toggle-icon-cloud-inactive.png</file>
|
||||
<file>data/images/view-toggle-icon-grid-active.png</file>
|
||||
<file>data/images/view-toggle-icon-grid-inactive.png</file>
|
||||
<file>data/images/view-toggle-icon-list-active.png</file>
|
||||
<file>data/images/view-toggle-icon-list-inactive.png</file>
|
||||
<file>data/images/view-toggle-inactive-centre.png</file>
|
||||
@@ -146,5 +148,16 @@
|
||||
<file>data/images/jump-link.png</file>
|
||||
<file>data/images/scrollbar-vertical-handle.png</file>
|
||||
<file>data/images/scrollbar-horizontal-handle.png</file>
|
||||
<file>data/images/subscribe-on.png</file>
|
||||
<file>data/images/subscribe-off.png</file>
|
||||
<file>data/qml/ArtistInfoScene.qml</file>
|
||||
<file>data/qml/StationScene.qml</file>
|
||||
<file>data/qml/CoverImage.qml</file>
|
||||
<file>data/qml/TagCloud.qml</file>
|
||||
<file>data/qml/StationConfig.qml</file>
|
||||
<file>data/qml/StationView.qml</file>
|
||||
<file>data/qml/tomahawkimports/InputField.qml</file>
|
||||
<file>data/qml/tomahawkimports/Button.qml</file>
|
||||
<file>data/qml/tomahawkimports/DoubleSlider.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
273
src/AclRegistryImpl.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AclRegistryImpl.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include "TomahawkSettings.h"
|
||||
#include "TomahawkApp.h"
|
||||
#include "Source.h"
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "accounts/Account.h"
|
||||
#include "jobview/AclJobItem.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#endif
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
|
||||
ACLRegistryImpl::ACLRegistryImpl( QObject* parent )
|
||||
: ACLRegistry( parent )
|
||||
, m_jobCount( 0 )
|
||||
{
|
||||
ACLRegistry::setInstance( this );
|
||||
load();
|
||||
}
|
||||
|
||||
|
||||
ACLRegistryImpl::~ACLRegistryImpl()
|
||||
{
|
||||
save();
|
||||
}
|
||||
|
||||
|
||||
ACLRegistry::ACL
|
||||
ACLRegistryImpl::isAuthorizedUser( const QString& dbid, const QString &username, ACLRegistry::ACL globalType, bool skipEmission )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
{
|
||||
if ( !skipEmission )
|
||||
QMetaObject::invokeMethod( this, "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( const QString&, dbid ), Q_ARG( const QString &, username ), Q_ARG( ACLRegistry::ACL, globalType ), Q_ARG( bool, skipEmission ) );
|
||||
return ACLRegistry::NotFound;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
if ( Tomahawk::Accounts::AccountManager::instance() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking account friendly names against" << username;
|
||||
Tomahawk::Accounts::AccountManager* accountManager = Tomahawk::Accounts::AccountManager::instance();
|
||||
QList< Tomahawk::Accounts::Account* > accounts = accountManager->accounts();
|
||||
foreach( Tomahawk::Accounts::Account* account, accounts )
|
||||
{
|
||||
if ( !( account->types() & Tomahawk::Accounts::SipType ) )
|
||||
continue;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking against account friendly name" << account->accountFriendlyName();
|
||||
if ( account->accountFriendlyName() == username )
|
||||
{
|
||||
if ( !skipEmission )
|
||||
emit aclResult( dbid, username, ACLRegistry::Stream );
|
||||
return ACLRegistry::Stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool found = false;
|
||||
QMutableListIterator< ACLRegistry::User > i( m_cache );
|
||||
while ( i.hasNext() )
|
||||
{
|
||||
ACLRegistry::User user = i.next();
|
||||
foreach ( QString knowndbid, user.knownDbids )
|
||||
{
|
||||
if ( dbid == knowndbid )
|
||||
{
|
||||
if ( !user.knownAccountIds.contains( username ) )
|
||||
user.knownAccountIds.append( username );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( QString knownaccountid, user.knownAccountIds )
|
||||
{
|
||||
if ( username == knownaccountid )
|
||||
{
|
||||
if ( !user.knownDbids.contains( dbid ) )
|
||||
user.knownDbids.append( dbid );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found )
|
||||
{
|
||||
if ( !skipEmission )
|
||||
emit aclResult( dbid, username, user.acl );
|
||||
i.setValue( user );
|
||||
return user.acl;
|
||||
}
|
||||
}
|
||||
|
||||
if ( skipEmission )
|
||||
return ACLRegistry::NotFound;
|
||||
|
||||
// User was not found, create a new user entry
|
||||
ACLRegistry::User user;
|
||||
user.knownDbids.append( dbid );
|
||||
user.knownAccountIds.append( username );
|
||||
if ( globalType != ACLRegistry::NotFound )
|
||||
user.acl = globalType;
|
||||
#ifdef ENABLE_HEADLESS
|
||||
user.acl = ACLRegistry::Stream;
|
||||
#else
|
||||
if ( !TomahawkUtils::headless() )
|
||||
{
|
||||
getUserDecision( user, username );
|
||||
return ACLRegistry::NotFound;
|
||||
}
|
||||
else
|
||||
user.acl = ACLRegistry::Stream;
|
||||
#endif
|
||||
m_cache.append( user );
|
||||
save();
|
||||
emit aclResult( dbid, username, user.acl );
|
||||
return user.acl;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
void
|
||||
ACLRegistryImpl::getUserDecision( ACLRegistry::User user, const QString &username )
|
||||
{
|
||||
if ( TomahawkUtils::headless() )
|
||||
return;
|
||||
|
||||
tLog() << Q_FUNC_INFO;
|
||||
ACLJobItem* job = new ACLJobItem( user, username );
|
||||
m_jobQueue.enqueue( job );
|
||||
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistryImpl::userDecision( ACLRegistry::User user )
|
||||
{
|
||||
if ( TomahawkUtils::headless() )
|
||||
return;
|
||||
|
||||
tLog() << Q_FUNC_INFO;
|
||||
m_cache.append( user );
|
||||
save();
|
||||
emit aclResult( user.knownDbids.first(), user.knownAccountIds.first(), user.acl );
|
||||
|
||||
m_jobCount--;
|
||||
if ( !m_jobQueue.isEmpty() )
|
||||
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistryImpl::queueNextJob()
|
||||
{
|
||||
if ( TomahawkUtils::headless() )
|
||||
return;
|
||||
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "queueNextJob", Qt::QueuedConnection );
|
||||
return;
|
||||
}
|
||||
tLog() << Q_FUNC_INFO << "jobCount =" << m_jobCount;
|
||||
tLog() << Q_FUNC_INFO << "jobQueue size =" << m_jobQueue.length();
|
||||
if ( m_jobCount != 0 )
|
||||
return;
|
||||
|
||||
if ( !m_jobQueue.isEmpty() )
|
||||
{
|
||||
ACLJobItem* job = m_jobQueue.dequeue();
|
||||
ACLRegistry::User user = job->user();
|
||||
bool found = false;
|
||||
foreach( QString dbid, user.knownDbids )
|
||||
{
|
||||
ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true );
|
||||
if ( acl != ACLRegistry::NotFound )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Found existing acl entry for =" << user.knownAccountIds.first();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( found )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "deleting job, already have ACL for" << user.knownAccountIds.first();
|
||||
delete job;
|
||||
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "activating job for user" << user.knownAccountIds.first();
|
||||
m_jobCount++;
|
||||
JobStatusView::instance()->model()->addJob( job );
|
||||
connect( job, SIGNAL( userDecision( ACLRegistry::User ) ), this, SLOT( userDecision( ACLRegistry::User ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ACLRegistryImpl::wipeEntries()
|
||||
{
|
||||
ACLRegistry::wipeEntries();
|
||||
save();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistryImpl::load()
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
QVariantList entryList = TomahawkSettings::instance()->aclEntries();
|
||||
foreach ( QVariant entry, entryList )
|
||||
{
|
||||
if ( !entry.isValid() || !entry.canConvert< ACLRegistry::User >() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "entry is invalid";
|
||||
continue;
|
||||
}
|
||||
ACLRegistry::User entryUser = entry.value< ACLRegistry::User >();
|
||||
if ( entryUser.knownAccountIds.empty() || entryUser.knownDbids.empty() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "user known account/dbids is empty";
|
||||
continue;
|
||||
}
|
||||
m_cache.append( entryUser );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistryImpl::save()
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
QVariantList entryList;
|
||||
foreach ( ACLRegistry::User user, m_cache )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "user is" << user.uuid << "with known name" << user.knownAccountIds.first();
|
||||
QVariant val = QVariant::fromValue< ACLRegistry::User >( user );
|
||||
if ( val.isValid() )
|
||||
entryList.append( val );
|
||||
}
|
||||
TomahawkSettings::instance()->setAclEntries( entryList );
|
||||
}
|
80
src/AclRegistryImpl.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TOMAHAWK_ACLREGISTRYIMPL_H
|
||||
#define TOMAHAWK_ACLREGISTRYIMPL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
#include <QTimer>
|
||||
#include <QMutex>
|
||||
#include <QVariant>
|
||||
#include <QQueue>
|
||||
#include <QStringList>
|
||||
#include <QUuid>
|
||||
|
||||
#include "AclRegistry.h"
|
||||
#include "HeadlessCheck.h"
|
||||
#include "DllMacro.h"
|
||||
|
||||
class ACLJobItem;
|
||||
|
||||
class ACLRegistryImpl : public ACLRegistry
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ACLRegistryImpl( QObject *parent = 0 );
|
||||
virtual ~ACLRegistryImpl();
|
||||
|
||||
signals:
|
||||
void aclResult( QString nodeid, QString username, ACLRegistry::ACL peerStatus );
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Checks if peer is authorized; optionally, can authorize peer with given type if not found
|
||||
*
|
||||
* @param dbid DBID of peer
|
||||
* @param globalType Global ACL to store if peer not found; if ACLRegistry::NotFound, does not store the peer Defaults to ACLRegistry::NotFound.
|
||||
* @param username If not empty, will store the given username along with the new ACL value. Defaults to QString().
|
||||
* @return ACLRegistry::ACL
|
||||
**/
|
||||
virtual ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false );
|
||||
virtual void wipeEntries();
|
||||
|
||||
protected:
|
||||
virtual void load();
|
||||
virtual void save();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
void getUserDecision( ACLRegistry::User user, const QString &username );
|
||||
|
||||
private slots:
|
||||
void userDecision( ACLRegistry::User user );
|
||||
void queueNextJob();
|
||||
#endif
|
||||
|
||||
private:
|
||||
QQueue< ACLJobItem* > m_jobQueue;
|
||||
int m_jobCount;
|
||||
};
|
||||
|
||||
#endif // TOMAHAWK_ACLREGISTRYIMPL_H
|
@@ -37,6 +37,8 @@
|
||||
#include "ViewManager.h"
|
||||
#include "Source.h"
|
||||
|
||||
const static int ALLOWED_MAX_DIVERSION = 300;
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
@@ -205,22 +207,20 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
ui->seekSlider->setValue( 0 );
|
||||
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
|
||||
|
||||
m_phononTickCheckTimer.stop();
|
||||
|
||||
m_sliderTimeLine.stop();
|
||||
m_sliderTimeLine.setDuration( duration );
|
||||
m_sliderTimeLine.setFrameRange( 0, duration );
|
||||
m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
|
||||
m_sliderTimeLine.setCurrentTime( 0 );
|
||||
m_seekMsecs = -1;
|
||||
m_seeked = false;
|
||||
|
||||
ui->seekSlider->setVisible( true );
|
||||
|
||||
int updateRate = (double)1000 / ( (double)ui->seekSlider->contentsRect().width() / (double)( duration / 1000 ) );
|
||||
m_sliderTimeLine.setUpdateInterval( qBound( 40, updateRate, 500 ) );
|
||||
|
||||
m_noTimeChange = false;
|
||||
m_lastSliderCheck = 0;
|
||||
m_phononTickCheckTimer.start( 500 );
|
||||
}
|
||||
|
||||
|
||||
@@ -326,18 +326,15 @@ AudioControls::onPlaybackResumed()
|
||||
{
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
|
||||
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioControls::onPlaybackSeeked( qint64 msec )
|
||||
{
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << " setting current timer to " << msec;
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
m_sliderTimeLine.setCurrentTime( msec );
|
||||
m_lastSliderCheck = msec;
|
||||
m_seekMsecs = msec;
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
|
||||
m_seeked = true;
|
||||
onPlaybackTimer( msec );
|
||||
}
|
||||
|
||||
|
||||
@@ -356,7 +353,8 @@ AudioControls::onPlaybackStopped()
|
||||
ui->seekSlider->setVisible( false );
|
||||
m_sliderTimeLine.stop();
|
||||
m_sliderTimeLine.setCurrentTime( 0 );
|
||||
|
||||
m_phononTickCheckTimer.stop();
|
||||
|
||||
ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
|
||||
ui->loveButton->setEnabled( false );
|
||||
ui->loveButton->setVisible( false );
|
||||
@@ -368,65 +366,90 @@ AudioControls::onPlaybackStopped()
|
||||
void
|
||||
AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
{
|
||||
//tDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_phononTickCheckTimer.stop();
|
||||
|
||||
if ( m_currentTrack.isNull() )
|
||||
{
|
||||
m_sliderTimeLine.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
const int seconds = msElapsed / 1000;
|
||||
if ( seconds != m_lastTextSecondShown && !m_currentTrack.isNull() )
|
||||
if ( seconds != m_lastTextSecondShown )
|
||||
{
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
|
||||
m_lastTextSecondShown = seconds;
|
||||
}
|
||||
|
||||
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime() << "and m_seekMsecs =" << m_seekMsecs;
|
||||
if ( msElapsed > 0 && msElapsed != m_lastSliderCheck && m_seekMsecs == -1 && msElapsed - 500 < m_lastSliderCheck )
|
||||
m_phononTickCheckTimer.start( 500 );
|
||||
|
||||
if ( msElapsed == 0 )
|
||||
return;
|
||||
m_lastSliderCheck = msElapsed;
|
||||
|
||||
if ( m_currentTrack.isNull() )
|
||||
{
|
||||
m_sliderTimeLine.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
ui->seekSlider->blockSignals( true );
|
||||
|
||||
if ( sender() != &m_phononTickCheckTimer )
|
||||
m_phononTickCheckTimer.start( 1000 );
|
||||
|
||||
int currentTime = m_sliderTimeLine.currentTime();
|
||||
if ( m_noTimeChange )
|
||||
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime();
|
||||
|
||||
// First condition checks for the common case where
|
||||
// 1) the track has been started
|
||||
// 2) we haven't seeked,
|
||||
// 3) the timeline is pretty close to the actual time elapsed, within ALLOWED_MAX_DIVERSIONmsec, so no adustment needed, and
|
||||
// 4) The audio engine is actually currently running
|
||||
if ( msElapsed > 0
|
||||
&& !m_seeked
|
||||
&& qAbs( msElapsed - currentTime ) <= ALLOWED_MAX_DIVERSION
|
||||
&& AudioEngine::instance()->state() == AudioEngine::Playing )
|
||||
{
|
||||
if ( currentTime != msElapsed )
|
||||
if ( m_sliderTimeLine.state() != QTimeLine::Running )
|
||||
m_sliderTimeLine.resume();
|
||||
m_lastSliderCheck = msElapsed;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//tDebug() << Q_FUNC_INFO << "Fallthrough";
|
||||
// If we're in here we're offset, so we need to do some munging around
|
||||
ui->seekSlider->blockSignals( true );
|
||||
|
||||
// First handle seeks
|
||||
if ( m_seeked )
|
||||
{
|
||||
//tDebug() << Q_FUNC_INFO << "Seeked";
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
m_noTimeChange = false;
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
m_seekMsecs = -1;
|
||||
m_sliderTimeLine.resume();
|
||||
m_seeked = false;
|
||||
if ( AudioEngine::instance()->state() == AudioEngine::Playing )
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
// Next handle falling behind by too much, or getting ahead by too much (greater than allowed amount, which would have been sorted above)
|
||||
// However, a Phonon bug means that after a seek we'll actually have AudioEngine's state be Playing, when it ain't, so have to detect that
|
||||
else if ( AudioEngine::instance()->state() == AudioEngine::Playing )
|
||||
{
|
||||
//tDebug() << Q_FUNC_INFO << "AudioEngine playing";
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
if ( msElapsed != m_lastSliderCheck )
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
// Finally, the case where the audioengine isn't playing; if the timeline is still running, pause it and catch up
|
||||
else if ( AudioEngine::instance()->state() != AudioEngine::Playing )
|
||||
{
|
||||
//tDebug() << Q_FUNC_INFO << "AudioEngine not playing";
|
||||
if ( msElapsed != currentTime || m_sliderTimeLine.state() == QTimeLine::Running)
|
||||
{
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "What to do? How could we even get here?";
|
||||
}
|
||||
m_lastSliderCheck = msElapsed;
|
||||
ui->seekSlider->blockSignals( false );
|
||||
}
|
||||
else if ( currentTime >= msElapsed || m_seekMsecs != -1 )
|
||||
{
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
|
||||
m_noTimeChange = false;
|
||||
if ( currentTime == msElapsed )
|
||||
m_noTimeChange = true;
|
||||
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
m_seekMsecs = -1;
|
||||
if ( AudioEngine::instance()->state() != AudioEngine::Paused && sender() != &m_phononTickCheckTimer )
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
else if ( m_sliderTimeLine.duration() > msElapsed && m_sliderTimeLine.state() == QTimeLine::NotRunning && AudioEngine::instance()->state() == AudioEngine::Playing )
|
||||
{
|
||||
m_sliderTimeLine.start();
|
||||
}
|
||||
else if ( m_sliderTimeLine.state() == QTimeLine::Paused && AudioEngine::instance()->state() != AudioEngine::Paused )
|
||||
{
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
|
||||
ui->seekSlider->blockSignals( false );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -101,9 +101,8 @@ private:
|
||||
|
||||
QTimer m_phononTickCheckTimer;
|
||||
QTimeLine m_sliderTimeLine;
|
||||
qint64 m_seekMsecs;
|
||||
bool m_seeked;
|
||||
qint64 m_lastSliderCheck;
|
||||
bool m_noTimeChange;
|
||||
qint64 m_lastTextSecondShown;
|
||||
|
||||
QWidget* m_parent;
|
||||
|
@@ -37,9 +37,8 @@ ENDIF()
|
||||
SET( tomahawkSources ${tomahawkSources}
|
||||
web/Api_v1.cpp
|
||||
|
||||
MusicScanner.cpp
|
||||
AclRegistryImpl.cpp
|
||||
ShortcutHandler.cpp
|
||||
ScanManager.cpp
|
||||
UbuntuUnityHack.cpp
|
||||
TomahawkApp.cpp
|
||||
main.cpp
|
||||
@@ -62,6 +61,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
||||
sourcetree/items/PlaylistItems.cpp
|
||||
sourcetree/items/CategoryItems.cpp
|
||||
sourcetree/items/GenericPageItems.cpp
|
||||
sourcetree/items/LovedTracksItem.cpp
|
||||
sourcetree/items/TemporaryPageItem.cpp
|
||||
sourcetree/items/GroupItem.cpp
|
||||
sourcetree/items/HistoryItem.cpp
|
||||
@@ -70,7 +70,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
||||
AudioControls.cpp
|
||||
SettingsDialog.cpp
|
||||
DiagnosticsDialog.cpp
|
||||
SettingsListDelegate.cpp
|
||||
TomahawkWindow.cpp
|
||||
LoadXSPFDialog.cpp
|
||||
SocialWidget.cpp
|
||||
@@ -113,8 +112,7 @@ INCLUDE_DIRECTORIES(
|
||||
${PHONON_INCLUDES}
|
||||
${QJSON_INCLUDE_DIR}
|
||||
${LIBATTICA_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}/..
|
||||
${ECHONEST_INCLUDE_DIR}
|
||||
${LIBLASTFM_INCLUDE_DIRS}
|
||||
${LIBLASTFM_INCLUDE_DIRS}/..
|
||||
)
|
||||
@@ -200,7 +198,7 @@ TARGET_LINK_LIBRARIES( tomahawk
|
||||
${OS_SPECIFIC_LINK_LIBRARIES}
|
||||
${QT_LIBRARIES}
|
||||
${MAC_EXTRA_LIBS}
|
||||
${LIBECHONEST_LIBRARY}
|
||||
${ECHONEST_LIBRARIES}
|
||||
${QXTWEB_LIBRARIES}
|
||||
${QJSON_LIBRARIES}
|
||||
${TAGLIB_LIBRARIES}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2012, Teo Mrnjavac <teo@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,20 +29,18 @@
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QSizeGrip>
|
||||
#include <QtGui/QToolBar>
|
||||
|
||||
#include "AtticaManager.h"
|
||||
#include "AclRegistry.h"
|
||||
#include "TomahawkApp.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "accounts/DelegateConfigWrapper.h"
|
||||
#include "MusicScanner.h"
|
||||
#include "Pipeline.h"
|
||||
#include "Resolver.h"
|
||||
#include "ExternalResolverGui.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/GuiHelpers.h"
|
||||
#include "ScanManager.h"
|
||||
#include "SettingsListDelegate.h"
|
||||
#include "accounts/AccountDelegate.h"
|
||||
#include "database/Database.h"
|
||||
#include "network/Servent.h"
|
||||
@@ -74,11 +73,23 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
|
||||
TomahawkUtils::unmarginLayout( layout() );
|
||||
ui->stackedWidget->setContentsMargins( 4, 4, 4, 0 );
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
ui->stackedWidget->setContentsMargins( 4, 4, 4, 4 );
|
||||
#else
|
||||
ui->stackedWidget->setContentsMargins( 4, 4, 4, 0 );
|
||||
#endif
|
||||
ui->checkBoxReporter->setChecked( s->crashReporterEnabled() );
|
||||
ui->checkBoxHttp->setChecked( s->httpEnabled() );
|
||||
|
||||
QFrame *sepLine = new QFrame( this );
|
||||
sepLine->setFrameShape( QFrame::HLine );
|
||||
sepLine->setFrameShadow( QFrame::Sunken );
|
||||
ui->horizontalLayout->insertWidget( 0, sepLine );
|
||||
|
||||
m_toolBar = new QToolBar( tr( "Tomahawk Settings" ), this );
|
||||
ui->horizontalLayout->insertWidget( 0, m_toolBar );
|
||||
m_toolBar->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
|
||||
|
||||
//Network settings
|
||||
TomahawkSettings::ExternalAddressMode mode = TomahawkSettings::instance()->externalAddressMode();
|
||||
@@ -104,29 +115,16 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
|
||||
createIcons();
|
||||
#ifdef Q_WS_X11
|
||||
ui->listWidget->setFrameShape( QFrame::StyledPanel );
|
||||
ui->listWidget->setFrameShadow( QFrame::Sunken );
|
||||
setContentsMargins( 4, 4, 4, 4 );
|
||||
#else
|
||||
setContentsMargins( 0, 4, 4, 4 );
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
ui->listWidget->setFixedWidth( 83 );
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
// Avoid resize handles on sheets on osx
|
||||
m_proxySettings.setSizeGripEnabled( true );
|
||||
QSizeGrip* p = m_proxySettings.findChild< QSizeGrip* >();
|
||||
p->setFixedSize( 0, 0 );
|
||||
|
||||
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer );
|
||||
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer_2 );
|
||||
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer_4 );
|
||||
delete ui->verticalSpacer;
|
||||
delete ui->verticalSpacer_2;
|
||||
delete ui->verticalSpacer_4;
|
||||
#endif
|
||||
|
||||
// Accounts
|
||||
@@ -195,6 +193,13 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
{
|
||||
ui->dirTree->checkPath( dir, Qt::Checked );
|
||||
}
|
||||
ui->advancedPage->setMinimumSize( ui->advancedPage->sizeHint() );
|
||||
|
||||
int buttonsWidth = qMax( ui->proxyButton->sizeHint().width(),
|
||||
ui->aclEntryClearButton->sizeHint().width() );
|
||||
ui->proxyButton->setFixedWidth( buttonsWidth );
|
||||
ui->aclEntryClearButton->setFixedWidth( buttonsWidth );
|
||||
|
||||
|
||||
// NOW PLAYING
|
||||
// #ifdef Q_WS_MAC
|
||||
@@ -212,9 +217,6 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
connect( ui->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
|
||||
connect( ui->enableProxyCheckBox, SIGNAL( toggled(bool) ), SLOT( toggleProxyEnabled() ) );
|
||||
connect( this, SIGNAL( rejected() ), SLOT( onRejected() ) );
|
||||
|
||||
ui->listWidget->setCurrentRow( 0 );
|
||||
ui->listWidget->setItemDelegate(new SettingsListDelegate());
|
||||
}
|
||||
|
||||
|
||||
@@ -282,56 +284,67 @@ SettingsDialog::serventReady()
|
||||
void
|
||||
SettingsDialog::createIcons()
|
||||
{
|
||||
/// Not fun but QListWidget sucks. Do our max-width calculation manually
|
||||
/// so the icons arre lined up.
|
||||
// Resolvers is the longest string... in english. fml.
|
||||
|
||||
ensurePolished();
|
||||
|
||||
int maxlen = 0;
|
||||
QFontMetrics fm( font() );
|
||||
QListWidgetItem *accountsButton = new QListWidgetItem( ui->listWidget );
|
||||
accountsButton->setIcon( QIcon( RESPATH "images/account-settings.png" ) );
|
||||
accountsButton->setText( tr( "Services" ) );
|
||||
accountsButton->setTextAlignment( Qt::AlignHCenter );
|
||||
accountsButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
maxlen = fm.width( accountsButton->text() );
|
||||
m_settingsGroup = new QActionGroup( m_toolBar );
|
||||
|
||||
QListWidgetItem *musicButton = new QListWidgetItem( ui->listWidget );
|
||||
musicButton->setIcon( QIcon( RESPATH "images/music-settings.png" ) );
|
||||
musicButton->setText( tr( "Collection" ) );
|
||||
musicButton->setTextAlignment( Qt::AlignHCenter );
|
||||
musicButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
maxlen = qMax( fm.width( musicButton->text() ), maxlen );
|
||||
QWidget *leftSpacer = new QWidget( m_toolBar );
|
||||
leftSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
|
||||
m_toolBar->addWidget( leftSpacer );
|
||||
|
||||
QListWidgetItem *advancedButton = new QListWidgetItem( ui->listWidget );
|
||||
advancedButton->setIcon( QIcon( RESPATH "images/advanced-settings.png" ) );
|
||||
advancedButton->setText( tr( "Advanced" ) );
|
||||
advancedButton->setTextAlignment( Qt::AlignHCenter );
|
||||
advancedButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
maxlen = qMax( fm.width( advancedButton->text() ), maxlen );
|
||||
QAction *accountsAction = new QAction( QIcon( RESPATH "images/account-settings.png" ),
|
||||
tr( "Services" ),
|
||||
m_toolBar );
|
||||
accountsAction->setCheckable( true );
|
||||
accountsAction->setToolTip( tr( "<b>Services</b><br>"
|
||||
"Configure the accounts and services used by Tomahawk "
|
||||
"to search and retrieve music, find your friends and "
|
||||
"update your status." ) );
|
||||
m_settingsGroup->addAction( accountsAction );
|
||||
|
||||
maxlen += 15; // padding
|
||||
accountsButton->setSizeHint( QSize( maxlen, 60 ) );
|
||||
musicButton->setSizeHint( QSize( maxlen, 60 ) );
|
||||
advancedButton->setSizeHint( QSize( maxlen, 60 ) );
|
||||
QAction *musicAction = new QAction( QIcon( RESPATH "images/music-settings.png" ),
|
||||
tr( "Collection" ),
|
||||
m_toolBar );
|
||||
musicAction->setCheckable( true );
|
||||
musicAction->setToolTip( tr( "<b>Collection</b><br>"
|
||||
"Manage how Tomahawk finds music on your computer." ) );
|
||||
m_settingsGroup->addAction( musicAction );
|
||||
|
||||
#ifndef Q_WS_MAC
|
||||
// doesn't listen to sizehint...
|
||||
ui->listWidget->setFixedWidth( maxlen + 8 );
|
||||
#endif
|
||||
|
||||
connect( ui->listWidget, SIGNAL( currentItemChanged( QListWidgetItem*, QListWidgetItem* ) ), SLOT( changePage( QListWidgetItem*, QListWidgetItem* ) ) );
|
||||
QAction *advancedAction = new QAction( QIcon( RESPATH "images/advanced-settings.png" ),
|
||||
tr( "Advanced" ),
|
||||
m_toolBar );
|
||||
advancedAction->setCheckable( true );
|
||||
advancedAction->setToolTip( tr( "<b>Advanced</b><br>"
|
||||
"Configure Tomahawk's advanced settings, including "
|
||||
"network connectivity settings, browser interaction "
|
||||
"and more." ) );
|
||||
m_settingsGroup->addAction( advancedAction );
|
||||
|
||||
m_settingsGroup->setExclusive( true );
|
||||
|
||||
m_toolBar->addActions( m_settingsGroup->actions() );
|
||||
|
||||
QWidget *rightSpacer = new QWidget( m_toolBar );
|
||||
rightSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
|
||||
m_toolBar->addWidget( rightSpacer );
|
||||
|
||||
connect( m_settingsGroup, SIGNAL( triggered( QAction * ) ),
|
||||
this, SLOT( changePage( QAction * ) ) );
|
||||
|
||||
accountsAction->setChecked( true );
|
||||
changePage( accountsAction );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::changePage( QListWidgetItem* current, QListWidgetItem* previous )
|
||||
SettingsDialog::changePage( QAction *action )
|
||||
{
|
||||
if ( !current )
|
||||
current = previous;
|
||||
|
||||
ui->stackedWidget->setCurrentIndex( ui->listWidget->row(current) );
|
||||
int index = m_settingsGroup->actions().indexOf( action );
|
||||
if( ui->stackedWidget->currentIndex() != index )
|
||||
{
|
||||
ui->stackedWidget->setCurrentIndex( index );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2012, Teo Mrnjavac <teo@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -23,6 +24,8 @@
|
||||
|
||||
#include <QtGui/QDialog>
|
||||
#include <QtCore/QModelIndex>
|
||||
#include <QtGui/QActionGroup>
|
||||
#include <QtGui/QToolBar>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -94,7 +97,7 @@ private slots:
|
||||
|
||||
void updateScanOptionsView();
|
||||
|
||||
void changePage( QListWidgetItem*, QListWidgetItem* );
|
||||
void changePage( QAction *action );
|
||||
void serventReady();
|
||||
|
||||
void aclEntryClearButtonClicked();
|
||||
@@ -106,6 +109,9 @@ private:
|
||||
|
||||
Ui_StackedSettingsDialog* ui;
|
||||
|
||||
QToolBar *m_toolBar;
|
||||
QActionGroup *m_settingsGroup;
|
||||
|
||||
ProxyDialog m_proxySettings;
|
||||
bool m_rejected;
|
||||
bool m_restartRequired;
|
||||
|
@@ -1,74 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SettingsListDelegate.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QIcon>
|
||||
#include <QApplication>
|
||||
|
||||
SettingsListDelegate::SettingsListDelegate(QObject *parent) :
|
||||
QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SettingsListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, QModelIndex() );
|
||||
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
|
||||
|
||||
#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
|
||||
// On mac draw our own selection rect as we don't get one from osx (around the whole icon or around just text)
|
||||
if ( opt.state & QStyle::State_Selected )
|
||||
{
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
|
||||
QPainterPath p;
|
||||
p.addRoundedRect( opt.rect.adjusted( 2, 1, -1, -1 ), 5, 5 );
|
||||
|
||||
QColor fill( 214, 214, 214 );
|
||||
QColor border( 107, 107, 107 );
|
||||
painter->setPen( border );
|
||||
painter->drawPath( p );
|
||||
painter->fillPath( p, fill );
|
||||
}
|
||||
#else
|
||||
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
||||
{
|
||||
painter->setPen( option.palette.color( QPalette::HighlightedText ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
int horizontalOffset = ( option.rect.width() - option.decorationSize.width() ) /2;
|
||||
QRect iconRect = option.rect.adjusted( horizontalOffset, 6, -horizontalOffset, -option.rect.height() + 6 + option.decorationSize.height() );
|
||||
QPixmap avatar = index.data( Qt::DecorationRole ).value<QIcon>().pixmap( iconRect.size() );
|
||||
painter->drawPixmap( iconRect, avatar );
|
||||
|
||||
QRect textRect = option.rect.adjusted( 6, iconRect.height() + 8, -6, 0 );
|
||||
QString text = painter->fontMetrics().elidedText( index.data( Qt::DisplayRole ).toString(), Qt::ElideRight, textRect.width() );
|
||||
QTextOption to( Qt::AlignHCenter );
|
||||
painter->drawText( textRect, text, to );
|
||||
|
||||
painter->restore();
|
||||
}
|
@@ -18,74 +18,11 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="autoScroll">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Static</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="layoutMode">
|
||||
<enum>QListView::Batched</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>1</width>
|
||||
<height>4</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<layout class="QVBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="accountsPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||
@@ -93,9 +30,12 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Internet Services</string>
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<property name="margin">
|
||||
@@ -153,11 +93,17 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Local Music Information</string>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
@@ -234,17 +180,23 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxNetworkAdvanced">
|
||||
<widget class="QFrame" name="frameNetworkAdvanced">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Advanced Settings</string>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
@@ -342,10 +294,13 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
@@ -363,8 +318,30 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="proxyButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Proxy Settings...</string>
|
||||
</property>
|
||||
@@ -378,10 +355,13 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
@@ -395,7 +375,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxHttp">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Allow web browsers to interact with Tomahawk (recommended)</string>
|
||||
@@ -408,7 +388,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxReporter">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send reports after Tomahawk crashed</string>
|
||||
@@ -425,6 +405,9 @@
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
|
@@ -31,8 +31,9 @@
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "Artist.h"
|
||||
#include "AclRegistryImpl.h"
|
||||
#include "Album.h"
|
||||
#include "Artist.h"
|
||||
#include "Collection.h"
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
@@ -50,11 +51,10 @@
|
||||
#include "web/Api_v1.h"
|
||||
#include "SourceList.h"
|
||||
#include "ShortcutHandler.h"
|
||||
#include "ScanManager.h"
|
||||
#include "libtomahawk/filemetadata/ScanManager.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "GlobalActionManager.h"
|
||||
#include "database/LocalCollection.h"
|
||||
#include "MusicScanner.h"
|
||||
#include "Pipeline.h"
|
||||
#include "DropJob.h"
|
||||
#include "EchonestCatalogSynchronizer.h"
|
||||
@@ -205,6 +205,8 @@ TomahawkApp::init()
|
||||
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
|
||||
new ACLRegistryImpl( this );
|
||||
|
||||
tDebug( LOGINFO ) << "Setting NAM.";
|
||||
// Cause the creation of the nam, but don't need to address it directly, so prevent warning
|
||||
Q_UNUSED( TomahawkUtils::nam() );
|
||||
@@ -319,7 +321,7 @@ TomahawkApp::init()
|
||||
|
||||
if ( arguments().contains( "--filescan" ) )
|
||||
{
|
||||
m_scanManager.data()->runScan( true );
|
||||
m_scanManager.data()->runFullRescan();
|
||||
}
|
||||
|
||||
// Set up echonest catalog synchronizer
|
||||
@@ -360,47 +362,38 @@ TomahawkApp::~TomahawkApp()
|
||||
|
||||
if ( !m_session.isNull() )
|
||||
delete m_session.data();
|
||||
tLog() << "Deleting connector";
|
||||
if ( !m_connector.isNull() )
|
||||
delete m_connector.data();
|
||||
|
||||
tLog() << "Stopping pipeline";
|
||||
if ( Pipeline::instance() )
|
||||
Pipeline::instance()->stop();
|
||||
|
||||
tLog() << "Deleting servent";
|
||||
if ( !m_servent.isNull() )
|
||||
delete m_servent.data();
|
||||
tLog() << "Deleting ScanManager";
|
||||
|
||||
delete dynamic_cast< ACLRegistryImpl* >( ACLRegistry::instance() );
|
||||
|
||||
if ( !m_scanManager.isNull() )
|
||||
delete m_scanManager.data();
|
||||
|
||||
tLog() << "Deleting AudioEngine";
|
||||
if ( !m_audioEngine.isNull() )
|
||||
delete m_audioEngine.data();
|
||||
|
||||
tLog() << "Deleting AccountManager";
|
||||
delete Tomahawk::Accounts::AccountManager::instance();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
tLog() << "Deleting AtticaManager";
|
||||
delete AtticaManager::instance();
|
||||
tLog() << "Deleting Window";
|
||||
delete m_mainwindow;
|
||||
#endif
|
||||
|
||||
tLog() << "Deleting database";
|
||||
if ( !m_database.isNull() )
|
||||
delete m_database.data();
|
||||
|
||||
tLog() << "Deleting Pipeline";
|
||||
delete Pipeline::instance();
|
||||
|
||||
tLog() << "Deleting InfoSystem";
|
||||
if ( !m_infoSystem.isNull() )
|
||||
delete m_infoSystem.data();
|
||||
|
||||
tLog() << "Deleting Cache";
|
||||
|
||||
delete TomahawkUtils::Cache::instance();
|
||||
|
||||
tLog() << "Finished shutdown.";
|
||||
@@ -726,6 +719,27 @@ TomahawkApp::loadUrl( const QString& url )
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TomahawkApp::notify( QObject *receiver, QEvent *e )
|
||||
{
|
||||
try
|
||||
{
|
||||
return TOMAHAWK_APPLICATION::notify( receiver, e );
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
qWarning( "TomahawkApp::notify caught a std exception in a Qt event handler: " );
|
||||
qFatal( e.what() );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
qFatal( "TomahawkApp::notify caught a non-std-exception from a Qt event handler. Aborting." );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance )
|
||||
{
|
||||
|
@@ -98,7 +98,10 @@ public:
|
||||
virtual bool loadUrl( const QString& url );
|
||||
|
||||
bool isTomahawkLoaded() const { return m_loaded; }
|
||||
|
||||
|
||||
// reimplemented from QApplication/QCoreApplication
|
||||
virtual bool notify( QObject* receiver, QEvent* e );
|
||||
|
||||
signals:
|
||||
void tomahawkLoaded();
|
||||
|
||||
|
@@ -67,12 +67,15 @@
|
||||
#include "TomahawkSettings.h"
|
||||
#include "SourceList.h"
|
||||
#include "TomahawkTrayIcon.h"
|
||||
#include "ScanManager.h"
|
||||
#include "libtomahawk/filemetadata/ScanManager.h"
|
||||
#include "TomahawkApp.h"
|
||||
#include "LoadXSPFDialog.h"
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#include <qtsparkle/Updater>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <qtsparkle/Updater>
|
||||
#ifndef THBN_CLICKED
|
||||
#define THBN_CLICKED 0x1800
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "utils/Logger.h"
|
||||
@@ -80,8 +83,13 @@
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
|
||||
|
||||
TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
: QMainWindow( parent )
|
||||
#ifdef Q_OS_WIN
|
||||
, m_buttonCreatedID( RegisterWindowMessage( L"TaskbarButtonCreated" ) )
|
||||
, m_taskbarList(0)
|
||||
#endif
|
||||
, ui( new Ui::TomahawkWindow )
|
||||
, m_searchWidget( 0 )
|
||||
, m_audioControls( new AudioControls( this ) )
|
||||
@@ -95,6 +103,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
connect( vm, SIGNAL( hideQueueRequested() ), SLOT( hideQueue() ) );
|
||||
connect( APP, SIGNAL( tomahawkLoaded() ), vm, SLOT( setTomahawkLoaded() ) ); // Pass loaded signal into libtomahawk so components in there can connect to ViewManager
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
connect( AudioEngine::instance(), SIGNAL( stateChanged( AudioState, AudioState) ), SLOT( audioStateChanged( AudioState, AudioState) ) );
|
||||
#endif
|
||||
ui->setupUi( this );
|
||||
|
||||
ui->menuApp->insertAction( ui->actionCreatePlaylist, ActionCollection::instance()->getAction( "togglePrivacy" ) );
|
||||
@@ -191,11 +202,7 @@ TomahawkWindow::saveSettings()
|
||||
void
|
||||
TomahawkWindow::applyPlatformTweaks()
|
||||
{
|
||||
// HACK QtCurve causes an infinite loop on startup. This is because setStyle calls setPalette, which calls ensureBaseStyle,
|
||||
// which loads QtCurve. QtCurve calls setPalette, which creates an infinite loop. The UI will look like CRAP with QtCurve, but
|
||||
// the user is asking for it explicitly... so he's gonna be stuck with an ugly UI.
|
||||
if ( !QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) )
|
||||
qApp->setStyle( new ProxyStyle() );
|
||||
qApp->setStyle( new ProxyStyle() );
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
setUnifiedTitleAndToolBarOnMac( true );
|
||||
@@ -237,7 +244,7 @@ TomahawkWindow::setupToolBar()
|
||||
m_searchWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
|
||||
m_searchWidget->setMaximumWidth( 340 );
|
||||
connect( m_searchWidget, SIGNAL( returnPressed() ), this, SLOT( onFilterEdited() ) );
|
||||
|
||||
|
||||
toolbar->addWidget( m_searchWidget );
|
||||
}
|
||||
|
||||
@@ -258,7 +265,9 @@ TomahawkWindow::setupSideBar()
|
||||
|
||||
m_sourcetree = new SourceTreeView( this );
|
||||
JobStatusView* jobsView = new JobStatusView( m_sidebar );
|
||||
m_jobsModel = new JobStatusModel( jobsView );
|
||||
JobStatusModel* sourceModel = new JobStatusModel( jobsView );
|
||||
m_jobsModel = new JobStatusSortModel( jobsView );
|
||||
m_jobsModel->setJobModel( sourceModel );
|
||||
jobsView->setModel( m_jobsModel );
|
||||
|
||||
m_queueView = new QueueView( m_sidebar );
|
||||
@@ -321,6 +330,71 @@ TomahawkWindow::setupUpdateCheck()
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool
|
||||
TomahawkWindow::setupWindowsButtons()
|
||||
{
|
||||
const GUID IID_ITaskbarList3 = { 0xea1afb91,0x9e28,0x4b86, { 0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf } };
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
QPixmap play( RESPATH "images/play-rest.png" );
|
||||
QPixmap back( RESPATH "images/back-rest.png" );
|
||||
QPixmap love( RESPATH "images/not-loved.png" );
|
||||
|
||||
QTransform transform;
|
||||
transform.rotate( 180 );
|
||||
QPixmap next( back.transformed( transform ) );
|
||||
|
||||
THUMBBUTTONMASK dwMask = THUMBBUTTONMASK( THB_ICON | THB_TOOLTIP | THB_FLAGS );
|
||||
m_thumbButtons[TP_PREVIOUS].dwMask = dwMask;
|
||||
m_thumbButtons[TP_PREVIOUS].iId = TP_PREVIOUS;
|
||||
m_thumbButtons[TP_PREVIOUS].hIcon = back.toWinHICON();
|
||||
m_thumbButtons[TP_PREVIOUS].dwFlags = THBF_ENABLED;
|
||||
m_thumbButtons[TP_PREVIOUS].szTip[ tr( "Back" ).toWCharArray( m_thumbButtons[TP_PREVIOUS].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[TP_PLAY_PAUSE].dwMask = dwMask;
|
||||
m_thumbButtons[TP_PLAY_PAUSE].iId = TP_PLAY_PAUSE;
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
|
||||
m_thumbButtons[TP_PLAY_PAUSE].dwFlags = THBF_ENABLED;
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[TP_NEXT].dwMask = dwMask;
|
||||
m_thumbButtons[TP_NEXT].iId = TP_NEXT;
|
||||
m_thumbButtons[TP_NEXT].hIcon = next.toWinHICON();
|
||||
m_thumbButtons[TP_NEXT].dwFlags = THBF_ENABLED;
|
||||
m_thumbButtons[TP_NEXT].szTip[ tr( "Next" ).toWCharArray( m_thumbButtons[TP_NEXT].szTip ) ] = 0;
|
||||
|
||||
m_thumbButtons[3].dwMask = dwMask;
|
||||
m_thumbButtons[3].iId = -1;
|
||||
m_thumbButtons[3].hIcon = 0;
|
||||
m_thumbButtons[3].dwFlags = THBF_NOBACKGROUND | THBF_DISABLED;
|
||||
m_thumbButtons[3].szTip[0] = 0;
|
||||
|
||||
m_thumbButtons[TP_LOVE].dwMask = dwMask;
|
||||
m_thumbButtons[TP_LOVE].iId = TP_LOVE;
|
||||
m_thumbButtons[TP_LOVE].hIcon = love.toWinHICON();
|
||||
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
|
||||
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
|
||||
|
||||
if ( S_OK == CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_taskbarList ) )
|
||||
{
|
||||
hr = m_taskbarList->HrInit();
|
||||
if ( SUCCEEDED( hr ) )
|
||||
{
|
||||
hr = m_taskbarList->ThumbBarAddButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_taskbarList->Release();
|
||||
m_taskbarList = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCEEDED( hr );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::setupSignals()
|
||||
{
|
||||
@@ -334,6 +408,7 @@ TomahawkWindow::setupSignals()
|
||||
connect( AudioEngine::instance(), SIGNAL( error( AudioEngine::AudioErrorCode ) ), SLOT( onAudioEngineError( AudioEngine::AudioErrorCode ) ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( finished(Tomahawk::result_ptr) ), SLOT( audioFinished() ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( resumed()), SLOT( audioStarted() ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) );
|
||||
@@ -380,7 +455,7 @@ TomahawkWindow::setupSignals()
|
||||
connect( account->sipPlugin(), SIGNAL( addMenu( QMenu* ) ), this, SLOT( pluginMenuAdded( QMenu* ) ) );
|
||||
connect( account->sipPlugin(), SIGNAL( removeMenu( QMenu* ) ), this, SLOT( pluginMenuRemoved( QMenu* ) ) );
|
||||
}
|
||||
|
||||
|
||||
connect( ViewManager::instance(), SIGNAL( historyBackAvailable( bool ) ), SLOT( onHistoryBackAvailable( bool ) ) );
|
||||
connect( ViewManager::instance(), SIGNAL( historyForwardAvailable( bool ) ), SLOT( onHistoryForwardAvailable( bool ) ) );
|
||||
}
|
||||
@@ -492,6 +567,123 @@ TomahawkWindow::keyPressEvent( QKeyEvent* e )
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool
|
||||
TomahawkWindow::winEvent( MSG* msg, long* result )
|
||||
{
|
||||
#define TB_PRESSED Q_FUNC_INFO << "Taskbar Button Pressed:"
|
||||
|
||||
switch( msg->message )
|
||||
{
|
||||
case WM_COMMAND:
|
||||
if ( HIWORD( msg->wParam ) == THBN_CLICKED )
|
||||
{
|
||||
switch( TB_STATES(LOWORD( msg->wParam )) )
|
||||
{
|
||||
case TP_PREVIOUS:
|
||||
tLog() << TB_PRESSED << "Previous";
|
||||
AudioEngine::instance()->previous();
|
||||
break;
|
||||
case TP_PLAY_PAUSE:
|
||||
tLog() << TB_PRESSED << "Play/Pause";
|
||||
AudioEngine::instance()->playPause();
|
||||
break;
|
||||
case TP_NEXT:
|
||||
tLog() << TB_PRESSED << "Next";
|
||||
AudioEngine::instance()->next();
|
||||
break;
|
||||
case TP_LOVE:
|
||||
tLog() << TB_PRESSED << "Love";
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() )
|
||||
{
|
||||
AudioEngine::instance()->currentTrack()->toQuery()->setLoved( !AudioEngine::instance()->currentTrack()->toQuery()->loved() );
|
||||
updateWindowsLoveButton();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( msg->message == m_buttonCreatedID )
|
||||
return setupWindowsButtons();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
|
||||
{
|
||||
if ( m_taskbarList == 0 )
|
||||
return;
|
||||
|
||||
switch ( newState )
|
||||
{
|
||||
case AudioEngine::Playing:
|
||||
{
|
||||
QPixmap pause( RESPATH "images/pause-rest.png" );
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = pause.toWinHICON();
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Pause" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
updateWindowsLoveButton();
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case AudioEngine::Paused:
|
||||
{
|
||||
QPixmap play( RESPATH "images/play-rest.png" );
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case AudioEngine::Stopped:
|
||||
{
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() )
|
||||
{
|
||||
disconnect(AudioEngine::instance()->currentTrack()->toQuery().data(),SIGNAL(socialActionsLoaded()),this,SLOT(updateWindowsLoveButton()));
|
||||
}
|
||||
QPixmap play( RESPATH "images/play-rest.png" );
|
||||
m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
|
||||
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
|
||||
|
||||
QPixmap not_loved( RESPATH "images/not-loved.png" );
|
||||
m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
|
||||
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
|
||||
}
|
||||
|
||||
void
|
||||
TomahawkWindow::updateWindowsLoveButton()
|
||||
{
|
||||
if ( !AudioEngine::instance()->currentTrack().isNull() && AudioEngine::instance()->currentTrack()->toQuery()->loved() )
|
||||
{
|
||||
QPixmap loved( RESPATH "images/loved.png" );
|
||||
m_thumbButtons[TP_LOVE].hIcon = loved.toWinHICON();
|
||||
m_thumbButtons[TP_LOVE].szTip[ tr( "Unlove" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
QPixmap not_loved( RESPATH "images/not-loved.png" );
|
||||
m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
|
||||
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
|
||||
}
|
||||
m_thumbButtons[TP_LOVE].dwFlags = THBF_ENABLED;
|
||||
m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::onHistoryBackAvailable( bool avail )
|
||||
{
|
||||
@@ -514,7 +706,7 @@ TomahawkWindow::showSettingsDialog()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
TomahawkWindow::showDiagnosticsDialog()
|
||||
{
|
||||
DiagnosticsDialog win;
|
||||
@@ -533,7 +725,7 @@ void
|
||||
TomahawkWindow::updateCollectionManually()
|
||||
{
|
||||
if ( TomahawkSettings::instance()->hasScannerPaths() )
|
||||
ScanManager::instance()->runScan();
|
||||
ScanManager::instance()->runNormalScan();
|
||||
}
|
||||
|
||||
|
||||
@@ -541,7 +733,7 @@ void
|
||||
TomahawkWindow::rescanCollectionManually()
|
||||
{
|
||||
if ( TomahawkSettings::instance()->hasScannerPaths() )
|
||||
ScanManager::instance()->runScan( true );
|
||||
ScanManager::instance()->runFullRescan();
|
||||
}
|
||||
|
||||
|
||||
@@ -838,6 +1030,18 @@ TomahawkWindow::audioStarted()
|
||||
|
||||
ui->actionPlay->setText( tr( "Pause" ) );
|
||||
ActionCollection::instance()->getAction( "stop" )->setEnabled( true );
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
connect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( updateWindowsLoveButton() ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
TomahawkWindow::audioFinished()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -853,7 +1057,7 @@ TomahawkWindow::audioStopped()
|
||||
{
|
||||
audioPaused();
|
||||
ActionCollection::instance()->getAction( "stop" )->setEnabled( false );
|
||||
|
||||
|
||||
m_currentTrack = result_ptr();
|
||||
setWindowTitle( m_windowTitle );
|
||||
}
|
||||
|
@@ -31,13 +31,19 @@
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "utils/XspfLoader.h"
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace Accounts {
|
||||
class Account;
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
#include <shobjidl.h>
|
||||
#endif
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
class Account;
|
||||
}
|
||||
}
|
||||
|
||||
class JobStatusModel;
|
||||
class JobStatusSortModel;
|
||||
class QSearchField;
|
||||
class SourceTreeView;
|
||||
class QAction;
|
||||
@@ -75,6 +81,10 @@ protected:
|
||||
void hideEvent( QHideEvent* e );
|
||||
void keyPressEvent( QKeyEvent* e );
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool winEvent( MSG* message, long* result );
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void createAutomaticPlaylist( QString );
|
||||
void createStation();
|
||||
@@ -85,8 +95,8 @@ public slots:
|
||||
void legalInfo();
|
||||
void updateCollectionManually();
|
||||
void rescanCollectionManually();
|
||||
void pluginMenuAdded(QMenu*);
|
||||
void pluginMenuRemoved(QMenu*);
|
||||
void pluginMenuAdded( QMenu* );
|
||||
void pluginMenuRemoved( QMenu* );
|
||||
void showOfflineSources();
|
||||
|
||||
void fullScreenEntered();
|
||||
@@ -111,6 +121,7 @@ private slots:
|
||||
void onPlaybackLoading( const Tomahawk::result_ptr& result );
|
||||
|
||||
void audioStarted();
|
||||
void audioFinished();
|
||||
void audioPaused();
|
||||
void audioStopped();
|
||||
|
||||
@@ -132,6 +143,11 @@ private slots:
|
||||
|
||||
void crashNow();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void audioStateChanged( AudioState newState, AudioState oldState );
|
||||
void updateWindowsLoveButton();
|
||||
#endif
|
||||
|
||||
private:
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
@@ -142,6 +158,14 @@ private:
|
||||
void setupSideBar();
|
||||
void setupUpdateCheck();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool setupWindowsButtons();
|
||||
const unsigned int m_buttonCreatedID;
|
||||
ITaskbarList3 *m_taskbarList;
|
||||
THUMBBUTTON m_thumbButtons[5];
|
||||
enum TB_STATES{ TP_PREVIOUS = 0,TP_PLAY_PAUSE = 1,TP_NEXT = 2,TP_LOVE = 4 };
|
||||
#endif
|
||||
|
||||
Ui::TomahawkWindow* ui;
|
||||
QSearchField* m_searchWidget;
|
||||
AudioControls* m_audioControls;
|
||||
@@ -151,7 +175,7 @@ private:
|
||||
QPushButton* m_queueButton;
|
||||
QueueView* m_queueView;
|
||||
AnimatedSplitter* m_sidebar;
|
||||
JobStatusModel* m_jobsModel;
|
||||
JobStatusSortModel* m_jobsModel;
|
||||
|
||||
QAction* m_backAction;
|
||||
QAction* m_forwardAction;
|
||||
|
@@ -73,6 +73,11 @@ AvatarManager::fetchVCard( const QString& jid )
|
||||
void
|
||||
AvatarManager::onNewPresence( const Jreen::Presence& presence )
|
||||
{
|
||||
if ( presence.error() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Jreen::VCardUpdate::Ptr update = presence.payload<Jreen::VCardUpdate>();
|
||||
if ( update )
|
||||
{
|
||||
|
@@ -1,4 +1,4 @@
|
||||
include_directories(${LIBECHONEST_INCLUDE_DIR})
|
||||
include_directories(${ECHONEST_INCLUDE_DIR})
|
||||
|
||||
list(APPEND simple_plugins
|
||||
Echonest
|
||||
|
@@ -42,7 +42,7 @@ NewReleasesPlugin::NewReleasesPlugin()
|
||||
: InfoPlugin()
|
||||
, m_nrFetchJobs ( 0 )
|
||||
{
|
||||
m_nrVersion = "0";
|
||||
m_nrVersion = "0.1";
|
||||
m_supportedGetTypes << InfoNewReleaseCapabilities << InfoNewRelease;
|
||||
}
|
||||
|
||||
@@ -54,8 +54,10 @@ NewReleasesPlugin::~NewReleasesPlugin()
|
||||
void
|
||||
NewReleasesPlugin::init()
|
||||
{
|
||||
|
||||
QVariantList source_qvarlist = TomahawkUtils::Cache::instance()->getData( "NewReleasesPlugin", "nr_sources" ).toList();
|
||||
foreach( const QVariant & source, source_qvarlist ) {
|
||||
foreach( const QVariant & source, source_qvarlist )
|
||||
{
|
||||
m_nrSources.append( source.toString() );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "fetched source from cache" << source.toString();
|
||||
|
||||
@@ -79,21 +81,28 @@ void NewReleasesPlugin::getInfo ( InfoRequestData requestData )
|
||||
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
bool foundSource = false;
|
||||
|
||||
switch ( requestData.type ) {
|
||||
switch ( requestData.type )
|
||||
{
|
||||
case InfoNewRelease:
|
||||
/// We need something to check if the request is actually ment to go to this plugin
|
||||
if ( !hash.contains ( "nr_source" ) ) {
|
||||
if ( !hash.contains ( "nr_source" ) )
|
||||
{
|
||||
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required param!";
|
||||
dataError ( requestData );
|
||||
break;
|
||||
} else {
|
||||
foreach ( QString resource, m_nrSources ) {
|
||||
if ( resource == hash["nr_source"] ) {
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( QString resource, m_nrSources )
|
||||
{
|
||||
if ( resource == hash["nr_source"] )
|
||||
{
|
||||
foundSource = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !foundSource ) {
|
||||
if ( !foundSource )
|
||||
{
|
||||
dataError ( requestData );
|
||||
break;
|
||||
}
|
||||
@@ -112,7 +121,8 @@ void NewReleasesPlugin::getInfo ( InfoRequestData requestData )
|
||||
|
||||
void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData )
|
||||
{
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) {
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
{
|
||||
dataError ( requestData );
|
||||
return;
|
||||
}
|
||||
@@ -121,7 +131,8 @@ void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData )
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
|
||||
/// Each request needs to contain both a id and source
|
||||
if ( !hash.contains ( "nr_id" ) && !hash.contains ( "nr_source" ) ) {
|
||||
if ( !hash.contains ( "nr_id" ) && !hash.contains ( "nr_source" ) )
|
||||
{
|
||||
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!";
|
||||
dataError ( requestData );
|
||||
return;
|
||||
@@ -136,7 +147,8 @@ void NewReleasesPlugin::fetchNRFromCache ( InfoRequestData requestData )
|
||||
|
||||
void NewReleasesPlugin::fetchNRCapabilitiesFromCache ( InfoRequestData requestData )
|
||||
{
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) {
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
{
|
||||
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "Could not convert requestData to InfoStringHash!";
|
||||
dataError ( requestData );
|
||||
return;
|
||||
@@ -150,15 +162,18 @@ void NewReleasesPlugin::fetchNRCapabilitiesFromCache ( InfoRequestData requestDa
|
||||
|
||||
void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestData requestData )
|
||||
{
|
||||
switch ( requestData.type ) {
|
||||
case InfoNewRelease: {
|
||||
switch ( requestData.type )
|
||||
{
|
||||
case InfoNewRelease:
|
||||
{
|
||||
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease not in cache! Fetching...";
|
||||
fetchNR ( requestData, criteria["nr_source"], criteria["nr_id"] );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
case InfoNewReleaseCapabilities: {
|
||||
case InfoNewReleaseCapabilities:
|
||||
{
|
||||
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching...";
|
||||
fetchNRSourcesList( false );
|
||||
m_cachedRequests.append ( requestData );
|
||||
@@ -166,7 +181,8 @@ void NewReleasesPlugin::notInCacheSlot ( InfoStringHash criteria, InfoRequestDat
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
default:
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Couldn't figure out what to do with this type of request after cache miss";
|
||||
emit info ( requestData, QVariant() );
|
||||
return;
|
||||
@@ -191,19 +207,22 @@ void NewReleasesPlugin::nrSourcesList()
|
||||
tDebug ( LOGVERBOSE ) << "Got newreleases sources list";
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*> ( sender() );
|
||||
|
||||
if ( reply->error() == QNetworkReply::NoError ) {
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QJson::Parser p;
|
||||
bool ok;
|
||||
const QVariantMap res = p.parse ( reply, &ok ).toMap();
|
||||
const QVariantList sources = res.value ( "sources" ).toList();
|
||||
|
||||
if ( !ok ) {
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << "Failed to parse sources" << p.errorString() << "On line" << p.errorLine();
|
||||
return;
|
||||
}
|
||||
|
||||
m_nrSources.clear();
|
||||
foreach ( const QVariant &source, sources ) {
|
||||
foreach ( const QVariant &source, sources )
|
||||
{
|
||||
m_nrSources << source.toString();
|
||||
}
|
||||
TomahawkUtils::Cache::instance()->putData( "NewReleasesPlugin", 172800000 /* 2 days */, "nr_sources", m_nrSources );
|
||||
@@ -214,9 +233,11 @@ void NewReleasesPlugin::nrSourcesList()
|
||||
|
||||
void NewReleasesPlugin::fetchAllNRSources()
|
||||
{
|
||||
if ( !m_nrSources.isEmpty() && m_allNRsMap.isEmpty() ) {
|
||||
if ( !m_nrSources.isEmpty() && m_allNRsMap.isEmpty() )
|
||||
{
|
||||
tDebug ( LOGVERBOSE ) << Q_FUNC_INFO << "InfoNewRelease fetching source data";
|
||||
foreach ( QString source, m_nrSources ) {
|
||||
foreach ( QString source, m_nrSources )
|
||||
{
|
||||
QUrl url = QUrl ( QString ( CHART_URL "newreleases/%1" ).arg ( source ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get ( QNetworkRequest ( url ) );
|
||||
reply->setProperty ( "nr_source", source );
|
||||
@@ -246,12 +267,14 @@ void NewReleasesPlugin::nrList()
|
||||
tDebug ( LOGVERBOSE ) << "Got newreleases list result";
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*> ( sender() );
|
||||
|
||||
if ( reply->error() == QNetworkReply::NoError ) {
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QJson::Parser p;
|
||||
bool ok;
|
||||
const QVariantMap res = p.parse ( reply, &ok ).toMap();
|
||||
|
||||
if ( !ok ) {
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << "Failed to parse resources" << p.errorString() << "On line" << p.errorLine();
|
||||
|
||||
return;
|
||||
@@ -267,31 +290,53 @@ void NewReleasesPlugin::nrList()
|
||||
// Building:
|
||||
// [Source] - New Release
|
||||
QList< InfoStringHash > albumNRs;
|
||||
|
||||
foreach ( const QVariant &nrObj, res.values() ) {
|
||||
if ( !nrObj.toMap().isEmpty() ) {
|
||||
QHash< QString, QVariantMap > extraType;
|
||||
foreach ( const QVariant &nrObj, res.values() )
|
||||
{
|
||||
if ( !nrObj.toMap().isEmpty() )
|
||||
{
|
||||
const QVariantMap nrMap = nrObj.toMap();
|
||||
const QString type = nrMap.value ( "type" ).toString();
|
||||
const QString extra = nrMap.value( "extra" ).toString();
|
||||
|
||||
InfoStringHash nr;
|
||||
nr["id"] = nrMap.value ( "id" ).toString();
|
||||
nr["label"] = nrMap.value ( "name" ).toString();
|
||||
nr["date"] = nrMap.value ( "date" ).toString();
|
||||
|
||||
if ( type == "Album" ) {
|
||||
if ( type == "Album" )
|
||||
{
|
||||
nr[ "type" ] = "album";
|
||||
albumNRs.append ( nr );
|
||||
} else {
|
||||
|
||||
if( !extra.isEmpty() )
|
||||
{
|
||||
qDebug() << "FOUND EXTRA!! " << extra;
|
||||
QList< Tomahawk::InfoSystem::InfoStringHash > extraTypeData = extraType[ extra ][ type ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >();
|
||||
extraTypeData.append( nr );
|
||||
extraType[ extra ][ type ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( extraTypeData );
|
||||
}
|
||||
else
|
||||
albumNRs.append ( nr );
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Unknown newrelease type " << type;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach( const QString& c, extraType.keys() )
|
||||
{
|
||||
newreleases[ c ] = extraType[ c ];
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "extraType has types:" << c;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !albumNRs.isEmpty() )
|
||||
newreleases.insert ( tr ( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > > ( albumNRs ) );
|
||||
|
||||
|
||||
/// @note For displaying purposes, upper the first letter
|
||||
/// @note Remeber to lower it when fetching this!
|
||||
nrName = source;
|
||||
@@ -306,8 +351,10 @@ void NewReleasesPlugin::nrList()
|
||||
}
|
||||
|
||||
m_nrFetchJobs--;
|
||||
if ( !m_cachedRequests.isEmpty() && m_nrFetchJobs == 0 ) {
|
||||
foreach ( InfoRequestData request, m_cachedRequests ) {
|
||||
if ( !m_cachedRequests.isEmpty() && m_nrFetchJobs == 0 )
|
||||
{
|
||||
foreach ( InfoRequestData request, m_cachedRequests )
|
||||
{
|
||||
emit info ( request, m_allNRsMap );
|
||||
// update cache
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
@@ -325,12 +372,14 @@ void NewReleasesPlugin::nrReturned()
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*> ( sender() );
|
||||
QVariantMap returnedData;
|
||||
|
||||
if ( reply->error() == QNetworkReply::NoError ) {
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QJson::Parser p;
|
||||
bool ok;
|
||||
QVariantMap res = p.parse ( reply, &ok ).toMap();
|
||||
|
||||
if ( !ok ) {
|
||||
if ( !ok )
|
||||
{
|
||||
tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine();
|
||||
return;
|
||||
}
|
||||
@@ -339,9 +388,11 @@ void NewReleasesPlugin::nrReturned()
|
||||
QVariantList albumList = res.value ( "list" ).toList();
|
||||
QList< Tomahawk::InfoSystem::InfoStringHash > newreleases;
|
||||
|
||||
foreach( const QVariant & albumObj, albumList ) {
|
||||
foreach( const QVariant & albumObj, albumList )
|
||||
{
|
||||
QVariantMap albumMap = albumObj.toMap();
|
||||
if(!albumMap.isEmpty()) {
|
||||
if( !albumMap.isEmpty() )
|
||||
{
|
||||
const QString album = albumMap.value("album").toString();
|
||||
const QString artist = albumMap.value("artist").toString();
|
||||
const QString date = albumMap.value("date").toString();
|
||||
|
@@ -22,18 +22,6 @@
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include "TomahawkSettings.h"
|
||||
#include "TomahawkApp.h"
|
||||
#include "Source.h"
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "accounts/Account.h"
|
||||
#include "jobview/AclJobItem.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#endif
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
|
||||
@@ -89,21 +77,23 @@ ACLRegistry* ACLRegistry::s_instance = 0;
|
||||
ACLRegistry*
|
||||
ACLRegistry::instance()
|
||||
{
|
||||
if( !s_instance )
|
||||
new ACLRegistry();
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::setInstance( ACLRegistry* instance )
|
||||
{
|
||||
s_instance = instance;
|
||||
}
|
||||
|
||||
|
||||
ACLRegistry::ACLRegistry( QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_jobCount( 0 )
|
||||
{
|
||||
s_instance = this;
|
||||
qRegisterMetaType< ACLRegistry::ACL >( "ACLRegistry::ACL" );
|
||||
qRegisterMetaType< ACLRegistry::User >( "ACLRegistry::User" );
|
||||
qRegisterMetaTypeStreamOperators< ACLRegistry::User >( "ACLRegistry::User" );
|
||||
load();
|
||||
}
|
||||
|
||||
|
||||
@@ -112,220 +102,15 @@ ACLRegistry::~ACLRegistry()
|
||||
}
|
||||
|
||||
|
||||
ACLRegistry::ACL
|
||||
ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACLRegistry::ACL globalType, bool skipEmission )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
{
|
||||
if ( !skipEmission )
|
||||
QMetaObject::invokeMethod( this, "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( const QString&, dbid ), Q_ARG( const QString &, username ), Q_ARG( ACLRegistry::ACL, globalType ), Q_ARG( bool, skipEmission ) );
|
||||
return ACLRegistry::NotFound;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
if ( Tomahawk::Accounts::AccountManager::instance() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking account friendly names against" << username;
|
||||
Tomahawk::Accounts::AccountManager* accountManager = Tomahawk::Accounts::AccountManager::instance();
|
||||
QList< Tomahawk::Accounts::Account* > accounts = accountManager->accounts();
|
||||
foreach( Tomahawk::Accounts::Account* account, accounts )
|
||||
{
|
||||
if ( !( account->types() & Tomahawk::Accounts::SipType ) )
|
||||
continue;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking against account friendly name" << account->accountFriendlyName();
|
||||
if ( account->accountFriendlyName() == username )
|
||||
{
|
||||
if ( !skipEmission )
|
||||
emit aclResult( dbid, username, ACLRegistry::Stream );
|
||||
return ACLRegistry::Stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool found = false;
|
||||
QMutableListIterator< ACLRegistry::User > i( m_cache );
|
||||
while ( i.hasNext() )
|
||||
{
|
||||
ACLRegistry::User user = i.next();
|
||||
foreach ( QString knowndbid, user.knownDbids )
|
||||
{
|
||||
if ( dbid == knowndbid )
|
||||
{
|
||||
if ( !user.knownAccountIds.contains( username ) )
|
||||
user.knownAccountIds.append( username );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( QString knownaccountid, user.knownAccountIds )
|
||||
{
|
||||
if ( username == knownaccountid )
|
||||
{
|
||||
if ( !user.knownDbids.contains( dbid ) )
|
||||
user.knownDbids.append( dbid );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( found )
|
||||
{
|
||||
if ( !skipEmission )
|
||||
emit aclResult( dbid, username, user.acl );
|
||||
i.setValue( user );
|
||||
return user.acl;
|
||||
}
|
||||
}
|
||||
|
||||
if ( skipEmission )
|
||||
return ACLRegistry::NotFound;
|
||||
|
||||
// User was not found, create a new user entry
|
||||
ACLRegistry::User user;
|
||||
user.knownDbids.append( dbid );
|
||||
user.knownAccountIds.append( username );
|
||||
if ( globalType != ACLRegistry::NotFound )
|
||||
user.acl = globalType;
|
||||
#ifdef ENABLE_HEADLESS
|
||||
user.acl = ACLRegistry::Stream;
|
||||
#else
|
||||
if ( !TomahawkUtils::headless() )
|
||||
{
|
||||
getUserDecision( user, username );
|
||||
return ACLRegistry::NotFound;
|
||||
}
|
||||
else
|
||||
user.acl = ACLRegistry::Stream;
|
||||
#endif
|
||||
|
||||
m_cache.append( user );
|
||||
save();
|
||||
emit aclResult( dbid, username, user.acl );
|
||||
return user.acl;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
|
||||
void
|
||||
ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username )
|
||||
{
|
||||
if ( TomahawkUtils::headless() )
|
||||
return;
|
||||
|
||||
tLog() << Q_FUNC_INFO;
|
||||
AclJobItem* job = new AclJobItem( user, username );
|
||||
m_jobQueue.enqueue( job );
|
||||
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::userDecision( ACLRegistry::User user )
|
||||
{
|
||||
if ( TomahawkUtils::headless() )
|
||||
return;
|
||||
|
||||
tLog() << Q_FUNC_INFO;
|
||||
m_cache.append( user );
|
||||
save();
|
||||
emit aclResult( user.knownDbids.first(), user.knownAccountIds.first(), user.acl );
|
||||
|
||||
m_jobCount--;
|
||||
if ( !m_jobQueue.isEmpty() )
|
||||
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::queueNextJob()
|
||||
{
|
||||
if ( TomahawkUtils::headless() )
|
||||
return;
|
||||
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "queueNextJob", Qt::QueuedConnection );
|
||||
return;
|
||||
}
|
||||
tLog() << Q_FUNC_INFO << "jobCount = " << m_jobCount;
|
||||
tLog() << Q_FUNC_INFO << "jobQueue size = " << m_jobQueue.length();
|
||||
if ( m_jobCount != 0 )
|
||||
return;
|
||||
|
||||
if ( !m_jobQueue.isEmpty() )
|
||||
{
|
||||
AclJobItem* job = m_jobQueue.dequeue();
|
||||
ACLRegistry::User user = job->user();
|
||||
bool found = false;
|
||||
foreach( QString dbid, user.knownDbids )
|
||||
{
|
||||
ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true );
|
||||
if ( acl != ACLRegistry::NotFound )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Found existing acl entry for = " << user.knownAccountIds.first();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( found )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "deleting job, already have ACL for " << user.knownAccountIds.first();
|
||||
delete job;
|
||||
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "activating job for user" << user.knownAccountIds.first();
|
||||
m_jobCount++;
|
||||
JobStatusView::instance()->model()->addJob( job );
|
||||
connect( job, SIGNAL( userDecision( ACLRegistry::User ) ), this, SLOT( userDecision( ACLRegistry::User ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::load()
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
QVariantList entryList = TomahawkSettings::instance()->aclEntries();
|
||||
foreach ( QVariant entry, entryList )
|
||||
{
|
||||
if ( !entry.isValid() || !entry.canConvert< ACLRegistry::User >() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "entry is invalid";
|
||||
continue;
|
||||
}
|
||||
tLog() << Q_FUNC_INFO << "loading entry";
|
||||
ACLRegistry::User entryUser = entry.value< ACLRegistry::User >();
|
||||
if ( entryUser.knownAccountIds.empty() || entryUser.knownDbids.empty() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "user known account/dbids is empty";
|
||||
continue;
|
||||
}
|
||||
m_cache.append( entryUser );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::save()
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
QVariantList entryList;
|
||||
foreach ( ACLRegistry::User user, m_cache )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "user is " << user.uuid << " with known name " << user.knownAccountIds.first();
|
||||
QVariant val = QVariant::fromValue< ACLRegistry::User >( user );
|
||||
if ( val.isValid() )
|
||||
entryList.append( val );
|
||||
}
|
||||
TomahawkSettings::instance()->setAclEntries( entryList );
|
||||
}
|
||||
|
||||
|
||||
@@ -334,5 +119,5 @@ ACLRegistry::wipeEntries()
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
m_cache.clear();
|
||||
save();
|
||||
}
|
||||
|
||||
|
@@ -35,8 +35,6 @@
|
||||
|
||||
#define ACLUSERVERSION 1
|
||||
|
||||
class AclJobItem;
|
||||
|
||||
class DLLEXPORT ACLRegistry : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -44,6 +42,7 @@ class DLLEXPORT ACLRegistry : public QObject
|
||||
public:
|
||||
|
||||
static ACLRegistry* instance();
|
||||
static void setInstance( ACLRegistry* instance );
|
||||
|
||||
enum ACL {
|
||||
NotFound = 0,
|
||||
@@ -88,7 +87,7 @@ public:
|
||||
};
|
||||
|
||||
ACLRegistry( QObject *parent = 0 );
|
||||
~ACLRegistry();
|
||||
virtual ~ACLRegistry();
|
||||
|
||||
signals:
|
||||
void aclResult( QString nodeid, QString username, ACLRegistry::ACL peerStatus );
|
||||
@@ -102,33 +101,21 @@ public slots:
|
||||
* @param username If not empty, will store the given username along with the new ACL value. Defaults to QString().
|
||||
* @return ACLRegistry::ACL
|
||||
**/
|
||||
ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false );
|
||||
void wipeEntries();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
void getUserDecision( ACLRegistry::User user, const QString &username );
|
||||
|
||||
private slots:
|
||||
void userDecision( ACLRegistry::User user );
|
||||
void queueNextJob();
|
||||
#endif
|
||||
virtual ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false ) = 0;
|
||||
virtual void wipeEntries();
|
||||
|
||||
private:
|
||||
protected:
|
||||
/**
|
||||
* @brief Saves the cache.
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
void save();
|
||||
|
||||
void load();
|
||||
virtual void save();
|
||||
virtual void load();
|
||||
|
||||
QList< ACLRegistry::User > m_cache;
|
||||
|
||||
static ACLRegistry* s_instance;
|
||||
|
||||
QQueue< AclJobItem* > m_jobQueue;
|
||||
int m_jobCount;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE( ACLRegistry::ACL );
|
||||
|
@@ -23,21 +23,28 @@
|
||||
#include "AlbumPlaylistInterface.h"
|
||||
#include "database/Database.h"
|
||||
#include "database/DatabaseImpl.h"
|
||||
#include "database/IdThreadWorker.h"
|
||||
#include "Query.h"
|
||||
#include "Source.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
QHash< QString, album_ptr > Album::s_albumsByName = QHash< QString, album_ptr >();
|
||||
QHash< unsigned int, album_ptr > Album::s_albumsById = QHash< unsigned int, album_ptr >();
|
||||
QHash< QString, album_ptr > Album::s_albumsByCoverId = QHash< QString, album_ptr >();
|
||||
|
||||
Album::~Album()
|
||||
static QMutex s_mutex;
|
||||
static QReadWriteLock s_idMutex;
|
||||
|
||||
|
||||
inline QString
|
||||
albumCacheKey( const Tomahawk::artist_ptr& artist, const QString& albumName )
|
||||
{
|
||||
m_ownRef.clear();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
delete m_cover;
|
||||
#endif
|
||||
return QString( "%1\t\t%2" ).arg( artist->name() ).arg( albumName );
|
||||
}
|
||||
|
||||
|
||||
@@ -47,11 +54,23 @@ Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCr
|
||||
if ( !Database::instance() || !Database::instance()->impl() )
|
||||
return album_ptr();
|
||||
|
||||
int albid = Database::instance()->impl()->albumId( artist->id(), name, autoCreate );
|
||||
if ( albid < 1 && autoCreate )
|
||||
return album_ptr();
|
||||
QMutexLocker l( &s_mutex );
|
||||
|
||||
return Album::get( albid, name, artist );
|
||||
const QString key = albumCacheKey( artist, name );
|
||||
if ( s_albumsByName.contains( key ) )
|
||||
{
|
||||
return s_albumsByName[ key ];
|
||||
}
|
||||
|
||||
// qDebug() << "LOOKING UP ALBUM:" << artist->name() << name;
|
||||
album_ptr album = album_ptr( new Album( name, artist ) );
|
||||
album->setWeakRef( album.toWeakRef() );
|
||||
album->loadId( autoCreate );
|
||||
|
||||
s_albumsByCoverId[ album->coverId() ] = album;
|
||||
s_albumsByName[ key ] = album;
|
||||
|
||||
return album;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,26 +78,40 @@ album_ptr
|
||||
Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist )
|
||||
{
|
||||
static QHash< unsigned int, album_ptr > s_albums;
|
||||
static QMutex s_mutex;
|
||||
|
||||
QMutexLocker lock( &s_mutex );
|
||||
if ( s_albums.contains( id ) )
|
||||
if ( s_albumsById.contains( id ) )
|
||||
{
|
||||
return s_albums.value( id );
|
||||
return s_albumsById.value( id );
|
||||
}
|
||||
|
||||
album_ptr a = album_ptr( new Album( id, name, artist ), &QObject::deleteLater );
|
||||
a->setWeakRef( a.toWeakRef() );
|
||||
|
||||
s_albumsByCoverId[ a->coverId() ] = a;
|
||||
s_albumsByName[ albumCacheKey( artist, name ) ] = a;
|
||||
if ( id > 0 )
|
||||
s_albums.insert( id, a );
|
||||
s_albumsById.insert( id, a );
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
album_ptr
|
||||
Album::getByCoverId( const QString& uuid )
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
|
||||
if ( s_albumsByCoverId.contains( uuid ) )
|
||||
return s_albumsByCoverId.value( uuid );
|
||||
|
||||
return album_ptr();
|
||||
}
|
||||
|
||||
|
||||
Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist )
|
||||
: QObject()
|
||||
, m_waitingForId( false )
|
||||
, m_id( id )
|
||||
, m_name( name )
|
||||
, m_artist( artist )
|
||||
@@ -92,6 +125,37 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr&
|
||||
}
|
||||
|
||||
|
||||
Album::Album( const QString& name, const Tomahawk::artist_ptr& artist )
|
||||
: QObject()
|
||||
, m_waitingForId( true )
|
||||
, m_name( name )
|
||||
, m_artist( artist )
|
||||
, m_coverLoaded( false )
|
||||
, m_coverLoading( false )
|
||||
#ifndef ENABLE_HEADLESS
|
||||
, m_cover( 0 )
|
||||
#endif
|
||||
{
|
||||
m_sortname = DatabaseImpl::sortname( name );
|
||||
}
|
||||
|
||||
|
||||
Album::~Album()
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
s_albumsByName.remove( albumCacheKey( artist(), name() ) );
|
||||
s_albumsByCoverId.remove( coverId() );
|
||||
/* if ( id() > 0 )
|
||||
s_albumsById.remove( id() );*/
|
||||
|
||||
m_ownRef.clear();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
delete m_cover;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Album::onTracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
@@ -106,6 +170,50 @@ Album::artist() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Album::loadId( bool autoCreate )
|
||||
{
|
||||
Q_ASSERT( m_waitingForId );
|
||||
IdThreadWorker::getAlbumId( m_ownRef.toStrongRef(), autoCreate );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Album::setIdFuture( QFuture<unsigned int> future )
|
||||
{
|
||||
m_idFuture = future;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
Album::id() const
|
||||
{
|
||||
s_idMutex.lockForRead();
|
||||
const bool waiting = m_waitingForId;
|
||||
unsigned int finalId = m_id;
|
||||
s_idMutex.unlock();
|
||||
|
||||
if ( waiting )
|
||||
{
|
||||
finalId = m_idFuture.result();
|
||||
|
||||
s_idMutex.lockForWrite();
|
||||
m_id = finalId;
|
||||
m_waitingForId = false;
|
||||
|
||||
if ( m_id > 0 )
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
s_albumsById[ m_id ] = m_ownRef.toStrongRef();
|
||||
}
|
||||
|
||||
s_idMutex.unlock();
|
||||
}
|
||||
|
||||
return finalId;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap
|
||||
Album::cover( const QSize& size, bool forceLoad ) const
|
||||
@@ -120,7 +228,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
|
||||
trackInfo["album"] = name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = infoid();
|
||||
requestData.caller = uniqueId();
|
||||
requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt;
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
|
||||
requestData.customData = QVariantMap();
|
||||
@@ -168,7 +276,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
|
||||
void
|
||||
Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, const QVariant& output )
|
||||
{
|
||||
if ( requestData.caller != infoid() ||
|
||||
if ( requestData.caller != uniqueId() ||
|
||||
requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt )
|
||||
{
|
||||
return;
|
||||
@@ -187,7 +295,13 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
|
||||
m_coverBuffer = ba;
|
||||
}
|
||||
|
||||
m_coverLoaded = true;
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
m_coverLoaded = true;
|
||||
s_albumsByCoverId.remove( coverId() );
|
||||
m_coverId = uuid();
|
||||
s_albumsByCoverId[ m_coverId ] = m_ownRef.toStrongRef();
|
||||
}
|
||||
emit coverChanged();
|
||||
}
|
||||
}
|
||||
@@ -196,7 +310,7 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
|
||||
void
|
||||
Album::infoSystemFinished( const QString& target )
|
||||
{
|
||||
if ( target != infoid() )
|
||||
if ( target != uniqueId() )
|
||||
return;
|
||||
|
||||
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
@@ -237,10 +351,20 @@ Album::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection )
|
||||
|
||||
|
||||
QString
|
||||
Album::infoid() const
|
||||
Album::uniqueId() const
|
||||
{
|
||||
if ( m_uuid.isEmpty() )
|
||||
m_uuid = uuid();
|
||||
|
||||
return m_uuid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
Album::coverId() const
|
||||
{
|
||||
if ( m_coverId.isEmpty() )
|
||||
m_coverId = uuid();
|
||||
|
||||
return m_coverId;
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include <QtGui/QPixmap>
|
||||
#endif
|
||||
#include <QFuture>
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "PlaylistInterface.h"
|
||||
@@ -34,6 +35,8 @@
|
||||
#include "Collection.h"
|
||||
#include "infosystem/InfoSystem.h"
|
||||
|
||||
class IdThreadWorker;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
@@ -44,13 +47,17 @@ Q_OBJECT
|
||||
public:
|
||||
static album_ptr get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCreate = false );
|
||||
static album_ptr get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
|
||||
static album_ptr getByCoverId( const QString& uuid );
|
||||
|
||||
explicit Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
|
||||
Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
|
||||
Album( const QString& name, const Tomahawk::artist_ptr& artist );
|
||||
virtual ~Album();
|
||||
|
||||
unsigned int id() const { return m_id; }
|
||||
unsigned int id() const;
|
||||
QString name() const { return m_name; }
|
||||
QString sortname() const { return m_sortname; }
|
||||
QString uniqueId() const;
|
||||
QString coverId() const;
|
||||
|
||||
artist_ptr artist() const;
|
||||
#ifndef ENABLE_HEADLESS
|
||||
@@ -64,6 +71,7 @@ public:
|
||||
QWeakPointer< Tomahawk::Album > weakRef() { return m_ownRef; }
|
||||
void setWeakRef( QWeakPointer< Tomahawk::Album > weakRef ) { m_ownRef = weakRef; }
|
||||
|
||||
void loadId( bool autoCreate );
|
||||
signals:
|
||||
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
|
||||
void updated();
|
||||
@@ -77,9 +85,11 @@ private slots:
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( Album )
|
||||
QString infoid() const;
|
||||
void setIdFuture( QFuture<unsigned int> future );
|
||||
|
||||
unsigned int m_id;
|
||||
mutable bool m_waitingForId;
|
||||
mutable QFuture<unsigned int> m_idFuture;
|
||||
mutable unsigned int m_id;
|
||||
QString m_name;
|
||||
QString m_sortname;
|
||||
|
||||
@@ -89,6 +99,7 @@ private:
|
||||
bool m_coverLoaded;
|
||||
mutable bool m_coverLoading;
|
||||
mutable QString m_uuid;
|
||||
mutable QString m_coverId;
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
mutable QPixmap* m_cover;
|
||||
@@ -98,6 +109,12 @@ private:
|
||||
QHash< Tomahawk::ModelMode, QHash< Tomahawk::collection_ptr, Tomahawk::playlistinterface_ptr > > m_playlistInterface;
|
||||
|
||||
QWeakPointer< Tomahawk::Album > m_ownRef;
|
||||
|
||||
static QHash< QString, album_ptr > s_albumsByName;
|
||||
static QHash< unsigned int, album_ptr > s_albumsById;
|
||||
static QHash< QString, album_ptr > s_albumsByCoverId;
|
||||
|
||||
friend class ::IdThreadWorker;
|
||||
};
|
||||
|
||||
} // ns
|
||||
|
@@ -92,6 +92,31 @@ AlbumPlaylistInterface::hasNextItem()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AlbumPlaylistInterface::hasPreviousItem()
|
||||
{
|
||||
int p = m_currentTrack;
|
||||
p--;
|
||||
if ( p < 0 || p >= m_queries.count() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AlbumPlaylistInterface::setCurrentTrack( unsigned int albumpos )
|
||||
{
|
||||
albumpos--;
|
||||
if ( albumpos >= m_queries.count() )
|
||||
return false;
|
||||
|
||||
m_currentTrack = albumpos;
|
||||
m_currentItem = m_queries.at( albumpos )->results().first();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QList< Tomahawk::query_ptr >
|
||||
AlbumPlaylistInterface::tracks()
|
||||
{
|
||||
@@ -114,6 +139,10 @@ AlbumPlaylistInterface::tracks()
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( finished( QString ) ),
|
||||
SLOT( infoSystemFinished( QString ) ) );
|
||||
}
|
||||
else if ( m_mode == DatabaseMode && !m_databaseLoaded )
|
||||
{
|
||||
@@ -178,9 +207,24 @@ AlbumPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData re
|
||||
}
|
||||
}
|
||||
|
||||
if ( !m_queries.isEmpty() )
|
||||
{
|
||||
infoSystemFinished( id() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumPlaylistInterface::infoSystemFinished( const QString& infoId )
|
||||
{
|
||||
if ( infoId != id() )
|
||||
return;
|
||||
|
||||
m_infoSystemLoaded = true;
|
||||
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ),
|
||||
this, SLOT( infoSystemFinished( QString ) ) );
|
||||
|
||||
if ( m_queries.isEmpty() && m_mode == Mixed )
|
||||
{
|
||||
|
@@ -43,11 +43,11 @@ public:
|
||||
QList<Tomahawk::query_ptr> tracks();
|
||||
|
||||
virtual int trackCount() const { return m_queries.count(); }
|
||||
virtual int unfilteredTrackCount() const { return m_queries.count(); }
|
||||
|
||||
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
|
||||
|
||||
virtual bool hasNextItem();
|
||||
virtual bool hasPreviousItem();
|
||||
virtual Tomahawk::result_ptr currentItem() const;
|
||||
|
||||
virtual PlaylistModes::RepeatMode repeatMode() const { return PlaylistModes::NoRepeat; }
|
||||
@@ -55,8 +55,7 @@ public:
|
||||
|
||||
virtual void setRepeatMode( PlaylistModes::RepeatMode ) {}
|
||||
virtual void setShuffled( bool ) {}
|
||||
|
||||
virtual void setFilter( const QString& /*pattern*/ ) {}
|
||||
virtual bool setCurrentTrack( unsigned int albumpos );
|
||||
|
||||
signals:
|
||||
void tracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
|
||||
@@ -64,6 +63,7 @@ signals:
|
||||
private slots:
|
||||
void onTracksLoaded( const QList< Tomahawk::query_ptr >& tracks );
|
||||
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
void infoSystemFinished( const QString& infoId );
|
||||
|
||||
private:
|
||||
QList< Tomahawk::query_ptr > m_queries;
|
||||
|
@@ -25,61 +25,88 @@
|
||||
#include "database/DatabaseImpl.h"
|
||||
#include "database/DatabaseCommand_AllAlbums.h"
|
||||
#include "database/DatabaseCommand_TrackStats.h"
|
||||
#include "database/IdThreadWorker.h"
|
||||
#include "Source.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#define ID_THREAD_DEBUG 0
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
QHash< QString, artist_ptr > Artist::s_artistsByName = QHash< QString, artist_ptr >();
|
||||
QHash< unsigned int, artist_ptr > Artist::s_artistsById = QHash< unsigned int, artist_ptr >();
|
||||
QHash< QString, artist_ptr > Artist::s_artistsByCoverId = QHash< QString, artist_ptr >();
|
||||
|
||||
Artist::~Artist()
|
||||
{
|
||||
m_ownRef.clear();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
delete m_cover;
|
||||
#endif
|
||||
}
|
||||
static QMutex s_mutex;
|
||||
static QReadWriteLock s_idMutex;
|
||||
|
||||
|
||||
artist_ptr
|
||||
Artist::get( const QString& name, bool autoCreate )
|
||||
{
|
||||
if ( name.isEmpty() )
|
||||
return artist_ptr();
|
||||
|
||||
QMutexLocker lock( &s_mutex );
|
||||
if ( s_artistsByName.contains( name ) )
|
||||
return s_artistsByName.value( name );
|
||||
|
||||
if ( !Database::instance() || !Database::instance()->impl() )
|
||||
return artist_ptr();
|
||||
|
||||
int artid = Database::instance()->impl()->artistId( name, autoCreate );
|
||||
if ( artid < 1 && autoCreate )
|
||||
return artist_ptr();
|
||||
#if ID_THREAD_DEBUG
|
||||
qDebug() << "Creating artist:" << name;
|
||||
#endif
|
||||
artist_ptr artist = artist_ptr( new Artist( name ), &QObject::deleteLater );
|
||||
artist->setWeakRef( artist.toWeakRef() );
|
||||
artist->loadId( autoCreate );
|
||||
|
||||
return Artist::get( artid, name );
|
||||
s_artistsByCoverId[ artist->coverId() ] = artist;
|
||||
s_artistsByName[ name ] = artist;
|
||||
|
||||
return artist;
|
||||
}
|
||||
|
||||
|
||||
artist_ptr
|
||||
Artist::get( unsigned int id, const QString& name )
|
||||
{
|
||||
static QHash< unsigned int, artist_ptr > s_artists;
|
||||
static QMutex s_mutex;
|
||||
|
||||
QMutexLocker lock( &s_mutex );
|
||||
if ( s_artists.contains( id ) )
|
||||
if ( s_artistsById.contains( id ) )
|
||||
{
|
||||
return s_artists.value( id );
|
||||
return s_artistsById.value( id );
|
||||
}
|
||||
|
||||
artist_ptr a = artist_ptr( new Artist( id, name ), &QObject::deleteLater );
|
||||
a->setWeakRef( a.toWeakRef() );
|
||||
|
||||
s_artistsByCoverId[ a->coverId() ] = a;
|
||||
s_artistsByName[ name ] = a;
|
||||
if ( id > 0 )
|
||||
s_artists.insert( id, a );
|
||||
s_artistsById.insert( id, a );
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
artist_ptr
|
||||
Artist::getByCoverId( const QString& uuid )
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
|
||||
if ( s_artistsByCoverId.contains( uuid ) )
|
||||
return s_artistsByCoverId.value( uuid );
|
||||
|
||||
return artist_ptr();
|
||||
}
|
||||
|
||||
|
||||
Artist::Artist( unsigned int id, const QString& name )
|
||||
: QObject()
|
||||
, m_waitingForFuture( false )
|
||||
, m_id( id )
|
||||
, m_name( name )
|
||||
, m_coverLoaded( false )
|
||||
@@ -95,6 +122,40 @@ Artist::Artist( unsigned int id, const QString& name )
|
||||
}
|
||||
|
||||
|
||||
Artist::Artist( const QString& name )
|
||||
: QObject()
|
||||
, m_waitingForFuture( true )
|
||||
, m_id( 0 )
|
||||
, m_name( name )
|
||||
, m_coverLoaded( false )
|
||||
, m_coverLoading( false )
|
||||
, m_simArtistsLoaded( false )
|
||||
, m_biographyLoaded( false )
|
||||
, m_infoJobs( 0 )
|
||||
#ifndef ENABLE_HEADLESS
|
||||
, m_cover( 0 )
|
||||
#endif
|
||||
{
|
||||
m_sortname = DatabaseImpl::sortname( name, true );
|
||||
}
|
||||
|
||||
|
||||
Artist::~Artist()
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
s_artistsByName.remove( name() );
|
||||
s_artistsByCoverId.remove( coverId() );
|
||||
/* if ( id() > 0 )
|
||||
s_artistsById.remove( id() );*/
|
||||
|
||||
m_ownRef.clear();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
delete m_cover;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Artist::onTracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
@@ -129,7 +190,7 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con
|
||||
artistInfo["artist"] = name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = infoid();
|
||||
requestData.caller = uniqueId();
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
|
||||
requestData.type = Tomahawk::InfoSystem::InfoArtistReleases;
|
||||
|
||||
@@ -169,7 +230,7 @@ Artist::similarArtists() const
|
||||
artistInfo["artist"] = name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = infoid();
|
||||
requestData.caller = uniqueId();
|
||||
requestData.customData = QVariantMap();
|
||||
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
|
||||
@@ -192,13 +253,70 @@ Artist::similarArtists() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Artist::loadId( bool autoCreate )
|
||||
{
|
||||
Q_ASSERT( m_waitingForFuture );
|
||||
|
||||
IdThreadWorker::getArtistId( m_ownRef.toStrongRef(), autoCreate );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Artist::setIdFuture( QFuture<unsigned int> future )
|
||||
{
|
||||
m_idFuture = future;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
Artist::id() const
|
||||
{
|
||||
s_idMutex.lockForRead();
|
||||
const bool waiting = m_waitingForFuture;
|
||||
unsigned int finalid = m_id;
|
||||
s_idMutex.unlock();
|
||||
|
||||
if ( waiting )
|
||||
{
|
||||
|
||||
#if ID_THREAD_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << "Asked for artist ID and NOT loaded yet" << m_name << m_idFuture.isFinished();
|
||||
#endif
|
||||
m_idFuture.waitForFinished();
|
||||
#if ID_THREAD_DEBUG
|
||||
qDebug() << "DONE WAITING:" << m_idFuture.resultCount() << m_idFuture.isResultReadyAt(0) << m_idFuture.isCanceled() << m_idFuture.isFinished() << m_idFuture.isPaused() << m_idFuture.isRunning() << m_idFuture.isStarted();
|
||||
#endif
|
||||
finalid = m_idFuture.result();
|
||||
|
||||
#if ID_THREAD_DEBUG
|
||||
qDebug() << Q_FUNC_INFO << "Got loaded artist:" << m_name << finalid;
|
||||
#endif
|
||||
|
||||
s_idMutex.lockForWrite();
|
||||
m_id = finalid;
|
||||
m_waitingForFuture = false;
|
||||
|
||||
if ( m_id > 0 )
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
s_artistsById[ m_id ] = m_ownRef.toStrongRef();
|
||||
}
|
||||
|
||||
s_idMutex.unlock();
|
||||
}
|
||||
|
||||
return m_id;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
Artist::biography() const
|
||||
{
|
||||
if ( !m_biographyLoaded )
|
||||
{
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = infoid();
|
||||
requestData.caller = uniqueId();
|
||||
requestData.customData = QVariantMap();
|
||||
|
||||
requestData.input = name();
|
||||
@@ -286,7 +404,7 @@ Artist::onAlbumsFound( const QList< album_ptr >& albums, const QVariant& data )
|
||||
void
|
||||
Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
|
||||
{
|
||||
if ( requestData.caller != infoid() )
|
||||
if ( requestData.caller != uniqueId() )
|
||||
return;
|
||||
|
||||
QVariantMap returnedData = output.value< QVariantMap >();
|
||||
@@ -327,7 +445,13 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
|
||||
m_coverBuffer = ba;
|
||||
}
|
||||
|
||||
m_coverLoaded = true;
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
m_coverLoaded = true;
|
||||
s_artistsByCoverId.remove( coverId() );
|
||||
m_coverId = uuid();
|
||||
s_artistsByCoverId[ m_coverId ] = m_ownRef.toStrongRef();
|
||||
}
|
||||
emit coverChanged();
|
||||
}
|
||||
|
||||
@@ -375,7 +499,7 @@ Artist::infoSystemFinished( QString target )
|
||||
{
|
||||
Q_UNUSED( target );
|
||||
|
||||
if ( target != infoid() )
|
||||
if ( target != uniqueId() )
|
||||
return;
|
||||
|
||||
if ( --m_infoJobs == 0 )
|
||||
@@ -406,7 +530,7 @@ Artist::cover( const QSize& size, bool forceLoad ) const
|
||||
trackInfo["artist"] = name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = infoid();
|
||||
requestData.caller = uniqueId();
|
||||
requestData.type = Tomahawk::InfoSystem::InfoArtistImages;
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
|
||||
requestData.customData = QVariantMap();
|
||||
@@ -479,10 +603,20 @@ Artist::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection )
|
||||
|
||||
|
||||
QString
|
||||
Artist::infoid() const
|
||||
Artist::uniqueId() const
|
||||
{
|
||||
if ( m_uuid.isEmpty() )
|
||||
m_uuid = uuid();
|
||||
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
Artist::coverId() const
|
||||
{
|
||||
if ( m_coverId.isEmpty() )
|
||||
m_coverId = uuid();
|
||||
|
||||
return m_coverId;
|
||||
}
|
||||
|
@@ -27,10 +27,15 @@
|
||||
#include <QtGui/QPixmap>
|
||||
#endif
|
||||
|
||||
#include <QFuture>
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "DllMacro.h"
|
||||
#include "Query.h"
|
||||
|
||||
|
||||
class IdThreadWorker;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
@@ -41,13 +46,17 @@ Q_OBJECT
|
||||
public:
|
||||
static artist_ptr get( const QString& name, bool autoCreate = false );
|
||||
static artist_ptr get( unsigned int id, const QString& name );
|
||||
static artist_ptr getByCoverId( const QString& uuid );
|
||||
|
||||
explicit Artist( unsigned int id, const QString& name );
|
||||
Artist( unsigned int id, const QString& name );
|
||||
explicit Artist( const QString& name );
|
||||
virtual ~Artist();
|
||||
|
||||
unsigned int id() const { return m_id; }
|
||||
unsigned int id() const;
|
||||
QString name() const { return m_name; }
|
||||
QString sortname() const { return m_sortname; }
|
||||
QString uniqueId() const;
|
||||
QString coverId() const;
|
||||
|
||||
QList<Tomahawk::album_ptr> albums( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ) const;
|
||||
QList<Tomahawk::artist_ptr> similarArtists() const;
|
||||
@@ -59,7 +68,7 @@ public:
|
||||
QList< Tomahawk::PlaybackLog > playbackHistory( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ) const;
|
||||
void setPlaybackHistory( const QList< Tomahawk::PlaybackLog >& playbackData );
|
||||
unsigned int playbackCount( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() );
|
||||
|
||||
|
||||
QString biography() const;
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
@@ -72,6 +81,7 @@ public:
|
||||
QWeakPointer< Tomahawk::Artist > weakRef() { return m_ownRef; }
|
||||
void setWeakRef( QWeakPointer< Tomahawk::Artist > weakRef ) { m_ownRef = weakRef; }
|
||||
|
||||
void loadId( bool autoCreate );
|
||||
signals:
|
||||
void tracksAdded( const QList<Tomahawk::query_ptr>& tracks, Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
|
||||
void albumsAdded( const QList<Tomahawk::album_ptr>& albums, Tomahawk::ModelMode mode );
|
||||
@@ -91,9 +101,13 @@ private slots:
|
||||
|
||||
private:
|
||||
Artist();
|
||||
QString infoid() const;
|
||||
|
||||
unsigned int m_id;
|
||||
void setIdFuture( QFuture<unsigned int> idFuture );
|
||||
|
||||
mutable bool m_waitingForFuture;
|
||||
mutable QFuture<unsigned int> m_idFuture;
|
||||
mutable unsigned int m_id;
|
||||
|
||||
QString m_name;
|
||||
QString m_sortname;
|
||||
|
||||
@@ -104,6 +118,7 @@ private:
|
||||
bool m_biographyLoaded;
|
||||
|
||||
mutable QString m_uuid;
|
||||
mutable QString m_coverId;
|
||||
mutable int m_infoJobs;
|
||||
|
||||
QList<Tomahawk::album_ptr> m_databaseAlbums;
|
||||
@@ -121,8 +136,14 @@ private:
|
||||
#endif
|
||||
|
||||
QHash< Tomahawk::ModelMode, QHash< Tomahawk::collection_ptr, Tomahawk::playlistinterface_ptr > > m_playlistInterface;
|
||||
|
||||
|
||||
QWeakPointer< Tomahawk::Artist > m_ownRef;
|
||||
|
||||
static QHash< QString, artist_ptr > s_artistsByName;
|
||||
static QHash< unsigned int, artist_ptr > s_artistsById;
|
||||
static QHash< QString, artist_ptr > s_artistsByCoverId;
|
||||
|
||||
friend class ::IdThreadWorker;
|
||||
};
|
||||
|
||||
} // ns
|
||||
|
@@ -112,6 +112,10 @@ ArtistPlaylistInterface::tracks()
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( finished( QString ) ),
|
||||
SLOT( infoSystemFinished( QString ) ) );
|
||||
}
|
||||
else if ( m_mode == DatabaseMode && !m_databaseLoaded )
|
||||
{
|
||||
@@ -176,9 +180,23 @@ ArtistPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData r
|
||||
}
|
||||
}
|
||||
|
||||
if ( !m_queries.isEmpty() )
|
||||
infoSystemFinished( id() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ArtistPlaylistInterface::infoSystemFinished( const QString &infoId )
|
||||
{
|
||||
if ( infoId != id() )
|
||||
return;
|
||||
|
||||
m_infoSystemLoaded = true;
|
||||
|
||||
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ),
|
||||
this, SLOT( infoSystemFinished( QString) ) );
|
||||
|
||||
if ( m_queries.isEmpty() && m_mode == Mixed )
|
||||
{
|
||||
|
@@ -42,7 +42,6 @@ public:
|
||||
virtual QList<Tomahawk::query_ptr> tracks();
|
||||
|
||||
virtual int trackCount() const { return m_queries.count(); }
|
||||
virtual int unfilteredTrackCount() const { return m_queries.count(); }
|
||||
|
||||
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
|
||||
|
||||
@@ -55,14 +54,13 @@ public:
|
||||
virtual void setRepeatMode( PlaylistModes::RepeatMode ) {}
|
||||
virtual void setShuffled( bool ) {}
|
||||
|
||||
virtual void setFilter( const QString& /*pattern*/ ) {}
|
||||
|
||||
signals:
|
||||
void tracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection );
|
||||
|
||||
private slots:
|
||||
void onTracksLoaded( const QList< Tomahawk::query_ptr >& tracks );
|
||||
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
void infoSystemFinished( const QString& infoId );
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( ArtistPlaylistInterface )
|
||||
|
@@ -48,6 +48,8 @@ set( libGuiSources
|
||||
|
||||
infobar/InfoBar.cpp
|
||||
|
||||
playlist/FlexibleHeader.cpp
|
||||
playlist/FlexibleView.cpp
|
||||
playlist/TreeModel.cpp
|
||||
playlist/TreeProxyModel.cpp
|
||||
playlist/TreeProxyModelPlaylistInterface.cpp
|
||||
@@ -65,13 +67,14 @@ set( libGuiSources
|
||||
playlist/GridItemDelegate.cpp
|
||||
playlist/GridView.cpp
|
||||
playlist/TreeView.cpp
|
||||
playlist/CustomPlaylistView.cpp
|
||||
playlist/ViewHeader.cpp
|
||||
playlist/LovedTracksModel.cpp
|
||||
playlist/RecentlyAddedModel.cpp
|
||||
playlist/RecentlyPlayedModel.cpp
|
||||
playlist/PlaylistLargeItemDelegate.cpp
|
||||
playlist/PlaylistChartItemDelegate.cpp
|
||||
playlist/PlayableItem.cpp
|
||||
playlist/SingleTrackPlaylistInterface.h
|
||||
|
||||
playlist/dynamic/DynamicPlaylist.cpp
|
||||
playlist/dynamic/DynamicView.cpp
|
||||
@@ -79,7 +82,9 @@ set( libGuiSources
|
||||
playlist/dynamic/echonest/EchonestGenerator.cpp
|
||||
playlist/dynamic/echonest/EchonestControl.cpp
|
||||
playlist/dynamic/echonest/EchonestSteerer.cpp
|
||||
playlist/dynamic/echonest/EchonestStation.cpp
|
||||
playlist/dynamic/widgets/DynamicWidget.cpp
|
||||
playlist/dynamic/widgets/DynamicQmlWidget.cpp
|
||||
playlist/dynamic/widgets/DynamicControlWrapper.cpp
|
||||
playlist/dynamic/widgets/DynamicControlList.cpp
|
||||
playlist/dynamic/widgets/ReadOrWriteWidget.cpp
|
||||
@@ -87,12 +92,6 @@ set( libGuiSources
|
||||
playlist/dynamic/widgets/CollapsibleControls.cpp
|
||||
playlist/dynamic/widgets/DynamicSetupWidget.cpp
|
||||
|
||||
playlist/topbar/TopBar.cpp
|
||||
playlist/topbar/ClearButton.cpp
|
||||
playlist/topbar/SearchLineEdit.cpp
|
||||
playlist/topbar/LineEdit.cpp
|
||||
playlist/topbar/SearchButton.cpp
|
||||
|
||||
ExternalResolverGui.cpp
|
||||
resolvers/ScriptResolver.cpp
|
||||
resolvers/QtScriptResolver.cpp
|
||||
@@ -118,6 +117,8 @@ set( libGuiSources
|
||||
utils/SharedTimeLine.cpp
|
||||
|
||||
widgets/AnimatedCounterLabel.cpp
|
||||
widgets/Breadcrumb.cpp
|
||||
widgets/BreadcrumbButton.cpp
|
||||
widgets/CheckDirTree.cpp
|
||||
widgets/QueryLabel.cpp
|
||||
widgets/ImageButton.cpp
|
||||
@@ -141,12 +142,17 @@ set( libGuiSources
|
||||
widgets/ToggleButton.cpp
|
||||
widgets/FadingPixmap.cpp
|
||||
widgets/SocialPlaylistWidget.cpp
|
||||
widgets/DeclarativeCoverArtProvider.cpp
|
||||
widgets/SourceTreePopupDialog.cpp
|
||||
widgets/infowidgets/SourceInfoWidget.cpp
|
||||
widgets/infowidgets/ArtistInfoWidget.cpp
|
||||
widgets/infowidgets/AlbumInfoWidget.cpp
|
||||
widgets/infowidgets/TrackInfoWidget.cpp
|
||||
widgets/Breadcrumb.cpp
|
||||
widgets/BreadcrumbButton.cpp
|
||||
widgets/infowidgets/AlbumArtImageProvider.cpp
|
||||
widgets/searchlineedit/ClearButton.cpp
|
||||
widgets/searchlineedit/LineEdit.cpp
|
||||
widgets/searchlineedit/SearchButton.cpp
|
||||
widgets/searchlineedit/SearchLineEdit.cpp
|
||||
)
|
||||
|
||||
IF(QCA2_FOUND)
|
||||
@@ -256,11 +262,23 @@ set( libSources
|
||||
database/DatabaseCommand_SetTrackAttributes.cpp
|
||||
database/Database.cpp
|
||||
database/TomahawkSqlQuery.cpp
|
||||
database/IdThreadWorker.cpp
|
||||
|
||||
infosystem/InfoSystem.cpp
|
||||
infosystem/InfoSystemCache.cpp
|
||||
infosystem/InfoSystemWorker.cpp
|
||||
|
||||
filemetadata/MusicScanner.cpp
|
||||
filemetadata/ScanManager.cpp
|
||||
filemetadata/taghandlers/tag.cpp
|
||||
filemetadata/taghandlers/apetag.cpp
|
||||
filemetadata/taghandlers/asftag.cpp
|
||||
filemetadata/taghandlers/id3v1tag.cpp
|
||||
filemetadata/taghandlers/id3v2tag.cpp
|
||||
filemetadata/taghandlers/mp4tag.cpp
|
||||
filemetadata/taghandlers/oggtag.cpp
|
||||
filemetadata/MetadataEditor.cpp
|
||||
|
||||
network/BufferIoDevice.cpp
|
||||
network/MsgProcessor.cpp
|
||||
network/StreamConnection.cpp
|
||||
@@ -281,14 +299,6 @@ set( libSources
|
||||
playlist/dynamic/database/DatabaseControl.cpp
|
||||
playlist/dynamic/DynamicControl.cpp
|
||||
|
||||
taghandlers/tag.cpp
|
||||
taghandlers/apetag.cpp
|
||||
taghandlers/asftag.cpp
|
||||
taghandlers/id3v1tag.cpp
|
||||
taghandlers/id3v2tag.cpp
|
||||
taghandlers/mp4tag.cpp
|
||||
taghandlers/oggtag.cpp
|
||||
|
||||
utils/TomahawkUtils.cpp
|
||||
utils/Logger.cpp
|
||||
utils/Qnr_IoDeviceStream.cpp
|
||||
@@ -314,8 +324,9 @@ set( libUI ${libUI}
|
||||
widgets/infowidgets/ArtistInfoWidget.ui
|
||||
widgets/infowidgets/AlbumInfoWidget.ui
|
||||
widgets/infowidgets/TrackInfoWidget.ui
|
||||
playlist/topbar/TopBar.ui
|
||||
playlist/QueueView.ui
|
||||
playlist/PlaylistHeader.ui
|
||||
filemetadata/MetadataEditor.ui
|
||||
context/ContextWidget.ui
|
||||
infobar/InfoBar.ui
|
||||
accounts/AccountFactoryWrapper.ui
|
||||
@@ -327,8 +338,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${QT_INCLUDE_DIR}
|
||||
${QJSON_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}/..
|
||||
${ECHONEST_INCLUDE_DIR}
|
||||
${LIBLASTFM_INCLUDE_DIRS}
|
||||
${LIBLASTFM_INCLUDE_DIRS}/..
|
||||
${CLUCENE_INCLUDE_DIRS}
|
||||
@@ -385,7 +395,8 @@ IF( APPLE )
|
||||
SET( libSources ${libSources}
|
||||
utils/TomahawkUtils_Mac.mm
|
||||
mac/FileHelpers.mm
|
||||
thirdparty/Qocoa/qsearchfield_mac.mm )
|
||||
thirdparty/Qocoa/qsearchfield_mac.mm
|
||||
widgets/SourceTreePopupDialog_mac.mm )
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(utils/TomahawkUtils_Mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
|
||||
|
||||
@@ -440,7 +451,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
|
||||
${PHONON_LIBS}
|
||||
${TAGLIB_LIBRARIES}
|
||||
${CLUCENE_LIBRARIES}
|
||||
${LIBECHONEST_LIBRARY}
|
||||
${ECHONEST_LIBRARIES}
|
||||
${QT_QTSQL_LIBRARY}
|
||||
${QT_QTUITOOLS_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
@@ -449,6 +460,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
|
||||
${QT_QTNETWORK_LIBRARY}
|
||||
${QT_QTXML_LIBRARY}
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTDECLARATIVE_LIBRARY}
|
||||
${OS_SPECIFIC_LINK_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${LINK_LIBRARIES}
|
||||
|
@@ -23,11 +23,15 @@
|
||||
#include "PlaylistView.h"
|
||||
#include "ViewManager.h"
|
||||
#include "Query.h"
|
||||
#include "Result.h"
|
||||
#include "Collection.h"
|
||||
#include "Source.h"
|
||||
#include "Artist.h"
|
||||
#include "Album.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "filemetadata/MetadataEditor.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -39,7 +43,7 @@ ContextMenu::ContextMenu( QWidget* parent )
|
||||
m_sigmap = new QSignalMapper( this );
|
||||
connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) );
|
||||
|
||||
m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage;
|
||||
m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +113,19 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
|
||||
addSeparator();
|
||||
|
||||
if ( m_supportedActions & ActionEditMetadata && itemCount() == 1 )
|
||||
{
|
||||
if ( m_queries.first()->results().isEmpty() )
|
||||
return;
|
||||
|
||||
Tomahawk::result_ptr result = m_queries.first()->results().first();
|
||||
if ( result->collection() && result->collection()->source() &&
|
||||
result->collection()->source()->isLocal() )
|
||||
{
|
||||
m_sigmap->setMapping( addAction( tr( "Properties..." ) ), ActionEditMetadata );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_supportedActions & ActionDelete )
|
||||
m_sigmap->setMapping( addAction( queries.count() > 1 ? tr( "&Delete Items" ) : tr( "&Delete Item" ) ), ActionDelete );
|
||||
|
||||
@@ -243,6 +260,13 @@ ContextMenu::onTriggered( int action )
|
||||
AudioEngine::instance()->setStopAfterTrack( m_queries.first() );
|
||||
break;
|
||||
|
||||
case ActionEditMetadata:
|
||||
if ( !m_queries.first()->results().isEmpty() ) {
|
||||
MetadataEditor* d = new MetadataEditor( m_queries.first()->results().first(), this );
|
||||
d->show();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
emit triggered( action );
|
||||
}
|
||||
@@ -312,12 +336,12 @@ ContextMenu::onSocialActionsLoaded()
|
||||
if ( m_queries.isEmpty() || m_queries.first().isNull() )
|
||||
return;
|
||||
|
||||
if ( m_queries.first()->loved() )
|
||||
if ( m_loveAction && m_queries.first()->loved() )
|
||||
{
|
||||
m_loveAction->setText( tr( "Un-&Love" ) );
|
||||
m_loveAction->setIcon( QIcon( RESPATH "images/not-loved.png" ) );
|
||||
}
|
||||
else
|
||||
else if ( m_loveAction )
|
||||
{
|
||||
m_loveAction->setText( tr( "&Love" ) );
|
||||
m_loveAction->setIcon( QIcon( RESPATH "images/loved.png" ) );
|
||||
|
@@ -42,7 +42,8 @@ public:
|
||||
ActionCopyLink = 8,
|
||||
ActionLove = 16,
|
||||
ActionStopAfter = 32,
|
||||
ActionPage = 64
|
||||
ActionPage = 64,
|
||||
ActionEditMetadata = 128
|
||||
};
|
||||
|
||||
explicit ContextMenu( QWidget* parent = 0 );
|
||||
|
@@ -425,12 +425,18 @@ DropJob::tracksFromMixedData( const QMimeData *data )
|
||||
QDataStream singleStream( &singleData, QIODevice::WriteOnly );
|
||||
|
||||
QMimeData singleMimeData;
|
||||
if ( mimeType == "application/tomahawk.query.list" || mimeType == "application/tomahawk.result.list" )
|
||||
if ( mimeType == "application/tomahawk.query.list" )
|
||||
{
|
||||
qlonglong query;
|
||||
stream >> query;
|
||||
singleStream << query;
|
||||
}
|
||||
else if ( mimeType == "application/tomahawk.result.list" )
|
||||
{
|
||||
qlonglong result;
|
||||
stream >> result;
|
||||
singleStream << result;
|
||||
}
|
||||
else if ( mimeType == "application/tomahawk.metadata.album" )
|
||||
{
|
||||
QString artist;
|
||||
|
@@ -43,7 +43,6 @@
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "ViewManager.h"
|
||||
#include "playlist/topbar/TopBar.h"
|
||||
#include "playlist/PlaylistView.h"
|
||||
#include "widgets/SearchWidget.h"
|
||||
|
||||
|
@@ -60,7 +60,10 @@ public slots:
|
||||
/// Takes a spotify link and performs the default open action on it
|
||||
bool openRdioLink( const QString& link );
|
||||
|
||||
/// Creates a link from the requested data and copies it to the clipboard
|
||||
void copyToClipboard( const Tomahawk::query_ptr& query );
|
||||
|
||||
|
||||
QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist );
|
||||
void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename );
|
||||
|
||||
|
@@ -37,7 +37,9 @@
|
||||
#include "PlaylistPlaylistInterface.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "PlaylistUpdaterInterface.h"
|
||||
#include "widgets/SourceTreePopupDialog.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -179,16 +181,14 @@ Playlist::create( const source_ptr& author,
|
||||
p->setGuid( uuid() );
|
||||
p->setDuration( query->duration() );
|
||||
p->setLastmodified( 0 );
|
||||
QString annotation = "";
|
||||
if ( !query->property( "annotation" ).toString().isEmpty() )
|
||||
annotation = query->property( "annotation" ).toString();
|
||||
p->setAnnotation( annotation );
|
||||
p->setAnnotation( query->property( "annotation" ).toString() );
|
||||
p->setQuery( query );
|
||||
|
||||
entries << p;
|
||||
}
|
||||
|
||||
playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ), &QObject::deleteLater );
|
||||
playlist->setWeakSelf( playlist.toWeakRef() );
|
||||
|
||||
// save to DB in the background
|
||||
// Watch for the created() signal if you need to be sure it's written.
|
||||
@@ -310,6 +310,83 @@ Playlist::removeUpdater( PlaylistUpdaterInterface* updater )
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Playlist::hasCustomDeleter() const
|
||||
{
|
||||
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
|
||||
{
|
||||
if ( updater->hasCustomDeleter() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::customDelete( const QPoint& leftCenter )
|
||||
{
|
||||
if ( !hasCustomDeleter() )
|
||||
return;
|
||||
|
||||
Tomahawk::PlaylistDeleteQuestions questions;
|
||||
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
|
||||
{
|
||||
if ( updater->deleteQuestions().isEmpty() )
|
||||
continue;
|
||||
|
||||
questions.append( updater->deleteQuestions() );
|
||||
}
|
||||
|
||||
SourceTreePopupDialog* dialog = new SourceTreePopupDialog;
|
||||
NewClosure( dialog, SIGNAL( result( bool ) ), this, SLOT( onDeleteResult( SourceTreePopupDialog* ) ), dialog );
|
||||
|
||||
dialog->setMainText( tr( "Would you like to delete the playlist <b>\"%2\"</b>?", "e.g. Would you like to delete the playlist named Foobar?" )
|
||||
.arg( title() ) );
|
||||
dialog->setOkButtonText( tr( "Delete" ) );
|
||||
dialog->setExtraQuestions( questions );
|
||||
|
||||
dialog->move( leftCenter.x() - dialog->offset(), leftCenter.y() - dialog->sizeHint().height() / 2. );
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::onDeleteResult( SourceTreePopupDialog* dialog )
|
||||
{
|
||||
dialog->deleteLater();
|
||||
|
||||
const bool ret = dialog->resultValue();
|
||||
|
||||
if ( !ret )
|
||||
return;
|
||||
|
||||
playlist_ptr p = m_weakSelf.toStrongRef();
|
||||
if ( p.isNull() )
|
||||
{
|
||||
qWarning() << "Got null m_weakSelf weak ref in Playlsit::onDeleteResult!!";
|
||||
Q_ASSERT( false );
|
||||
return;
|
||||
}
|
||||
|
||||
const QMap< int, bool > questionResults = dialog->questionResults();
|
||||
foreach ( PlaylistUpdaterInterface* updater, m_updaters )
|
||||
{
|
||||
updater->setQuestionResults( questionResults );
|
||||
}
|
||||
|
||||
dynplaylist_ptr dynpl = p.dynamicCast< DynamicPlaylist >();
|
||||
if ( !dynpl.isNull() )
|
||||
{
|
||||
DynamicPlaylist::remove( dynpl );
|
||||
}
|
||||
else
|
||||
{
|
||||
remove( p );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::loadRevision( const QString& rev )
|
||||
{
|
||||
@@ -508,7 +585,7 @@ Playlist::setNewRevision( const QString& rev,
|
||||
tDebug() << "m_entries" << m_entries;
|
||||
|
||||
tLog() << "Playlist error for playlist with guid" << guid() << "from source" << author()->friendlyName();
|
||||
Q_ASSERT( false ); // XXX
|
||||
// Q_ASSERT( false ); // XXX
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,6 +787,13 @@ Playlist::checkRevisionQueue()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Playlist::setWeakSelf( QWeakPointer< Playlist > self )
|
||||
{
|
||||
m_weakSelf = self;
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::playlistinterface_ptr
|
||||
Playlist::playlistInterface()
|
||||
{
|
||||
|
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
class SourceTreePopupDialog;
|
||||
class DatabaseCommand_LoadAllPlaylists;
|
||||
class DatabaseCommand_LoadAllSortedPlaylists;
|
||||
class DatabaseCommand_SetPlaylistRevision;
|
||||
@@ -194,6 +195,18 @@ public:
|
||||
void removeUpdater( PlaylistUpdaterInterface* updater );
|
||||
QList<PlaylistUpdaterInterface*> updaters() const { return m_updaters; }
|
||||
|
||||
/**
|
||||
* Some updaters might have custom deleters in order to perform more actions that require
|
||||
* user prompting on delete.
|
||||
*/
|
||||
bool hasCustomDeleter() const;
|
||||
/**
|
||||
* If this playlist has a custom deleter, let it do the deleting itself.
|
||||
*
|
||||
* If it needs user prompting, use the \param customDeleter as the right-most center point.
|
||||
*/
|
||||
void customDelete( const QPoint& rightCenter );
|
||||
|
||||
Tomahawk::playlistinterface_ptr playlistInterface();
|
||||
|
||||
signals:
|
||||
@@ -249,6 +262,7 @@ public slots:
|
||||
|
||||
void resolve();
|
||||
|
||||
void setWeakSelf( QWeakPointer< Playlist > self );
|
||||
protected:
|
||||
// called from loadAllPlaylists DB cmd:
|
||||
explicit Playlist( const source_ptr& src,
|
||||
@@ -282,6 +296,7 @@ private slots:
|
||||
void onResultsFound( const QList<Tomahawk::result_ptr>& results );
|
||||
void onResolvingFinished();
|
||||
|
||||
void onDeleteResult( SourceTreePopupDialog* );
|
||||
private:
|
||||
Playlist();
|
||||
void init();
|
||||
@@ -289,6 +304,7 @@ private:
|
||||
void setBusy( bool b );
|
||||
void checkRevisionQueue();
|
||||
|
||||
QWeakPointer< Playlist > m_weakSelf;
|
||||
source_ptr m_source;
|
||||
QString m_currentrevision;
|
||||
QString m_guid, m_title, m_info, m_creator;
|
||||
|
@@ -42,12 +42,12 @@ public:
|
||||
virtual QList< Tomahawk::query_ptr > tracks() = 0;
|
||||
virtual bool isFinished() const { return m_finished; }
|
||||
|
||||
virtual int unfilteredTrackCount() const = 0;
|
||||
virtual int trackCount() const = 0;
|
||||
|
||||
virtual Tomahawk::result_ptr currentItem() const = 0;
|
||||
virtual Tomahawk::result_ptr previousItem();
|
||||
virtual bool hasNextItem() { return true; }
|
||||
virtual bool hasPreviousItem() { return true; }
|
||||
virtual Tomahawk::result_ptr nextItem();
|
||||
virtual Tomahawk::result_ptr siblingItem( int itemsAway ) = 0;
|
||||
|
||||
@@ -66,8 +66,7 @@ public:
|
||||
virtual PlaylistModes::LatchMode latchMode() const { return m_latchMode; }
|
||||
virtual void setLatchMode( PlaylistModes::LatchMode latchMode ) { m_latchMode = latchMode; }
|
||||
|
||||
virtual QString filter() const { return m_filter; }
|
||||
virtual void setFilter( const QString& pattern ) { m_filter = pattern; }
|
||||
virtual bool setCurrentTrack( unsigned int albumpos ) { Q_UNUSED( albumpos ); return false; }
|
||||
|
||||
virtual void reset() {}
|
||||
|
||||
@@ -81,10 +80,9 @@ public slots:
|
||||
virtual void setShuffled( bool enabled ) = 0;
|
||||
|
||||
signals:
|
||||
void trackCountChanged( unsigned int tracks );
|
||||
void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode );
|
||||
void shuffleModeChanged( bool enabled );
|
||||
void trackCountChanged( unsigned int tracks );
|
||||
void sourceTrackCountChanged( unsigned int tracks );
|
||||
void latchModeChanged( Tomahawk::PlaylistModes::LatchMode mode );
|
||||
void nextTrackReady();
|
||||
|
||||
|
@@ -40,13 +40,6 @@ PlaylistPlaylistInterface::~PlaylistPlaylistInterface()
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PlaylistPlaylistInterface::unfilteredTrackCount() const
|
||||
{
|
||||
return ( m_playlist.isNull() ? 0 : m_playlist.data()->entries().count() );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PlaylistPlaylistInterface::trackCount() const
|
||||
{
|
||||
|
@@ -44,7 +44,6 @@ public:
|
||||
|
||||
virtual QList<Tomahawk::query_ptr> tracks();
|
||||
|
||||
virtual int unfilteredTrackCount() const;
|
||||
virtual int trackCount() const;
|
||||
|
||||
virtual bool hasNextItem() { return false; }
|
||||
@@ -55,8 +54,6 @@ public:
|
||||
virtual PlaylistModes::RepeatMode repeatMode() const { return PlaylistModes::NoRepeat; }
|
||||
virtual bool shuffled() const { return false; }
|
||||
|
||||
virtual void setFilter( const QString& /*pattern*/ ) {}
|
||||
|
||||
public slots:
|
||||
virtual void setRepeatMode( PlaylistModes::RepeatMode ) {}
|
||||
virtual void setShuffled( bool ) {}
|
||||
|
@@ -82,8 +82,11 @@ PlaybackLog::PlaybackLog( const PlaybackLog& other )
|
||||
query_ptr
|
||||
Query::get( const QString& artist, const QString& track, const QString& album, const QID& qid, bool autoResolve )
|
||||
{
|
||||
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
|
||||
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
|
||||
{
|
||||
Q_ASSERT( false );
|
||||
return query_ptr();
|
||||
}
|
||||
|
||||
if ( qid.isEmpty() )
|
||||
autoResolve = false;
|
||||
@@ -150,6 +153,7 @@ Query::Query( const QString& query, const QID& qid )
|
||||
Query::~Query()
|
||||
{
|
||||
QMutexLocker lock( &m_mutex );
|
||||
|
||||
m_ownRef.clear();
|
||||
m_results.clear();
|
||||
}
|
||||
@@ -349,6 +353,22 @@ Query::id() const
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
Query::coverId() const
|
||||
{
|
||||
if ( m_albumPtr && m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() )
|
||||
{
|
||||
return m_albumPtr->coverId();
|
||||
}
|
||||
else if ( m_artistPtr )
|
||||
{
|
||||
return m_artistPtr->coverId();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Query::setPlayedBy( const Tomahawk::source_ptr& source, unsigned int playtime )
|
||||
{
|
||||
@@ -459,14 +479,19 @@ Query::checkResults()
|
||||
|
||||
|
||||
bool
|
||||
Query::equals( const Tomahawk::query_ptr& other ) const
|
||||
Query::equals( const Tomahawk::query_ptr& other, bool ignoreCase ) const
|
||||
{
|
||||
if ( other.isNull() )
|
||||
return false;
|
||||
|
||||
return ( artist() == other->artist() &&
|
||||
album() == other->album() &&
|
||||
track() == other->track() );
|
||||
if ( ignoreCase )
|
||||
return ( artist().toLower() == other->artist().toLower() &&
|
||||
album().toLower() == other->album().toLower() &&
|
||||
track().toLower() == other->track().toLower() );
|
||||
else
|
||||
return ( artist() == other->artist() &&
|
||||
album() == other->album() &&
|
||||
track() == other->track() );
|
||||
}
|
||||
|
||||
|
||||
@@ -502,7 +527,7 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
Q_ASSERT( !r->album().isNull() );
|
||||
if ( r->artist().isNull() || r->album().isNull() )
|
||||
return 0.0;
|
||||
|
||||
|
||||
// result values
|
||||
const QString rArtistname = r->artist()->sortname();
|
||||
const QString rAlbumname = r->album()->sortname();
|
||||
|
@@ -95,6 +95,7 @@ public:
|
||||
unsigned int numResults() const;
|
||||
|
||||
QID id() const;
|
||||
QString coverId() const;
|
||||
|
||||
/// sorter for list of results
|
||||
static bool resultSorter( const result_ptr& left, const result_ptr& right );
|
||||
@@ -122,7 +123,7 @@ public:
|
||||
void setAlbumPos( unsigned int albumpos ) { m_albumpos = albumpos; }
|
||||
void setDiscNumber( unsigned int discnumber ) { m_discnumber = discnumber; }
|
||||
|
||||
bool equals( const Tomahawk::query_ptr& other ) const;
|
||||
bool equals( const Tomahawk::query_ptr& other, bool ignoreCase = false ) const;
|
||||
|
||||
QVariant toVariant() const;
|
||||
QString toString() const;
|
||||
|
@@ -207,6 +207,10 @@ Result::toQuery()
|
||||
if ( m_query.isNull() )
|
||||
{
|
||||
m_query = Tomahawk::Query::get( artist()->name(), track(), album()->name() );
|
||||
|
||||
if ( m_query.isNull() )
|
||||
return query_ptr();
|
||||
|
||||
m_query->setAlbumPos( albumpos() );
|
||||
m_query->setDiscNumber( discnumber() );
|
||||
m_query->setDuration( duration() );
|
||||
|
@@ -292,10 +292,8 @@ Source::scanningProgress( unsigned int files )
|
||||
|
||||
|
||||
void
|
||||
Source::scanningFinished( unsigned int files )
|
||||
Source::scanningFinished()
|
||||
{
|
||||
Q_UNUSED( files );
|
||||
|
||||
m_textStatus = QString();
|
||||
|
||||
if ( m_updateIndexWhenSynced )
|
||||
|
@@ -80,7 +80,7 @@ public:
|
||||
void setControlConnection( ControlConnection* cc );
|
||||
|
||||
void scanningProgress( unsigned int files );
|
||||
void scanningFinished( unsigned int files );
|
||||
void scanningFinished();
|
||||
|
||||
unsigned int trackCount() const;
|
||||
|
||||
|
@@ -42,7 +42,6 @@ public:
|
||||
QList<Tomahawk::query_ptr> tracks();
|
||||
|
||||
virtual int trackCount() const { return 1; }
|
||||
virtual int unfilteredTrackCount() const { return 1; }
|
||||
|
||||
virtual Tomahawk::result_ptr siblingItem( int itemsAway );
|
||||
virtual bool sourceValid();
|
||||
@@ -59,7 +58,6 @@ public:
|
||||
virtual void setLatchMode( PlaylistModes::LatchMode latchMode ) { m_latchMode = latchMode; emit latchModeChanged( latchMode ); }
|
||||
|
||||
virtual bool shuffled() const { return false; }
|
||||
virtual void setFilter( const QString& /*pattern*/ ) {}
|
||||
|
||||
virtual QWeakPointer< Tomahawk::Source > source() const;
|
||||
|
||||
|
@@ -98,6 +98,9 @@ namespace Tomahawk
|
||||
typedef QMultiHash< QString, SerializedUpdater > SerializedUpdaters;
|
||||
typedef QList< SerializedUpdater > SerializedUpdaterList;
|
||||
|
||||
// Yes/no questions with an associated enum value
|
||||
typedef QPair< QString, int > PlaylistDeleteQuestion;
|
||||
typedef QList< PlaylistDeleteQuestion > PlaylistDeleteQuestions;
|
||||
|
||||
namespace InfoSystem
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,8 +26,8 @@
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "context/ContextWidget.h"
|
||||
#include "infobar/InfoBar.h"
|
||||
#include "topbar/TopBar.h"
|
||||
|
||||
#include "FlexibleView.h"
|
||||
#include "TreeModel.h"
|
||||
#include "PlaylistModel.h"
|
||||
#include "PlaylistView.h"
|
||||
@@ -38,10 +39,10 @@
|
||||
#include "SourceList.h"
|
||||
#include "TomahawkSettings.h"
|
||||
|
||||
#include "CustomPlaylistView.h"
|
||||
#include "PlaylistLargeItemDelegate.h"
|
||||
#include "RecentlyPlayedModel.h"
|
||||
#include "dynamic/widgets/DynamicWidget.h"
|
||||
#include "dynamic/widgets/DynamicQmlWidget.h"
|
||||
|
||||
#include "widgets/NewReleasesWidget.h"
|
||||
#include "widgets/WelcomeWidget.h"
|
||||
@@ -75,10 +76,8 @@ ViewManager::ViewManager( QObject* parent )
|
||||
, m_welcomeWidget( new WelcomeWidget() )
|
||||
, m_whatsHotWidget( new WhatsHotWidget() )
|
||||
, m_newReleasesWidget( new NewReleasesWidget() )
|
||||
, m_topLovedWidget( 0 )
|
||||
, m_recentPlaysWidget( 0 )
|
||||
, m_currentPage( 0 )
|
||||
, m_currentMode( PlaylistModes::Tree )
|
||||
, m_loaded( false )
|
||||
{
|
||||
s_instance = this;
|
||||
@@ -94,15 +93,11 @@ ViewManager::ViewManager( QObject* parent )
|
||||
m_widget->layout()->addWidget( m_contextWidget );
|
||||
|
||||
m_superCollectionView = new TreeView();
|
||||
m_superCollectionView->proxyModel()->setStyle( PlayableProxyModel::Collection );
|
||||
m_superCollectionModel = new TreeModel( m_superCollectionView );
|
||||
m_superCollectionView->setTreeModel( m_superCollectionModel );
|
||||
m_superCollectionView->setShowModes( false );
|
||||
// m_superCollectionView->proxyModel()->setShowOfflineResults( false );
|
||||
|
||||
m_superGridView = new GridView();
|
||||
m_superAlbumModel = new AlbumModel( m_superGridView );
|
||||
m_superGridView->setPlayableModel( m_superAlbumModel );
|
||||
|
||||
m_stack->setContentsMargins( 0, 0, 0, 0 );
|
||||
m_widget->setContentsMargins( 0, 0, 0, 0 );
|
||||
m_widget->layout()->setContentsMargins( 0, 0, 0, 0 );
|
||||
@@ -130,23 +125,27 @@ ViewManager::~ViewManager()
|
||||
delete m_whatsHotWidget;
|
||||
delete m_newReleasesWidget;
|
||||
delete m_welcomeWidget;
|
||||
delete m_topLovedWidget;
|
||||
delete m_recentPlaysWidget;
|
||||
delete m_contextWidget;
|
||||
delete m_widget;
|
||||
}
|
||||
|
||||
|
||||
PlaylistView*
|
||||
ViewManager::createPageForPlaylist( const playlist_ptr& pl )
|
||||
FlexibleView*
|
||||
ViewManager::createPageForPlaylist( const playlist_ptr& playlist )
|
||||
{
|
||||
PlaylistView* view = new PlaylistView();
|
||||
FlexibleView* view = new FlexibleView();
|
||||
PlaylistModel* model = new PlaylistModel();
|
||||
view->setPlaylistModel( model );
|
||||
model->loadPlaylist( pl );
|
||||
pl->resolve();
|
||||
|
||||
m_playlistViews.insert( pl, view );
|
||||
PlaylistView* pv = new PlaylistView();
|
||||
pv->setPlaylistModel( model );
|
||||
view->setDetailedView( pv );
|
||||
view->setPixmap( pv->pixmap() );
|
||||
|
||||
model->loadPlaylist( playlist );
|
||||
view->setPlayableModel( model );
|
||||
playlist->resolve();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -170,11 +169,12 @@ ViewManager::playlistForPage( ViewPage* page ) const
|
||||
Tomahawk::ViewPage*
|
||||
ViewManager::show( const Tomahawk::playlist_ptr& playlist )
|
||||
{
|
||||
PlaylistView* view;
|
||||
FlexibleView* view;
|
||||
|
||||
if ( !m_playlistViews.contains( playlist ) || m_playlistViews.value( playlist ).isNull() )
|
||||
{
|
||||
view = createPageForPlaylist( playlist );
|
||||
m_playlistViews.insert( playlist, view );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -182,9 +182,6 @@ ViewManager::show( const Tomahawk::playlist_ptr& playlist )
|
||||
}
|
||||
|
||||
setPage( view );
|
||||
|
||||
emit numSourcesChanged( SourceList::instance()->count() );
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -194,7 +191,7 @@ ViewManager::show( const Tomahawk::dynplaylist_ptr& playlist )
|
||||
{
|
||||
if ( !m_dynamicWidgets.contains( playlist ) || m_dynamicWidgets.value( playlist ).isNull() )
|
||||
{
|
||||
m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicWidget( playlist, m_stack );
|
||||
m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicQmlWidget( playlist, m_stack );
|
||||
|
||||
playlist->resolve();
|
||||
}
|
||||
@@ -206,8 +203,6 @@ ViewManager::show( const Tomahawk::dynplaylist_ptr& playlist )
|
||||
else
|
||||
showQueue();*/
|
||||
|
||||
emit numSourcesChanged( SourceList::instance()->count() );
|
||||
|
||||
return m_dynamicWidgets.value( playlist ).data();
|
||||
}
|
||||
|
||||
@@ -272,82 +267,32 @@ ViewManager::show( const Tomahawk::query_ptr& query )
|
||||
Tomahawk::ViewPage*
|
||||
ViewManager::show( const Tomahawk::collection_ptr& collection )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << m_currentMode;
|
||||
m_currentCollection = collection;
|
||||
ViewPage* shown = 0;
|
||||
if ( m_currentMode == PlaylistModes::Flat )
|
||||
|
||||
TreeView* view;
|
||||
if ( !m_treeViews.contains( collection ) || m_treeViews.value( collection ).isNull() )
|
||||
{
|
||||
/* CollectionView* view;
|
||||
if ( !m_collectionViews.contains( collection ) || m_collectionViews.value( collection ).isNull() )
|
||||
{
|
||||
view = new CollectionView();
|
||||
CollectionFlatModel* model = new CollectionFlatModel();
|
||||
view->setPlayableModel( model );
|
||||
view = new TreeView();
|
||||
view->proxyModel()->setStyle( PlayableProxyModel::Collection );
|
||||
TreeModel* model = new TreeModel();
|
||||
view->setTreeModel( model );
|
||||
|
||||
model->addCollection( collection );
|
||||
|
||||
m_collectionViews.insert( collection, view );
|
||||
}
|
||||
if ( collection && collection->source()->isLocal() )
|
||||
view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) );
|
||||
else
|
||||
{
|
||||
view = m_collectionViews.value( collection ).data();
|
||||
}
|
||||
view->setEmptyTip( tr( "This collection is empty." ) );
|
||||
|
||||
shown = view;
|
||||
setPage( view );*/
|
||||
model->addCollection( collection );
|
||||
|
||||
m_treeViews.insert( collection, view );
|
||||
}
|
||||
else
|
||||
{
|
||||
view = m_treeViews.value( collection ).data();
|
||||
}
|
||||
|
||||
if ( m_currentMode == PlaylistModes::Tree )
|
||||
{
|
||||
TreeView* view;
|
||||
if ( !m_treeViews.contains( collection ) || m_treeViews.value( collection ).isNull() )
|
||||
{
|
||||
view = new TreeView();
|
||||
TreeModel* model = new TreeModel();
|
||||
view->setTreeModel( model );
|
||||
|
||||
if ( collection && collection->source()->isLocal() )
|
||||
view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) );
|
||||
else
|
||||
view->setEmptyTip( tr( "This collection is empty." ) );
|
||||
|
||||
model->addCollection( collection );
|
||||
|
||||
m_treeViews.insert( collection, view );
|
||||
}
|
||||
else
|
||||
{
|
||||
view = m_treeViews.value( collection ).data();
|
||||
}
|
||||
|
||||
shown = view;
|
||||
setPage( view );
|
||||
}
|
||||
|
||||
if ( m_currentMode == PlaylistModes::Album )
|
||||
{
|
||||
GridView* aview;
|
||||
if ( !m_collectionGridViews.contains( collection ) || m_collectionGridViews.value( collection ).isNull() )
|
||||
{
|
||||
aview = new GridView();
|
||||
AlbumModel* amodel = new AlbumModel( aview );
|
||||
aview->setPlayableModel( amodel );
|
||||
amodel->addCollection( collection );
|
||||
|
||||
m_collectionGridViews.insert( collection, aview );
|
||||
}
|
||||
else
|
||||
{
|
||||
aview = m_collectionGridViews.value( collection ).data();
|
||||
}
|
||||
|
||||
shown = aview;
|
||||
setPage( aview );
|
||||
}
|
||||
|
||||
emit numSourcesChanged( 1 );
|
||||
|
||||
return shown;
|
||||
setPage( view );
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@@ -396,28 +341,9 @@ ViewManager::showSuperCollection()
|
||||
|
||||
m_superCollectionModel->setTitle( tr( "SuperCollection" ) );
|
||||
m_superCollectionModel->setDescription( tr( "Combined libraries of all your online friends" ) );
|
||||
m_superAlbumModel->setTitle( tr( "All available albums" ) );
|
||||
|
||||
ViewPage* shown = 0;
|
||||
if ( m_currentMode == PlaylistModes::Tree )
|
||||
{
|
||||
shown = m_superCollectionView;
|
||||
setPage( m_superCollectionView );
|
||||
}
|
||||
else if ( m_currentMode == PlaylistModes::Flat )
|
||||
{
|
||||
shown = m_superCollectionView;
|
||||
setPage( m_superCollectionView );
|
||||
}
|
||||
else if ( m_currentMode == PlaylistModes::Album )
|
||||
{
|
||||
shown = m_superGridView;
|
||||
setPage( m_superGridView );
|
||||
}
|
||||
|
||||
emit numSourcesChanged( m_superCollections.count() );
|
||||
|
||||
return shown;
|
||||
setPage( m_superCollectionView );
|
||||
return m_superCollectionView;
|
||||
}
|
||||
|
||||
|
||||
@@ -459,40 +385,24 @@ ViewManager::showNewReleasesPage()
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::ViewPage*
|
||||
ViewManager::showTopLovedPage()
|
||||
{
|
||||
if ( !m_topLovedWidget )
|
||||
{
|
||||
CustomPlaylistView* view = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget );
|
||||
PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() );
|
||||
connect( del, SIGNAL( updateIndex( QModelIndex ) ), view, SLOT( update( QModelIndex ) ) );
|
||||
view->setItemDelegate( del );
|
||||
|
||||
m_topLovedWidget = view;
|
||||
}
|
||||
|
||||
return show( m_topLovedWidget );
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::ViewPage*
|
||||
ViewManager::showRecentPlaysPage()
|
||||
{
|
||||
if ( !m_recentPlaysWidget )
|
||||
{
|
||||
PlaylistView* pv = new PlaylistView( m_widget );
|
||||
FlexibleView* pv = new FlexibleView( m_widget );
|
||||
pv->setPixmap( QPixmap( RESPATH "images/recently-played.png" ) );
|
||||
|
||||
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( pv );
|
||||
raModel->setTitle( tr( "Recently Played Tracks" ) );
|
||||
raModel->setDescription( tr( "Recently played tracks from all your friends" ) );
|
||||
raModel->setStyle( PlayableModel::Large );
|
||||
|
||||
PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv, pv->proxyModel() );
|
||||
connect( del, SIGNAL( updateIndex( QModelIndex ) ), pv, SLOT( update( QModelIndex ) ) );
|
||||
pv->setItemDelegate( del );
|
||||
PlaylistLargeItemDelegate* del = new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv->trackView(), pv->trackView()->proxyModel() );
|
||||
connect( del, SIGNAL( updateIndex( QModelIndex ) ), pv->trackView(), SLOT( update( QModelIndex ) ) );
|
||||
pv->trackView()->setItemDelegate( del );
|
||||
|
||||
pv->setPlaylistModel( raModel );
|
||||
pv->setPlayableModel( raModel );
|
||||
pv->setEmptyTip( tr( "Sorry, we could not find any recent plays!" ) );
|
||||
raModel->setSource( source_ptr() );
|
||||
|
||||
m_recentPlaysWidget = pv;
|
||||
@@ -502,48 +412,6 @@ ViewManager::showRecentPlaysPage()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ViewManager::setTableMode()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_currentMode = PlaylistModes::Flat;
|
||||
|
||||
if ( isSuperCollectionVisible() )
|
||||
showSuperCollection();
|
||||
else
|
||||
show( m_currentCollection );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ViewManager::setTreeMode()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_currentMode = PlaylistModes::Tree;
|
||||
|
||||
if ( isSuperCollectionVisible() )
|
||||
showSuperCollection();
|
||||
else
|
||||
show( m_currentCollection );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ViewManager::setAlbumMode()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_currentMode = PlaylistModes::Album;
|
||||
|
||||
if ( isSuperCollectionVisible() )
|
||||
showSuperCollection();
|
||||
else
|
||||
show( m_currentCollection );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ViewManager::setFilter( const QString& filter )
|
||||
{
|
||||
@@ -559,8 +427,8 @@ ViewManager::setFilter( const QString& filter )
|
||||
void
|
||||
ViewManager::applyFilter()
|
||||
{
|
||||
if ( currentPlaylistInterface() && currentPlaylistInterface()->filter() != m_filter )
|
||||
currentPlaylistInterface()->setFilter( m_filter );
|
||||
if ( m_currentPage )
|
||||
m_currentPage->setFilter( m_filter );
|
||||
}
|
||||
|
||||
|
||||
@@ -716,17 +584,11 @@ ViewManager::unlinkPlaylist()
|
||||
{
|
||||
if ( currentPlaylistInterface() )
|
||||
{
|
||||
disconnect( currentPlaylistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ),
|
||||
this, SIGNAL( numTracksChanged( unsigned int ) ) );
|
||||
|
||||
disconnect( currentPlaylistInterface().data(), SIGNAL( trackCountChanged( unsigned int ) ),
|
||||
this, SIGNAL( numShownChanged( unsigned int ) ) );
|
||||
|
||||
disconnect( currentPlaylistInterface().data(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
|
||||
this, SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
|
||||
this, SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
|
||||
|
||||
disconnect( currentPlaylistInterface().data(), SIGNAL( shuffleModeChanged( bool ) ),
|
||||
this, SIGNAL( shuffleModeChanged( bool ) ) );
|
||||
this, SIGNAL( shuffleModeChanged( bool ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,12 +599,16 @@ ViewManager::saveCurrentPlaylistSettings()
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
Tomahawk::playlist_ptr pl = playlistForInterface( currentPlaylistInterface() );
|
||||
|
||||
if ( !pl.isNull() ) {
|
||||
if ( !pl.isNull() )
|
||||
{
|
||||
s->setShuffleState( pl->guid(), currentPlaylistInterface()->shuffled() );
|
||||
s->setRepeatMode( pl->guid(), currentPlaylistInterface()->repeatMode() );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Tomahawk::dynplaylist_ptr dynPl = dynamicPlaylistForInterface( currentPlaylistInterface() );
|
||||
if ( !dynPl.isNull() ) {
|
||||
if ( !dynPl.isNull() )
|
||||
{
|
||||
s->setShuffleState( dynPl->guid(), currentPlaylistInterface()->shuffled() );
|
||||
s->setRepeatMode( dynPl->guid(), currentPlaylistInterface()->repeatMode() );
|
||||
}
|
||||
@@ -755,33 +621,16 @@ ViewManager::updateView()
|
||||
{
|
||||
if ( currentPlaylistInterface() )
|
||||
{
|
||||
connect( currentPlaylistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ),
|
||||
SIGNAL( numTracksChanged( unsigned int ) ) );
|
||||
|
||||
connect( currentPlaylistInterface().data(), SIGNAL( trackCountChanged( unsigned int ) ),
|
||||
SIGNAL( numShownChanged( unsigned int ) ) );
|
||||
|
||||
connect( currentPlaylistInterface().data(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
|
||||
SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
|
||||
|
||||
connect( currentPlaylistInterface().data(), SIGNAL( shuffleModeChanged( bool ) ),
|
||||
SIGNAL( shuffleModeChanged( bool ) ) );
|
||||
|
||||
m_infobar->setFilter( currentPlaylistInterface()->filter() );
|
||||
}
|
||||
|
||||
if ( currentPage()->showStatsBar() && currentPlaylistInterface() )
|
||||
{
|
||||
emit numTracksChanged( currentPlaylistInterface()->unfilteredTrackCount() );
|
||||
|
||||
if ( !currentPlaylistInterface()->filter().isEmpty() )
|
||||
emit numShownChanged( currentPlaylistInterface()->trackCount() );
|
||||
else
|
||||
emit numShownChanged( currentPlaylistInterface()->unfilteredTrackCount() );
|
||||
m_infobar->setFilter( currentPage()->filter() );
|
||||
|
||||
emit repeatModeChanged( currentPlaylistInterface()->repeatMode() );
|
||||
emit shuffleModeChanged( currentPlaylistInterface()->shuffled() );
|
||||
emit modeChanged( currentPlaylistInterface()->viewMode() );
|
||||
}
|
||||
|
||||
/* if ( currentPage()->queueVisible() )
|
||||
@@ -789,18 +638,10 @@ ViewManager::updateView()
|
||||
else
|
||||
hideQueue();*/
|
||||
|
||||
emit statsAvailable( currentPage()->showStatsBar() );
|
||||
emit modesAvailable( currentPage()->showModes() );
|
||||
emit filterAvailable( currentPage()->showFilter() );
|
||||
|
||||
/* if ( !currentPage()->showStatsBar() && !currentPage()->showModes() && !currentPage()->showFilter() )
|
||||
m_topbar->setVisible( false );
|
||||
else
|
||||
m_topbar->setVisible( true );*/
|
||||
|
||||
m_infobar->setVisible( currentPage()->showInfoBar() );
|
||||
m_infobar->setCaption( currentPage()->title() );
|
||||
|
||||
m_infobar->setUpdaters( currentPage()->updaters() );
|
||||
|
||||
switch( currentPage()->descriptionType() )
|
||||
@@ -977,7 +818,7 @@ ViewManager::currentPage() const
|
||||
Tomahawk::playlist_ptr
|
||||
ViewManager::playlistForInterface( Tomahawk::playlistinterface_ptr interface ) const
|
||||
{
|
||||
foreach ( QWeakPointer<PlaylistView> view, m_playlistViews.values() )
|
||||
foreach ( QWeakPointer<FlexibleView> view, m_playlistViews.values() )
|
||||
{
|
||||
if ( !view.isNull() && view.data()->playlistInterface() == interface )
|
||||
{
|
||||
@@ -992,7 +833,7 @@ ViewManager::playlistForInterface( Tomahawk::playlistinterface_ptr interface ) c
|
||||
Tomahawk::dynplaylist_ptr
|
||||
ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interface ) const
|
||||
{
|
||||
foreach ( QWeakPointer<DynamicWidget> view, m_dynamicWidgets.values() )
|
||||
foreach ( QWeakPointer<DynamicQmlWidget> view, m_dynamicWidgets.values() )
|
||||
{
|
||||
if ( !view.isNull() && view.data()->playlistInterface() == interface )
|
||||
{
|
||||
@@ -1004,27 +845,11 @@ ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interf
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::collection_ptr
|
||||
ViewManager::collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const
|
||||
{
|
||||
foreach ( QWeakPointer<GridView> view, m_collectionGridViews.values() )
|
||||
{
|
||||
if ( view.data()->playlistInterface() == interface )
|
||||
{
|
||||
return m_collectionGridViews.key( view );
|
||||
}
|
||||
}
|
||||
|
||||
return collection_ptr();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ViewManager::isSuperCollectionVisible() const
|
||||
{
|
||||
return ( currentPage() != 0 &&
|
||||
( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() ||
|
||||
currentPage()->playlistInterface() == m_superGridView->playlistInterface() ) );
|
||||
( currentPage()->playlistInterface() == m_superCollectionView->playlistInterface() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -1037,19 +862,6 @@ ViewManager::showCurrentTrack()
|
||||
{
|
||||
setPage( page );
|
||||
page->jumpToCurrentTrack();
|
||||
|
||||
// reset the correct mode, if the user has changed it since
|
||||
|
||||
if ( dynamic_cast< TrackView* >( page ) )
|
||||
m_currentMode = PlaylistModes::Flat;
|
||||
else if ( dynamic_cast< GridView* >( page ) )
|
||||
m_currentMode = PlaylistModes::Album;
|
||||
else if ( dynamic_cast< TreeView* >( page ) )
|
||||
m_currentMode = PlaylistModes::Tree;
|
||||
else
|
||||
return;
|
||||
|
||||
emit modeChanged( (PlaylistModes::ViewMode)m_currentMode );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,13 +887,6 @@ ViewManager::newReleasesWidget() const
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::ViewPage*
|
||||
ViewManager::topLovedWidget() const
|
||||
{
|
||||
return m_topLovedWidget;
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::ViewPage*
|
||||
ViewManager::recentPlaysWidget() const
|
||||
{
|
||||
|
@@ -40,6 +40,7 @@ class ArtistInfoWidget;
|
||||
class TreeView;
|
||||
class CollectionModel;
|
||||
class ContextWidget;
|
||||
class FlexibleView;
|
||||
class PlaylistModel;
|
||||
class PlaylistView;
|
||||
class TrackProxyModel;
|
||||
@@ -49,7 +50,6 @@ class TreeModel;
|
||||
class TrackView;
|
||||
class SourceInfoWidget;
|
||||
class InfoBar;
|
||||
class TopBar;
|
||||
class TrackInfoWidget;
|
||||
class NewReleasesWidget;
|
||||
class WelcomeWidget;
|
||||
@@ -59,6 +59,7 @@ class QPushButton;
|
||||
namespace Tomahawk
|
||||
{
|
||||
class DynamicWidget;
|
||||
class DynamicQmlWidget;
|
||||
}
|
||||
|
||||
class DLLEXPORT ViewManager : public QObject
|
||||
@@ -90,7 +91,6 @@ public:
|
||||
Tomahawk::ViewPage* welcomeWidget() const;
|
||||
Tomahawk::ViewPage* whatsHotWidget() const;
|
||||
Tomahawk::ViewPage* newReleasesWidget() const;
|
||||
Tomahawk::ViewPage* topLovedWidget() const;
|
||||
Tomahawk::ViewPage* recentPlaysWidget() const;
|
||||
TreeView* superCollectionView() const;
|
||||
|
||||
@@ -104,23 +104,15 @@ public:
|
||||
|
||||
// only use this is you need to create a playlist and show it directly and want it to be
|
||||
// linked to the sidebar. call it right after creating the playlist
|
||||
PlaylistView* createPageForPlaylist( const Tomahawk::playlist_ptr& pl );
|
||||
FlexibleView* createPageForPlaylist( const Tomahawk::playlist_ptr& playlist );
|
||||
|
||||
bool isTomahawkLoaded() const { return m_loaded; }
|
||||
|
||||
signals:
|
||||
void numSourcesChanged( unsigned int sources );
|
||||
void numTracksChanged( unsigned int tracks );
|
||||
void numArtistsChanged( unsigned int artists );
|
||||
void numShownChanged( unsigned int shown );
|
||||
|
||||
void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode );
|
||||
void shuffleModeChanged( bool enabled );
|
||||
|
||||
void statsAvailable( bool b );
|
||||
void modesAvailable( bool b );
|
||||
void filterAvailable( bool b );
|
||||
void modeChanged( Tomahawk::PlaylistModes::ViewMode mode );
|
||||
|
||||
void playClicked();
|
||||
void pauseClicked();
|
||||
@@ -132,7 +124,7 @@ signals:
|
||||
void hideQueueRequested();
|
||||
|
||||
void tomahawkLoaded();
|
||||
|
||||
|
||||
void historyBackAvailable( bool avail );
|
||||
void historyForwardAvailable( bool avail );
|
||||
|
||||
@@ -141,7 +133,6 @@ public slots:
|
||||
Tomahawk::ViewPage* showWelcomePage();
|
||||
Tomahawk::ViewPage* showWhatsHotPage();
|
||||
Tomahawk::ViewPage* showNewReleasesPage();
|
||||
Tomahawk::ViewPage* showTopLovedPage();
|
||||
Tomahawk::ViewPage* showRecentPlaysPage();
|
||||
void showCurrentTrack();
|
||||
|
||||
@@ -156,17 +147,13 @@ public slots:
|
||||
|
||||
void historyBack();
|
||||
void historyForward();
|
||||
|
||||
|
||||
QList< Tomahawk::ViewPage* > historyPages() const;
|
||||
void destroyPage( Tomahawk::ViewPage* page );
|
||||
|
||||
void showQueue() { emit showQueueRequested(); }
|
||||
void hideQueue() { emit hideQueueRequested(); }
|
||||
|
||||
void setTreeMode();
|
||||
void setTableMode();
|
||||
void setAlbumMode();
|
||||
|
||||
void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode mode );
|
||||
void setShuffled( bool enabled );
|
||||
|
||||
@@ -193,7 +180,6 @@ private:
|
||||
|
||||
Tomahawk::playlist_ptr playlistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
|
||||
Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
|
||||
Tomahawk::collection_ptr collectionForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
|
||||
|
||||
QWidget* m_widget;
|
||||
InfoBar* m_infobar;
|
||||
@@ -201,26 +187,22 @@ private:
|
||||
QStackedWidget* m_stack;
|
||||
AnimatedSplitter* m_splitter;
|
||||
|
||||
AlbumModel* m_superAlbumModel;
|
||||
GridView* m_superGridView;
|
||||
TreeModel* m_superCollectionModel;
|
||||
TreeView* m_superCollectionView;
|
||||
QueueView* m_queue;
|
||||
WelcomeWidget* m_welcomeWidget;
|
||||
WhatsHotWidget* m_whatsHotWidget;
|
||||
NewReleasesWidget* m_newReleasesWidget;
|
||||
Tomahawk::ViewPage* m_topLovedWidget;
|
||||
Tomahawk::ViewPage* m_recentPlaysWidget;
|
||||
|
||||
QList< Tomahawk::collection_ptr > m_superCollections;
|
||||
|
||||
QHash< Tomahawk::dynplaylist_ptr, QWeakPointer<Tomahawk::DynamicWidget> > m_dynamicWidgets;
|
||||
QHash< Tomahawk::dynplaylist_ptr, QWeakPointer<Tomahawk::DynamicQmlWidget> > m_dynamicWidgets;
|
||||
QHash< Tomahawk::collection_ptr, QWeakPointer<TreeView> > m_treeViews;
|
||||
QHash< Tomahawk::collection_ptr, QWeakPointer<GridView> > m_collectionGridViews;
|
||||
QHash< Tomahawk::artist_ptr, QWeakPointer<ArtistInfoWidget> > m_artistViews;
|
||||
QHash< Tomahawk::album_ptr, QWeakPointer<AlbumInfoWidget> > m_albumViews;
|
||||
QHash< Tomahawk::query_ptr, QWeakPointer<TrackInfoWidget> > m_trackViews;
|
||||
QHash< Tomahawk::playlist_ptr, QWeakPointer<PlaylistView> > m_playlistViews;
|
||||
QHash< Tomahawk::playlist_ptr, QWeakPointer<FlexibleView> > m_playlistViews;
|
||||
QHash< Tomahawk::source_ptr, QWeakPointer<SourceInfoWidget> > m_sourceViews;
|
||||
|
||||
QList<Tomahawk::ViewPage*> m_pageHistoryBack;
|
||||
@@ -228,7 +210,6 @@ private:
|
||||
Tomahawk::ViewPage* m_currentPage;
|
||||
|
||||
Tomahawk::collection_ptr m_currentCollection;
|
||||
int m_currentMode;
|
||||
|
||||
QTimer m_filterTimer;
|
||||
QString m_filter;
|
||||
|
@@ -23,3 +23,10 @@
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
bool
|
||||
ViewPage::setFilter( const QString& filter )
|
||||
{
|
||||
m_filter = filter;
|
||||
return false;
|
||||
}
|
||||
|
@@ -58,12 +58,13 @@ public:
|
||||
virtual QString longDescription() const { return QString(); }
|
||||
virtual QPixmap pixmap() const { return QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ); }
|
||||
|
||||
virtual bool showStatsBar() const { return true; }
|
||||
virtual bool showInfoBar() const { return true; }
|
||||
virtual bool showModes() const { return false; }
|
||||
virtual bool showFilter() const { return false; }
|
||||
virtual bool queueVisible() const { return true; }
|
||||
|
||||
virtual QString filter() const { return m_filter; }
|
||||
virtual bool setFilter( const QString& filter );
|
||||
|
||||
virtual bool jumpToCurrentTrack() = 0;
|
||||
|
||||
virtual bool isTemporaryPage() const { return false; }
|
||||
@@ -82,6 +83,9 @@ public:
|
||||
*
|
||||
* See DynamicWidget for an example
|
||||
*/
|
||||
|
||||
private:
|
||||
QString m_filter;
|
||||
};
|
||||
|
||||
}; // ns
|
||||
|
@@ -38,8 +38,9 @@ using namespace Accounts;
|
||||
|
||||
AccountModel::AccountModel( QObject* parent )
|
||||
: QAbstractListModel( parent )
|
||||
, m_waitingForAtticaLoaded( true )
|
||||
{
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( loadData() ) );
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded() ) );
|
||||
connect( AtticaManager::instance(), SIGNAL( startedInstalling( QString ) ), this, SLOT( onStartedInstalling( QString ) ) );
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( onFinishedInstalling( QString ) ) );
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverInstallationFailed( QString ) ), this, SLOT( resolverInstallFailed( QString ) ) );
|
||||
@@ -51,6 +52,15 @@ AccountModel::AccountModel( QObject* parent )
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountModel::atticaLoaded()
|
||||
{
|
||||
m_waitingForAtticaLoaded = false;
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountModel::loadData()
|
||||
{
|
||||
@@ -644,7 +654,8 @@ AccountModel::accountAdded( Account* account )
|
||||
if ( ResolverAccount* resolver = qobject_cast< ResolverAccount* >( account ) )
|
||||
{
|
||||
qDebug() << "Plain old manual resolver added, appending at end";
|
||||
Q_ASSERT( qobject_cast< AtticaResolverAccount* >( account ) == 0 ); // should NOT get attica accounts here, should be caught above
|
||||
if ( !m_waitingForAtticaLoaded )
|
||||
Q_ASSERT( qobject_cast< AtticaResolverAccount* >( account ) == 0 ); // should NOT get attica accounts here, should be caught above
|
||||
const int count = m_accounts.size();
|
||||
beginInsertRows( QModelIndex(), count, count );
|
||||
m_accounts << new AccountModelNode( resolver );
|
||||
|
@@ -100,6 +100,7 @@ signals:
|
||||
void errorInstalling( const QPersistentModelIndex& idx );
|
||||
|
||||
private slots:
|
||||
void atticaLoaded();
|
||||
void loadData();
|
||||
|
||||
void accountAdded( Tomahawk::Accounts::Account* );
|
||||
@@ -112,6 +113,7 @@ private slots:
|
||||
private:
|
||||
QModelIndex indexForAtticaId( const QString& resolverId ) const;
|
||||
|
||||
bool m_waitingForAtticaLoaded;
|
||||
QList< AccountModelNode* > m_accounts;
|
||||
QSet< QString > m_waitingForAtticaInstall;
|
||||
};
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include <attica/content.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
|
||||
namespace Tomahawk {
|
||||
class ExternalResolverGui;
|
||||
|