Compare commits
64 Commits
libfuzzyma
...
stable-0.7
Author | SHA1 | Date | |
---|---|---|---|
|
588b9898dd | ||
|
072a2e8d78 | ||
|
247c184ba3 | ||
|
af6f96728f | ||
|
03b581856f | ||
|
7a869ef332 | ||
|
93ec8a300d | ||
|
b4752ba7a6 | ||
|
87311cfbd7 | ||
|
1a75a46f78 | ||
|
2867314465 | ||
|
760c8b664d | ||
|
16aae53436 | ||
|
214e2ac924 | ||
|
627c32be9f | ||
|
911d611701 | ||
|
efc89621b6 | ||
|
f552f20322 | ||
|
1cef0c9ac4 | ||
|
8d069f83c8 | ||
|
0849e24c5a | ||
|
deb81ac8d4 | ||
|
3af985b798 | ||
|
3aaa951b41 | ||
|
4a1c5aef33 | ||
|
0b4765c728 | ||
|
aa0dc80efc | ||
|
616f02087e | ||
|
d2bfda03aa | ||
|
d76580ab5f | ||
|
d0b71a6c00 | ||
|
1c5635dad5 | ||
|
63196bc550 | ||
|
757d9f98d6 | ||
|
9c1db4970a | ||
|
49d50e5487 | ||
|
c6b87a09b6 | ||
|
858bbaa3d8 | ||
|
27d522165d | ||
|
1b08c197e3 | ||
|
c37ab1779e | ||
|
f2a0c05413 | ||
|
bc3ae087eb | ||
|
4e92cb5e48 | ||
|
552a830284 | ||
|
3f9356a0e0 | ||
|
e7fe517e9a | ||
|
822c84b32a | ||
|
e8322cef91 | ||
|
1ad39e3ef6 | ||
|
1ec2ccabea | ||
|
769f02b7da | ||
|
94dc1cfd5e | ||
|
75e9b78883 | ||
|
117b091e4a | ||
|
b0fb51eed7 | ||
|
6a86f843bc | ||
|
3a27edbe38 | ||
|
8771fd6f0e | ||
|
c6b82dc30d | ||
|
c3f2eff5cb | ||
|
7132ef85cd | ||
|
6bab0f7b6f | ||
|
663d7af61b |
@@ -22,8 +22,8 @@ ELSE()
|
||||
ENDIF()
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 6 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 99 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 7 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 0 )
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
SET( TOMAHAWK_TRANSLATION_LANGUAGES ar bg bn_IN ca cs de en el es fi fr hi_IN hu gl it ja lt pl pt_BR ru sv tr zh_CN zh_TW )
|
||||
@@ -191,8 +191,8 @@ if(PHONON_FOUND)
|
||||
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
|
||||
endif()
|
||||
|
||||
macro_optional_find_package(Echonest 2.0.2)
|
||||
macro_log_feature(ECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 2.0.2 is needed for dynamic playlists and the infosystem")
|
||||
macro_optional_find_package(Echonest 2.0.3)
|
||||
macro_log_feature(ECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 2.0.3 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")
|
||||
@@ -241,7 +241,7 @@ ENDIF( WIN32 )
|
||||
#TODO: support external qxt
|
||||
set(QXTWEB_FOUND TRUE)
|
||||
set(QXTWEB_LIBRARIES qxtweb-standalone)
|
||||
set(QXTWEB_INCLUDE_DIRS ${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(QXTWEB_INCLUDE_DIRS ${THIRDPARTY_DIR}/qxt/qxtweb-standalone/web ${THIRDPARTY_DIR}/qxt/qxtweb-standalone/network ${THIRDPARTY_DIR}/qxt/qxtweb-standalone/core ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
### libportfwd
|
||||
set(LIBPORTFWD_INCLUDE_DIR ${THIRDPARTY_DIR}/libportfwd/include)
|
||||
|
22
ChangeLog
@@ -1,4 +1,26 @@
|
||||
Version 0.7.1:
|
||||
* Heavily reduced memory footprint during and after indexing the database.
|
||||
|
||||
Version 0.7.0:
|
||||
* JavaScript Resolvers can now expose collections.
|
||||
* Introduced bundle system for JavaScript Resolvers, called "axes".
|
||||
* Fixed playback-loop caused by duplicate tracks in a playlist.
|
||||
* Improved peer handling.
|
||||
* Taking an account offline now also disconnects associated peers.
|
||||
* Improved spotify protocol handling.
|
||||
* Added "Append to Playlist" context menu item.
|
||||
* User-friendlier collection handling: added info-buttons for artists and
|
||||
albums. Double-clicking an item expands it now.
|
||||
* Charts only load on-demand now.
|
||||
* Fixed Diagnostics information not correctly updating.
|
||||
* Fixed issue with hidden sidebar and panels.
|
||||
* Fixed issues with some color schemes.
|
||||
* Fixed playing files with special characters in the filename.
|
||||
* Improved stability.
|
||||
* Added translations for Catalan, Czech, Galician, Greek, Italian and
|
||||
Chinese.
|
||||
* (Windows) Smoother and more responsive audio playback.
|
||||
* (Linux) Fixed grid issues with GTK-styles.
|
||||
|
||||
Version 0.6.1:
|
||||
* Improved stability.
|
||||
|
@@ -44,7 +44,7 @@ Required 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 2.0.2 - http://projects.kde.org/projects/playground/libs/libechonest/
|
||||
* libechonest 2.0.3 - 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/
|
||||
* liblastfm 1.0.1 - https://github.com/lastfm/liblastfm/
|
||||
|
@@ -16,5 +16,4 @@ Comment[se]=Tomahawk — Den Sociala Musikspelaren
|
||||
Icon=tomahawk
|
||||
Terminal=false
|
||||
Categories=Qt;AudioVideo;Audio;Player;
|
||||
MimeType=x-scheme-handler/tomahawk;
|
||||
MimeType=x-scheme-handler/spotify;
|
||||
MimeType=x-scheme-handler/tomahawk;x-scheme-handler/spotify;
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 822 B After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 10 KiB |
@@ -1,101 +1,23 @@
|
||||
<?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>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="3100px" height="3100px" viewBox="0 0 3100 3100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<title>tomahawk-icon</title>
|
||||
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<defs>
|
||||
<filter x="-20%" y="-20%" width="140%" height="140%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Page 1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<circle d="M1546,3051 C2374.42717,3051 3046,2379.42717 3046,1551 C3046,722.572834 2374.42717,51 1546,51 C717.572834,51 46,722.572834 46,1551 C46,2379.42717 717.572834,3051 1546,3051 Z M1546,3051" id="Oval 1" stroke="#979797" fill="#FFFFFF" sketch:type="MSShapeGroup" cx="1546" cy="1551" r="1500"></circle>
|
||||
<g id="Group" sketch:type="MSLayerGroup" transform="translate(46.000000, 48.000000)">
|
||||
<path d="M1500.00026,326.562245 C852.333832,326.562245 325.623384,853.409757 325.623384,1501.14467 C325.623384,2148.84339 852.297589,2675.87184 1500.00026,2675.87184 C1592.85982,2675.87184 1682.97119,2664.36909 1769.71967,2643.75096 L1769.71967,1630.53256 L961.97175,2202.26973 C954.812018,2207.15297 945.916593,2209.9744 937.346612,2209.9744 C930.693123,2209.9744 923.894994,2208.56369 917.783909,2205.05499 C903.464446,2197.74821 894.56902,2183.06231 894.56902,2167.32742 L894.56902,827.040286 C894.56902,811.305396 903.464445,796.474809 917.783909,788.951001 C932.103373,781.969774 949.026377,783.199628 961.97175,792.27884 L1769.71967,1364.0522 L1769.71967,784.284802 L1804.10807,784.284802 L2127.56161,784.284802 L2127.56161,2492.84071 C2455.75216,2284.34437 2674.34095,1918.13743 2674.34095,1501.10857 C2674.34087,853.446289 2147.48558,326.562245 1500.00026,326.562245 L1500.00026,326.562245 L1500.00026,326.562245" id="Shape" sketch:type="MSShapeGroup"></path>
|
||||
<path d="M1500.00026,0.904613118 C672.870406,0.904613118 0.0726019231,673.923876 0.0726019231,1501.14494 C0.0726019231,2328.4023 672.870475,3001.38527 1500.00026,3001.38527 C2326.94928,3001.38527 2999.78337,2328.40223 2999.78337,1501.14494 C2999.74681,673.923394 2326.94887,0.904613118 1500.00026,0.904613118 L1500.00026,0.904613118 L1500.00026,0.904613118 M2127.56146,2492.87708 L2127.56146,784.321176 L1804.10793,784.321176 L1769.71952,784.321176 L1769.71952,1364.08857 L961.971604,792.315213 C949.06239,783.236001 932.103228,782.006148 917.783763,788.987375 C903.464299,796.511184 894.568874,811.341769 894.568874,827.076659 L894.568874,2167.3638 C894.568874,2183.09869 903.464299,2197.78459 917.783763,2205.09136 C923.894847,2208.60006 930.692976,2210.01078 937.346465,2210.01078 C945.880287,2210.01078 954.775711,2207.18935 961.971604,2202.30611 L1769.71952,1630.56893 L1769.71952,2643.78733 C1682.97105,2664.36929 1592.85968,2675.90821 1500.00012,2675.90821 C852.333686,2675.90821 325.623237,2148.87983 325.623237,1501.18104 C325.623237,853.482317 852.297442,326.598618 1500.00012,326.598618 C2147.48578,326.598618 2674.377,853.44613 2674.377,1501.18104 C2674.34087,1918.17376 2455.75215,2284.38047 2127.56146,2492.87708 L2072.56159,399.051282" id="Shape" fill="#E63E30" filter="url(#filter-1)" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 3.9 KiB |
@@ -1,16 +1,23 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/lang">
|
||||
<file>tomahawk_en.qm</file>
|
||||
<file>tomahawk_ar.qm</file>
|
||||
<file>tomahawk_bg.qm</file>
|
||||
<file>tomahawk_ca.qm</file>
|
||||
<file>tomahawk_ca@valencia.qm</file>
|
||||
<file>tomahawk_cs.qm</file>
|
||||
<file>tomahawk_de.qm</file>
|
||||
<file>tomahawk_el.qm</file>
|
||||
<file>tomahawk_en.qm</file>
|
||||
<file>tomahawk_es.qm</file>
|
||||
<file>tomahawk_fi.qm</file>
|
||||
<file>tomahawk_fr.qm</file>
|
||||
<file>tomahawk_gl.qm</file>
|
||||
<file>tomahawk_it.qm</file>
|
||||
<file>tomahawk_ja.qm</file>
|
||||
<file>tomahawk_pl.qm</file>
|
||||
<file>tomahawk_pt_BR.qm</file>
|
||||
<file>tomahawk_ru.qm</file>
|
||||
<file>tomahawk_es.qm</file>
|
||||
<file>tomahawk_sv.qm</file>
|
||||
<file>tomahawk_ja.qm</file>
|
||||
<file>tomahawk_ar.qm</file>
|
||||
<file>tomahawk_zh_CN.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -64,7 +64,6 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->artistTrackLabel->setFont( font );
|
||||
ui->artistTrackLabel->setElideMode( Qt::ElideMiddle );
|
||||
ui->artistTrackLabel->setType( QueryLabel::Track );
|
||||
ui->artistTrackLabel->setJumpLinkVisible( true );
|
||||
|
||||
font.setPointSize( TomahawkUtils::defaultFontSize() );
|
||||
ui->albumLabel->setFont( font );
|
||||
@@ -74,7 +73,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
queryLabelsPalette.setColor( QPalette::Foreground, Qt::black );
|
||||
ui->artistTrackLabel->setPalette( queryLabelsPalette );
|
||||
ui->albumLabel->setPalette( queryLabelsPalette );
|
||||
|
||||
|
||||
font.setWeight( QFont::Normal );
|
||||
ui->timeLabel->setFont( font );
|
||||
ui->timeLeftLabel->setFont( font );
|
||||
@@ -136,7 +135,6 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
connect( ui->loveButton, SIGNAL( clicked( bool ) ), SLOT( onLoveButtonClicked( bool ) ) );
|
||||
connect( ui->ownerButton, SIGNAL( clicked() ), SLOT( onOwnerButtonClicked() ) );
|
||||
|
||||
// <From AudioEngine>
|
||||
connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( onPlaybackLoading( Tomahawk::result_ptr ) ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( onPlaybackPaused() ) );
|
||||
@@ -149,6 +147,8 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
connect( AudioEngine::instance(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ), SLOT( onRepeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
|
||||
connect( AudioEngine::instance(), SIGNAL( shuffleModeChanged( bool ) ), SLOT( onShuffleModeChanged( bool ) ) );
|
||||
|
||||
connect( ViewManager::instance(), SIGNAL( viewPageDestroyed() ), SLOT( onControlStateChanged() ) );
|
||||
|
||||
ui->buttonAreaLayout->setSpacing( 0 );
|
||||
ui->stackedLayout->setSpacing( 0 );
|
||||
ui->stackedLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
@@ -216,6 +216,10 @@ AudioControls::onControlStateChanged()
|
||||
|
||||
ui->prevButton->setEnabled( AudioEngine::instance()->canGoPrevious() );
|
||||
ui->nextButton->setEnabled( AudioEngine::instance()->canGoNext() );
|
||||
|
||||
// If the ViewManager doesn't know a page for the current interface, we can't offer the jump link
|
||||
ui->artistTrackLabel->setJumpLinkVisible( AudioEngine::instance()->currentTrackPlaylist()
|
||||
&& ViewManager::instance()->pageForInterface( AudioEngine::instance()->currentTrackPlaylist() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +243,7 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( 0 ) );
|
||||
|
||||
|
||||
m_sliderTimeLine.setDuration( duration );
|
||||
m_sliderTimeLine.setFrameRange( 0, duration );
|
||||
m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
|
||||
@@ -299,9 +303,6 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
ui->seekSlider->setVisible( true );
|
||||
m_sliderTimeLine.stop();
|
||||
|
||||
// If the ViewManager doesn't know a page for the current interface, we can't offer the jump link
|
||||
ui->artistTrackLabel->setJumpLinkVisible( ( ViewManager::instance()->pageForInterface( AudioEngine::instance()->currentTrackPlaylist() ) ) );
|
||||
|
||||
onControlStateChanged();
|
||||
|
||||
QPixmap sourceIcon = result->sourceIcon( TomahawkUtils::RoundedCorners, ui->ownerButton->size() );
|
||||
|
@@ -107,7 +107,6 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
#endif
|
||||
, ui( new Ui::TomahawkWindow )
|
||||
, m_searchWidget( 0 )
|
||||
, m_audioControls( new AudioControls( this ) )
|
||||
, m_trayIcon( new TomahawkTrayIcon( this ) )
|
||||
, m_settingsDialog( 0 )
|
||||
, m_audioRetryCounter( 0 )
|
||||
@@ -115,6 +114,8 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
|
||||
|
||||
ViewManager* vm = new ViewManager( this );
|
||||
m_audioControls = new AudioControls( this );
|
||||
|
||||
connect( vm, SIGNAL( showQueueRequested() ), SLOT( showQueue() ) );
|
||||
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
|
||||
@@ -415,6 +416,7 @@ TomahawkWindow::setupSideBar()
|
||||
|
||||
ui->splitter->addWidget( sidebarWidget );
|
||||
ui->splitter->addWidget( ViewManager::instance()->widget() );
|
||||
ui->splitter->setCollapsible( 0, false );
|
||||
ui->splitter->setCollapsible( 1, false );
|
||||
|
||||
ActionCollection::instance()->getAction( "showOfflineSources" )
|
||||
|
@@ -880,7 +880,7 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
|
||||
handlePeerStatus( jid, Jreen::Presence::Available );
|
||||
}
|
||||
}
|
||||
else if ( context == RequestVersion)
|
||||
else if ( context == RequestVersion )
|
||||
{
|
||||
Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload<Jreen::SoftwareVersion>();
|
||||
if ( softwareVersion )
|
||||
@@ -932,7 +932,7 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
|
||||
Tomahawk::peerinfo_ptr peerInfo = PeerInfo::get( this, iq.from().full() );
|
||||
if ( peerInfo.isNull() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "no valid peerInfo for " << iq.from().full();
|
||||
tDebug() << Q_FUNC_INFO << "no valid peerInfo for" << iq.from().full();
|
||||
return;
|
||||
}
|
||||
peerInfo->setSipInfo( info );
|
||||
|
@@ -162,6 +162,7 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
|
||||
|
||||
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( this, host, Tomahawk::PeerInfo::AutoCreate );
|
||||
peerInfo->setSipInfo( sipInfo );
|
||||
peerInfo->setContactId( host );
|
||||
peerInfo->setFriendlyName( name );
|
||||
peerInfo->setType( PeerInfo::Local );
|
||||
peerInfo->setStatus( PeerInfo::Online );
|
||||
|
@@ -78,6 +78,10 @@ ContextMenu::addToPlaylist( int playlistIdx )
|
||||
playlist->addEntries( m_queries, playlist->currentrevision() );
|
||||
}
|
||||
|
||||
bool caseInsensitiveLessThan(Tomahawk::playlist_ptr &s1, Tomahawk::playlist_ptr &s2)
|
||||
{
|
||||
return s1->title().toLower() < s2->title().toLower();
|
||||
}
|
||||
|
||||
void
|
||||
ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
@@ -97,7 +101,9 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
|
||||
if ( m_supportedActions & ActionPlaylist ) {
|
||||
// Get the current list of all playlists.
|
||||
m_playlists = SourceList::instance()->getLocal()->dbCollection()->playlists();
|
||||
m_playlists = QList< Tomahawk::playlist_ptr >( SourceList::instance()->getLocal()->dbCollection()->playlists() );
|
||||
// Sort the playlist
|
||||
qSort( m_playlists.begin(), m_playlists.end(), caseInsensitiveLessThan );
|
||||
m_playlists_sigmap = new QSignalMapper( this );
|
||||
|
||||
// Build the menu listing all available playlists
|
||||
|
@@ -58,8 +58,8 @@ PlaylistInterface::nextResult() const
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::result_ptr
|
||||
PlaylistInterface::siblingResult( int itemsAway, qint64 rootIndex ) const
|
||||
qint64
|
||||
PlaylistInterface::siblingResultIndex( int itemsAway, qint64 rootIndex ) const
|
||||
{
|
||||
qint64 idx = siblingIndex( itemsAway, rootIndex );
|
||||
QList< qint64 > safetyCheck;
|
||||
@@ -73,12 +73,49 @@ PlaylistInterface::siblingResult( int itemsAway, qint64 rootIndex ) const
|
||||
|
||||
if ( query && query->playable() )
|
||||
{
|
||||
return query->results().first();
|
||||
return idx;
|
||||
}
|
||||
|
||||
idx = siblingIndex( itemsAway < 0 ? -1 : 1, idx );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::result_ptr
|
||||
PlaylistInterface::siblingResult( int itemsAway, qint64 rootIndex ) const
|
||||
{
|
||||
qint64 idx = siblingResultIndex( itemsAway, rootIndex );
|
||||
if ( idx >= 0 )
|
||||
{
|
||||
Tomahawk::query_ptr query = queryAt( idx );
|
||||
|
||||
if ( query && query->playable() )
|
||||
{
|
||||
return query->results().first();
|
||||
}
|
||||
}
|
||||
|
||||
return Tomahawk::result_ptr();
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::result_ptr
|
||||
PlaylistInterface::setSiblingResult( int itemsAway, qint64 rootIndex )
|
||||
{
|
||||
qint64 idx = siblingResultIndex( itemsAway, rootIndex );
|
||||
if ( idx >= 0 )
|
||||
{
|
||||
Tomahawk::query_ptr query = queryAt( idx );
|
||||
|
||||
if ( query && query->playable() )
|
||||
{
|
||||
setCurrentIndex( idx );
|
||||
return query->results().first();
|
||||
}
|
||||
}
|
||||
|
||||
return Tomahawk::result_ptr();
|
||||
}
|
||||
|
||||
|
@@ -53,8 +53,10 @@ public:
|
||||
virtual Tomahawk::result_ptr previousResult() const;
|
||||
|
||||
virtual qint64 siblingIndex( int itemsAway, qint64 rootIndex = -1 ) const = 0;
|
||||
virtual qint64 siblingResultIndex( int itemsAway, qint64 rootIndex = -1 ) const;
|
||||
virtual Tomahawk::result_ptr siblingResult( int itemsAway, qint64 rootIndex = -1 ) const;
|
||||
|
||||
virtual Tomahawk::result_ptr setSiblingResult( int itemsAway, qint64 rootIndex = -1 );
|
||||
|
||||
virtual Tomahawk::result_ptr resultAt( qint64 index ) const = 0;
|
||||
virtual Tomahawk::query_ptr queryAt( qint64 index ) const = 0;
|
||||
virtual qint64 indexOfResult( const Tomahawk::result_ptr& result ) const = 0;
|
||||
|
@@ -61,6 +61,7 @@ namespace Tomahawk
|
||||
typedef QSharedPointer<Album> album_ptr;
|
||||
typedef QWeakPointer<Album> album_wptr;
|
||||
typedef QSharedPointer<PeerInfo> peerinfo_ptr;
|
||||
typedef QWeakPointer<PeerInfo> peerinfo_wptr;
|
||||
|
||||
typedef QSharedPointer<DynamicControl> dyncontrol_ptr;
|
||||
typedef QSharedPointer<GeneratorInterface> geninterface_ptr;
|
||||
|
@@ -508,6 +508,7 @@ ViewManager::destroyPage( ViewPage* page )
|
||||
return;
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Deleting page:" << page->title();
|
||||
|
||||
if ( historyPages().contains( page ) )
|
||||
{
|
||||
m_pageHistoryBack.removeAll( page );
|
||||
@@ -523,6 +524,10 @@ ViewManager::destroyPage( ViewPage* page )
|
||||
|
||||
historyBack();
|
||||
}
|
||||
|
||||
emit viewPageAboutToBeDestroyed( page );
|
||||
delete page;
|
||||
emit viewPageDestroyed();
|
||||
}
|
||||
|
||||
|
||||
@@ -659,6 +664,7 @@ ViewManager::onWidgetDestroyed( QWidget* widget )
|
||||
|
||||
m_pageHistoryBack.removeAll( page );
|
||||
m_pageHistoryFwd.removeAll( page );
|
||||
break;
|
||||
}
|
||||
|
||||
m_stack->removeWidget( widget );
|
||||
|
@@ -17,8 +17,8 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PLAYLISTMANAGER_H
|
||||
#define PLAYLISTMANAGER_H
|
||||
#ifndef VIEWMANAGER_H
|
||||
#define VIEWMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
@@ -115,6 +115,8 @@ signals:
|
||||
|
||||
void tempPageActivated( Tomahawk::ViewPage* );
|
||||
void viewPageActivated( Tomahawk::ViewPage* );
|
||||
void viewPageAboutToBeDestroyed( Tomahawk::ViewPage* );
|
||||
void viewPageDestroyed();
|
||||
|
||||
void showQueueRequested();
|
||||
void hideQueueRequested();
|
||||
@@ -206,4 +208,4 @@ private:
|
||||
static ViewManager* s_instance;
|
||||
};
|
||||
|
||||
#endif // PLAYLISTMANAGER_H
|
||||
#endif // VIEWMANAGER_H
|
||||
|
@@ -45,7 +45,6 @@
|
||||
#include <QtCore/QUrl>
|
||||
#include <QDir>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -72,6 +71,7 @@ AudioEngine::AudioEngine()
|
||||
, m_expectStop( false )
|
||||
, m_waitingOnNewTrack( false )
|
||||
, m_state( Stopped )
|
||||
, m_coverTempFile( 0 )
|
||||
{
|
||||
s_instance = this;
|
||||
tDebug() << "Init AudioEngine";
|
||||
@@ -395,24 +395,23 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type )
|
||||
{
|
||||
playInfo["cover"] = cover;
|
||||
|
||||
QTemporaryFile* coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) );
|
||||
if ( !coverTempFile->open() )
|
||||
delete m_coverTempFile;
|
||||
m_coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + m_currentTrack->artist()->name() + "_" + m_currentTrack->album()->name() + "_tomahawk_cover.png" ) );
|
||||
if ( !m_coverTempFile->open() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "WARNING: could not write temporary file for cover art!";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Finally, save the image to the new temp file
|
||||
coverTempFile->setAutoRemove( false );
|
||||
if ( cover.save( coverTempFile, "PNG" ) )
|
||||
if ( cover.save( m_coverTempFile, "PNG" ) )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *coverTempFile ).absoluteFilePath();
|
||||
playInfo["coveruri"] = QFileInfo( *coverTempFile ).absoluteFilePath();
|
||||
tDebug() << Q_FUNC_INFO << "Saving cover image to:" << QFileInfo( *m_coverTempFile ).absoluteFilePath();
|
||||
playInfo["coveruri"] = QFileInfo( *m_coverTempFile ).absoluteFilePath();
|
||||
}
|
||||
else
|
||||
tDebug() << Q_FUNC_INFO << "Failed to save cover image!";
|
||||
}
|
||||
delete coverTempFile;
|
||||
}
|
||||
else
|
||||
tDebug() << Q_FUNC_INFO << "Cover from query is null!";
|
||||
@@ -504,12 +503,11 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointe
|
||||
else
|
||||
{
|
||||
QString furl = m_currentTrack->url();
|
||||
#ifdef Q_WS_WIN
|
||||
if ( furl.startsWith( "file://" ) )
|
||||
furl = furl.right( furl.length() - 7 );
|
||||
#endif
|
||||
tLog( LOGVERBOSE ) << "Passing to Phonon:" << furl << furl.toLatin1();
|
||||
m_mediaObject->setCurrentSource( furl );
|
||||
|
||||
tLog( LOGVERBOSE ) << "Passing to Phonon:" << QUrl::fromLocalFile( furl );
|
||||
m_mediaObject->setCurrentSource( QUrl::fromLocalFile( furl ) );
|
||||
}
|
||||
|
||||
m_mediaObject->currentSource().setAutoDelete( true );
|
||||
@@ -558,7 +556,7 @@ AudioEngine::loadPreviousTrack()
|
||||
Tomahawk::result_ptr result;
|
||||
if ( m_playlist.data()->previousResult() )
|
||||
{
|
||||
result = m_playlist.data()->previousResult();
|
||||
result = m_playlist.data()->setSiblingResult( -1 );
|
||||
m_currentTrackPlaylist = m_playlist;
|
||||
}
|
||||
|
||||
@@ -599,7 +597,7 @@ AudioEngine::loadNextTrack()
|
||||
|
||||
if ( m_playlist.data()->nextResult() )
|
||||
{
|
||||
result = m_playlist.data()->nextResult();
|
||||
result = m_playlist.data()->setSiblingResult( 1 );
|
||||
m_currentTrackPlaylist = m_playlist;
|
||||
}
|
||||
}
|
||||
@@ -1004,7 +1002,7 @@ AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
|
||||
|
||||
if ( result )
|
||||
{
|
||||
if ( m_playlist )
|
||||
if ( m_playlist && m_playlist->currentItem() != result )
|
||||
{
|
||||
m_playlist->setCurrentIndex( m_playlist->indexOfResult( result ) );
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QQueue>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
|
||||
class DLLEXPORT AudioEngine : public QObject
|
||||
@@ -178,6 +179,8 @@ private:
|
||||
uint_fast8_t m_underrunCount;
|
||||
bool m_underrunNotified;
|
||||
|
||||
QTemporaryFile* m_coverTempFile;
|
||||
|
||||
static AudioEngine* s_instance;
|
||||
};
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2013, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@@ -49,6 +49,8 @@ DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex()
|
||||
|
||||
DatabaseCommand_UpdateSearchIndex::~DatabaseCommand_UpdateSearchIndex()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
if ( ! m_statusJob.isNull() )
|
||||
m_statusJob.data()->done();
|
||||
@@ -61,35 +63,30 @@ DatabaseCommand_UpdateSearchIndex::exec( DatabaseImpl* db )
|
||||
{
|
||||
db->m_fuzzyIndex->beginIndexing();
|
||||
|
||||
QMap< unsigned int, QMap< QString, QString > > data;
|
||||
TomahawkSqlQuery q = db->newquery();
|
||||
|
||||
q.exec( "SELECT track.id, track.name, artist.name, artist.id FROM track, artist WHERE artist.id = track.artist" );
|
||||
while ( q.next() )
|
||||
{
|
||||
QMap< QString, QString > track;
|
||||
track.insert( "track", q.value( 1 ).toString() );
|
||||
track.insert( "artist", q.value( 2 ).toString() );
|
||||
track.insert( "artistid", q.value( 3 ).toString() );
|
||||
IndexData ida;
|
||||
ida.id = q.value( 0 ).toUInt();
|
||||
ida.artistId = q.value( 3 ).toUInt();
|
||||
ida.track = q.value( 1 ).toString();
|
||||
ida.artist = q.value( 2 ).toString();
|
||||
|
||||
data.insert( q.value( 0 ).toUInt(), track );
|
||||
db->m_fuzzyIndex->appendFields( ida );
|
||||
}
|
||||
|
||||
db->m_fuzzyIndex->appendFields( data );
|
||||
data.clear();
|
||||
|
||||
q.exec( "SELECT album.id, album.name FROM album" );
|
||||
while ( q.next() )
|
||||
{
|
||||
QMap< QString, QString > album;
|
||||
album.insert( "album", q.value( 1 ).toString() );
|
||||
IndexData ida;
|
||||
ida.id = q.value( 0 ).toUInt();
|
||||
ida.album = q.value( 1 ).toString();
|
||||
|
||||
data.insert( q.value( 0 ).toUInt(), album );
|
||||
db->m_fuzzyIndex->appendFields( ida );
|
||||
}
|
||||
|
||||
db->m_fuzzyIndex->appendFields( data );
|
||||
|
||||
qDebug() << "Building index finished.";
|
||||
tDebug( LOGVERBOSE ) << "Building index finished.";
|
||||
|
||||
db->m_fuzzyIndex->endIndexing();
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2013, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,6 +25,15 @@
|
||||
|
||||
class IndexingJobItem;
|
||||
|
||||
struct IndexData
|
||||
{
|
||||
unsigned int id;
|
||||
unsigned int artistId;
|
||||
QString artist;
|
||||
QString album;
|
||||
QString track;
|
||||
};
|
||||
|
||||
class DLLEXPORT DatabaseCommand_UpdateSearchIndex : public DatabaseCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2013, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <CLucene.h>
|
||||
#include <CLucene/queryParser/MultiFieldQueryParser.h>
|
||||
|
||||
#include "DatabaseCommand_UpdateSearchIndex.h"
|
||||
#include "DatabaseImpl.h"
|
||||
#include "Database.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
@@ -112,10 +111,11 @@ FuzzyIndex::beginIndexing()
|
||||
|
||||
try
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Starting indexing.";
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Starting indexing.";
|
||||
if ( m_luceneReader != 0 )
|
||||
{
|
||||
qDebug() << "Deleting old lucene stuff.";
|
||||
tDebug( LOGVERBOSE ) << "Deleting old lucene stuff.";
|
||||
|
||||
m_luceneSearcher->close();
|
||||
m_luceneReader->close();
|
||||
delete m_luceneSearcher;
|
||||
@@ -124,8 +124,8 @@ FuzzyIndex::beginIndexing()
|
||||
m_luceneReader = 0;
|
||||
}
|
||||
|
||||
qDebug() << "Creating new index writer.";
|
||||
IndexWriter luceneWriter( m_luceneDir, m_analyzer, true );
|
||||
tDebug( LOGVERBOSE ) << "Creating new index writer.";
|
||||
m_luceneWriter = new IndexWriter( m_luceneDir, m_analyzer, true );
|
||||
}
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
@@ -138,62 +138,52 @@ FuzzyIndex::beginIndexing()
|
||||
void
|
||||
FuzzyIndex::endIndexing()
|
||||
{
|
||||
m_luceneWriter->optimize();
|
||||
m_luceneWriter->close();
|
||||
delete m_luceneWriter;
|
||||
m_luceneWriter = 0;
|
||||
|
||||
m_mutex.unlock();
|
||||
emit indexReady();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >& trackData )
|
||||
FuzzyIndex::appendFields( const IndexData& data )
|
||||
{
|
||||
try
|
||||
{
|
||||
tDebug() << "Appending to index:" << trackData.count();
|
||||
bool create = !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() );
|
||||
IndexWriter luceneWriter( m_luceneDir, m_analyzer, create );
|
||||
Document doc;
|
||||
|
||||
QMapIterator< unsigned int, QMap< QString, QString > > it( trackData );
|
||||
while ( it.hasNext() )
|
||||
if ( !data.track.isEmpty() )
|
||||
{
|
||||
it.next();
|
||||
unsigned int id = it.key();
|
||||
QMap< QString, QString > values = it.value();
|
||||
doc.add( *( _CLNEW Field( _T( "fulltext" ), DatabaseImpl::sortname( QString( "%1 %2" ).arg( data.artist ).arg( data.track ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
if ( values.contains( "track" ) )
|
||||
{
|
||||
doc.add( *( _CLNEW Field( _T( "fulltext" ), DatabaseImpl::sortname( QString( "%1 %2" ).arg( values.value( "artist" ) ).arg( values.value( "track" ) ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
doc.add( *( _CLNEW Field( _T( "track" ), DatabaseImpl::sortname( data.track ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "track" ), DatabaseImpl::sortname( values.value( "track" ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
doc.add( *( _CLNEW Field( _T( "artist" ), DatabaseImpl::sortname( data.artist ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "artist" ), DatabaseImpl::sortname( values.value( "artist" ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
doc.add( *( _CLNEW Field( _T( "artistid" ), QString::number( data.artistId ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "artistid" ), values.value( "artistid" ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "trackid" ), QString::number( id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
}
|
||||
else if ( values.contains( "album" ) )
|
||||
{
|
||||
doc.add( *( _CLNEW Field( _T( "album" ), DatabaseImpl::sortname( values.value( "album" ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "albumid" ), QString::number( id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
}
|
||||
else
|
||||
Q_ASSERT( false );
|
||||
|
||||
luceneWriter.addDocument( &doc );
|
||||
doc.clear();
|
||||
doc.add( *( _CLNEW Field( _T( "trackid" ), QString::number( data.id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
}
|
||||
else if ( !data.album.isEmpty() )
|
||||
{
|
||||
doc.add( *( _CLNEW Field( _T( "album" ), DatabaseImpl::sortname( data.album ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
luceneWriter.optimize();
|
||||
luceneWriter.close();
|
||||
doc.add( *( _CLNEW Field( _T( "albumid" ), QString::number( data.id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
}
|
||||
else
|
||||
Q_ASSERT( false );
|
||||
|
||||
m_luceneWriter->addDocument( &doc );
|
||||
}
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
@@ -223,7 +213,7 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
if ( !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() ) )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "index didn't exist.";
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "index didn't exist.";
|
||||
return resultsmap;
|
||||
}
|
||||
|
||||
@@ -314,7 +304,7 @@ FuzzyIndex::searchAlbum( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
if ( !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() ) )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "index didn't exist.";
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "index didn't exist.";
|
||||
return resultsmap;
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Copyright 2010-2013, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QMutex>
|
||||
|
||||
#include "Query.h"
|
||||
#include "DatabaseCommand_UpdateSearchIndex.h"
|
||||
|
||||
namespace lucene
|
||||
{
|
||||
@@ -60,7 +61,7 @@ public:
|
||||
|
||||
void beginIndexing();
|
||||
void endIndexing();
|
||||
void appendFields( const QMap< unsigned int, QMap< QString, QString > >& trackData );
|
||||
void appendFields( const IndexData& data );
|
||||
|
||||
signals:
|
||||
void indexReady();
|
||||
@@ -82,6 +83,7 @@ private:
|
||||
lucene::analysis::SimpleAnalyzer* m_analyzer;
|
||||
lucene::store::Directory* m_luceneDir;
|
||||
lucene::index::IndexReader* m_luceneReader;
|
||||
lucene::index::IndexWriter* m_luceneWriter;
|
||||
lucene::search::IndexSearcher* m_luceneSearcher;
|
||||
};
|
||||
|
||||
|
@@ -35,8 +35,6 @@
|
||||
#include "utils/Logger.h"
|
||||
#include "taglib/fileref.h"
|
||||
|
||||
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileInfo>
|
||||
@@ -231,7 +229,11 @@ MetadataEditor::loadResult( const Tomahawk::result_ptr& result )
|
||||
|
||||
if ( result->collection() && result->collection()->source()->isLocal() )
|
||||
{
|
||||
QFileInfo fi( QUrl( m_result->url() ).toLocalFile() );
|
||||
QString furl = m_result->url();
|
||||
if ( furl.startsWith( "file://" ) )
|
||||
furl = furl.right( furl.length() - 7 );
|
||||
|
||||
QFileInfo fi( furl );
|
||||
setFileName( fi.absoluteFilePath() );
|
||||
setFileSize( TomahawkUtils::filesizeToString( fi.size() ) );
|
||||
}
|
||||
|
@@ -298,7 +298,7 @@ Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
{
|
||||
if ( peerInfo->hasControlConnection() )
|
||||
{
|
||||
peerInfoDebug( peerInfo ) << "already had control connection, not doin nuffin: " << peerInfo->controlConnection()->name();
|
||||
peerInfoDebug( peerInfo ) << "already had control connection, doing nothing: " << peerInfo->controlConnection()->name();
|
||||
tLog() << "existing control connection has following peers:";
|
||||
foreach ( const peerinfo_ptr& otherPeerInfo, peerInfo->controlConnection()->peerInfos() )
|
||||
{
|
||||
@@ -311,7 +311,7 @@ Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
|
||||
if ( peerInfo->type() == Tomahawk::PeerInfo::Local )
|
||||
{
|
||||
peerInfoDebug(peerInfo) << "YAY, we need to establish the connection now.. thinking";
|
||||
peerInfoDebug(peerInfo) << "we need to establish the connection now... thinking";
|
||||
if ( !connectedToSession( peerInfo->sipInfo().nodeId() ) )
|
||||
{
|
||||
connectToPeer( peerInfo );
|
||||
@@ -336,17 +336,17 @@ Servent::registerPeer( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
else
|
||||
{
|
||||
SipInfo info;
|
||||
QString peerId = peerInfo->id();
|
||||
QString key = uuid();
|
||||
ControlConnection* conn = new ControlConnection( this );
|
||||
|
||||
const QString& nodeid = Database::instance()->impl()->dbid();
|
||||
conn->setName( peerInfo->contactId() );
|
||||
conn->setId( nodeid );
|
||||
conn->addPeerInfo( peerInfo );
|
||||
|
||||
if ( visibleExternally() )
|
||||
{
|
||||
QString peerId = peerInfo->id();
|
||||
QString key = uuid();
|
||||
ControlConnection* conn = new ControlConnection( this );
|
||||
|
||||
const QString& nodeid = Database::instance()->impl()->dbid();
|
||||
conn->setName( peerInfo->contactId() );
|
||||
conn->setId( nodeid );
|
||||
conn->addPeerInfo( peerInfo );
|
||||
|
||||
registerOffer( key, conn );
|
||||
info.setVisible( true );
|
||||
info.setHost( externalAddress() );
|
||||
@@ -414,6 +414,12 @@ void Servent::handleSipInfo( const Tomahawk::peerinfo_ptr& peerInfo )
|
||||
else
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "They are not visible, doing nothing atm";
|
||||
|
||||
if ( !visibleExternally() )
|
||||
{
|
||||
if ( peerInfo->controlConnection() )
|
||||
delete peerInfo->controlConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,10 +720,13 @@ Servent::connectToPeer( const peerinfo_ptr& peerInfo )
|
||||
SipInfo sipInfo = peerInfo->sipInfo();
|
||||
|
||||
peerInfoDebug( peerInfo ) << "connectToPeer: search for already established connections to the same nodeid:" << m_controlconnections.count() << "connections";
|
||||
if ( peerInfo->controlConnection() )
|
||||
delete peerInfo->controlConnection();
|
||||
|
||||
bool isDupe = false;
|
||||
ControlConnection* conn = 0;
|
||||
// try to find a ControlConnection with the same SipInfo, then we dont need to try to connect again
|
||||
|
||||
foreach ( ControlConnection* c, m_controlconnections )
|
||||
{
|
||||
Q_ASSERT( c );
|
||||
@@ -769,7 +778,6 @@ Servent::connectToPeer( const peerinfo_ptr& peerInfo )
|
||||
m["nodeid"] = Database::instance()->impl()->dbid();
|
||||
|
||||
peerInfoDebug(peerInfo) << "No match found, creating a new ControlConnection...";
|
||||
|
||||
conn = new ControlConnection( this );
|
||||
conn->addPeerInfo( peerInfo );
|
||||
conn->setFirstMessage( m );
|
||||
@@ -787,7 +795,7 @@ Servent::connectToPeer( const peerinfo_ptr& peerInfo )
|
||||
|
||||
|
||||
void
|
||||
Servent::connectToPeer( const QString& ha, int port, const QString &key, Connection* conn )
|
||||
Servent::connectToPeer( const QString& ha, int port, const QString& key, Connection* conn )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << "Servent::connectToPeer:" << ha << ":" << port
|
||||
<< thread() << QThread::currentThread();
|
||||
@@ -902,6 +910,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
// this is terrible, actually there should be a way to let this be created by the zeroconf plugin
|
||||
// because this way we rely on the ip being used as id in two totally different parts of the code
|
||||
Tomahawk::peerinfo_ptr peerInfo = Tomahawk::PeerInfo::get( account->sipPlugin(), peer.toString(), Tomahawk::PeerInfo::AutoCreate );
|
||||
peerInfo->setContactId( peer.toString() );
|
||||
peerInfoDebug( peerInfo );
|
||||
conn->addPeerInfo( peerInfo );
|
||||
return conn;
|
||||
|
@@ -118,8 +118,8 @@ public slots:
|
||||
|
||||
public:
|
||||
void connectToPeer( const Tomahawk::peerinfo_ptr& ha );
|
||||
void connectToPeer( const QString& ha, int port, const QString &key, Connection* conn );
|
||||
void reverseOfferRequest( ControlConnection* orig_conn, const QString &theirdbid, const QString& key, const QString& theirkey );
|
||||
void connectToPeer( const QString& ha, int port, const QString& key, Connection* conn );
|
||||
void reverseOfferRequest( ControlConnection* orig_conn, const QString& theirdbid, const QString& key, const QString& theirkey );
|
||||
|
||||
bool visibleExternally() const { return !m_externalHostname.isNull() || (m_externalPort > 0 && !m_externalAddress.isNull()); }
|
||||
QString externalAddress() const { return !m_externalHostname.isNull() ? m_externalHostname : m_externalAddress.toString(); }
|
||||
|
@@ -119,21 +119,28 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
|
||||
painter->setFont( boldFont );
|
||||
painter->setPen( option.palette.text().color().lighter( 450 ) );
|
||||
|
||||
|
||||
QRect figureRect = r.adjusted( 4, 0, 0, 0 );
|
||||
figureRect.setWidth( QFontMetrics( painter->font() ).width( "888" ) );
|
||||
painter->drawText( figureRect, QString::number( index.row() + 1 ), QTextOption( Qt::AlignCenter ) );
|
||||
|
||||
r.adjust( figureRect.width() + 12, 0, 0, 0 );
|
||||
QRect leftRect = r.adjusted( 0, 0, -48, 0 );
|
||||
QRect rightRect = r.adjusted( r.width() - smallBoldFontMetrics.width( TomahawkUtils::timeToString( duration ) ), 0, 0, 0 );
|
||||
|
||||
QString text = painter->fontMetrics().elidedText( track, Qt::ElideRight, leftRect.width() );
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
painter->drawText( leftRect, text, m_centerOption );
|
||||
QRect leftRect = r.adjusted( 0, 0, -( rightRect.width() + 8 ), 0 );
|
||||
|
||||
const int sourceIconSize = r.height();
|
||||
if ( q->numResults() && !q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) ).isNull() )
|
||||
|
||||
if ( hoveringOver() == index && index.column() == 0 )
|
||||
{
|
||||
const QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, QSize( sourceIconSize, sourceIconSize ) );
|
||||
QRect arrowRect = QRect( rightRect.right() - sourceIconSize, r.center().y() - sourceIconSize / 2, infoIcon.width(), infoIcon.height() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
|
||||
setInfoButtonRect( index, arrowRect );
|
||||
rightRect.moveLeft( rightRect.left() - infoIcon.width() - 8 );
|
||||
leftRect.adjust( 0, 0, -( infoIcon.width() + 8 ), 0 );
|
||||
}
|
||||
else if ( q->numResults() && !q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) ).isNull() )
|
||||
{
|
||||
const QPixmap sourceIcon = q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) );
|
||||
painter->setOpacity( 0.8 );
|
||||
@@ -142,6 +149,10 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
rightRect.moveLeft( rightRect.left() - sourceIcon.width() - 8 );
|
||||
}
|
||||
|
||||
QString text = painter->fontMetrics().elidedText( track, Qt::ElideRight, leftRect.width() );
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
painter->drawText( leftRect, text, m_centerOption );
|
||||
|
||||
if ( duration > 0 )
|
||||
{
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
|
@@ -29,18 +29,16 @@
|
||||
#include "Query.h"
|
||||
#include "Result.h"
|
||||
#include "Source.h"
|
||||
#include "audio/AudioEngine.h"
|
||||
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/PixmapDelegateFader.h"
|
||||
#include <utils/Closure.h>
|
||||
|
||||
#include "playlist/PlayableItem.h"
|
||||
#include "playlist/PlayableProxyModel.h"
|
||||
#include "GridView.h"
|
||||
#include "ViewManager.h"
|
||||
#include "utils/AnimatedSpinner.h"
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "playlist/PlayableItem.h"
|
||||
#include "playlist/PlayableProxyModel.h"
|
||||
#include "widgets/ImageButton.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/PixmapDelegateFader.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/AnimatedSpinner.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
namespace {
|
||||
@@ -377,7 +375,6 @@ GridItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const Q
|
||||
|
||||
if ( hoveringArtist )
|
||||
{
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
|
@@ -53,6 +53,7 @@ public:
|
||||
void setIsPlaying( bool b ) { m_isPlaying = b; emit dataChanged(); }
|
||||
bool fetchingMore() const { return m_fetchingMore; }
|
||||
void setFetchingMore( bool b ) { m_fetchingMore = b; }
|
||||
void requestRepaint() { emit dataChanged(); }
|
||||
|
||||
QString name() const;
|
||||
QString artistName() const;
|
||||
|
@@ -97,7 +97,6 @@ PlayableProxyModelPlaylistInterface::onCurrentIndexChanged()
|
||||
void
|
||||
PlayableProxyModelPlaylistInterface::setCurrentIndex( qint64 index )
|
||||
{
|
||||
Q_ASSERT( m_proxyModel );
|
||||
if ( m_proxyModel.isNull() )
|
||||
return;
|
||||
|
||||
|
@@ -43,7 +43,7 @@ using namespace Tomahawk;
|
||||
|
||||
|
||||
PlaylistChartItemDelegate::PlaylistChartItemDelegate( TrackView* parent, PlayableProxyModel* proxy )
|
||||
: QStyledItemDelegate( (QObject*)parent )
|
||||
: PlaylistItemDelegate( parent, proxy )
|
||||
, m_view( parent )
|
||||
, m_model( proxy )
|
||||
{
|
||||
@@ -59,11 +59,8 @@ PlaylistChartItemDelegate::PlaylistChartItemDelegate( TrackView* parent, Playabl
|
||||
m_bottomOption = QTextOption( Qt::AlignBottom );
|
||||
m_bottomOption.setWrapMode( QTextOption::NoWrap );
|
||||
|
||||
connect( this, SIGNAL( updateIndex( QModelIndex ) ), parent, SLOT( update( QModelIndex ) ) );
|
||||
|
||||
connect( m_model, SIGNAL( modelReset() ), this, SLOT( modelChanged() ) );
|
||||
if ( PlaylistView* plView = qobject_cast< PlaylistView* >( parent ) )
|
||||
connect( plView, SIGNAL( modelChanged() ), this, SLOT( modelChanged() ) );
|
||||
connect( proxy, SIGNAL( modelReset() ), SLOT( modelChanged() ) );
|
||||
connect( parent, SIGNAL( modelChanged() ), SLOT( modelChanged() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -99,25 +96,6 @@ PlaylistChartItemDelegate::sizeHint( const QStyleOptionViewItem& option, const Q
|
||||
}
|
||||
|
||||
|
||||
QWidget*
|
||||
PlaylistChartItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
Q_UNUSED( parent );
|
||||
Q_UNUSED( option );
|
||||
Q_UNUSED( index );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistChartItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const
|
||||
{
|
||||
initStyleOption( option, index );
|
||||
|
||||
TomahawkUtils::prepareStyleOption( option, index, item );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistChartItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
@@ -143,7 +121,7 @@ PlaylistChartItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
painter->save();
|
||||
{
|
||||
QRect r = opt.rect.adjusted( 4, 6, 0, -6 );
|
||||
|
||||
|
||||
// Paint Now Playing Speaker Icon
|
||||
if ( item->isPlaying() )
|
||||
{
|
||||
@@ -214,7 +192,29 @@ PlaylistChartItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
painter->drawPixmap( pixmapRect, pixmap );
|
||||
|
||||
r.adjust( pixmapRect.width() + figureRect.width() + 18, 1, -28, 0 );
|
||||
QRect leftRect = r.adjusted( 0, 0, -durationFontMetrics.width( TomahawkUtils::timeToString( duration ) ) - 8, 0 );
|
||||
QRect rightRect = r.adjusted( r.width() - durationFontMetrics.width( TomahawkUtils::timeToString( duration ) ), 0, 0, 0 );
|
||||
QRect leftRect = r.adjusted( 0, 0, -( rightRect.width() + 8 ), 0 );
|
||||
|
||||
/* const int sourceIconSize = r.height();
|
||||
|
||||
if ( hoveringOver() == index && index.column() == 0 )
|
||||
{
|
||||
const QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, QSize( sourceIconSize, sourceIconSize ) );
|
||||
QRect arrowRect = QRect( rightRect.right() - sourceIconSize, r.center().y() - sourceIconSize / 2, infoIcon.width(), infoIcon.height() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
|
||||
setInfoButtonRect( index, arrowRect );
|
||||
rightRect.moveLeft( rightRect.left() - infoIcon.width() - 8 );
|
||||
leftRect.adjust( 0, 0, -( infoIcon.width() + 8 ), 0 );
|
||||
}
|
||||
else if ( q->numResults() && !q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) ).isNull() )
|
||||
{
|
||||
const QPixmap sourceIcon = q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) );
|
||||
painter->setOpacity( 0.8 );
|
||||
painter->drawPixmap( QRect( rightRect.right() - sourceIconSize, r.center().y() - sourceIconSize / 2, sourceIcon.width(), sourceIcon.height() ), sourceIcon );
|
||||
painter->setOpacity( 1.0 );
|
||||
rightRect.moveLeft( rightRect.left() - sourceIcon.width() - 8 );
|
||||
}*/
|
||||
|
||||
painter->setFont( boldFont );
|
||||
QString text = painter->fontMetrics().elidedText( track, Qt::ElideRight, leftRect.width() );
|
||||
@@ -226,10 +226,9 @@ PlaylistChartItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
|
||||
if ( duration > 0 )
|
||||
{
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
painter->setFont( durationFont );
|
||||
QRect rightRect = r.adjusted( r.width() - durationFontMetrics.width( TomahawkUtils::timeToString( duration ) ), 0, 0, 0 );
|
||||
text = painter->fontMetrics().elidedText( TomahawkUtils::timeToString( duration ), Qt::ElideRight, rightRect.width() );
|
||||
painter->drawText( rightRect, text, m_centerRightOption );
|
||||
painter->drawText( rightRect, TomahawkUtils::timeToString( duration ), m_centerRightOption );
|
||||
}
|
||||
}
|
||||
painter->restore();
|
||||
@@ -239,7 +238,8 @@ PlaylistChartItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
void
|
||||
PlaylistChartItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx )
|
||||
{
|
||||
emit updateIndex( idx );
|
||||
if ( idx.isValid() )
|
||||
emit updateIndex( idx );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -19,9 +19,9 @@
|
||||
#ifndef PLAYLISTCHARTITEMDELEGATE_H
|
||||
#define PLAYLISTCHARTITEMDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QTextOption>
|
||||
|
||||
#include "PlaylistItemDelegate.h"
|
||||
#include "DllMacro.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
@@ -35,37 +35,32 @@ class PlayableItem;
|
||||
class PlayableProxyModel;
|
||||
class TrackView;
|
||||
|
||||
class DLLEXPORT PlaylistChartItemDelegate : public QStyledItemDelegate
|
||||
class DLLEXPORT PlaylistChartItemDelegate : public PlaylistItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlaylistChartItemDelegate( TrackView* parent = 0, PlayableProxyModel* proxy = 0 );
|
||||
|
||||
signals:
|
||||
void updateIndex( const QModelIndex& idx );
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
protected:
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
private slots:
|
||||
void modelChanged();
|
||||
void doUpdateIndex( const QPersistentModelIndex& idx );
|
||||
void modelChanged();
|
||||
|
||||
private:
|
||||
void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const;
|
||||
|
||||
QTextOption m_topOption;
|
||||
QTextOption m_centerOption;
|
||||
QTextOption m_centerRightOption;
|
||||
QTextOption m_bottomOption;
|
||||
|
||||
mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_pixmaps;
|
||||
|
||||
TrackView* m_view;
|
||||
PlayableProxyModel* m_model;
|
||||
|
||||
mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_pixmaps;
|
||||
};
|
||||
|
||||
#endif // PLAYLISTCHARTITEMDELEGATE_H
|
||||
|
@@ -21,10 +21,12 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "Query.h"
|
||||
#include "Result.h"
|
||||
#include "Artist.h"
|
||||
#include "Album.h"
|
||||
#include "Source.h"
|
||||
#include "SourceList.h"
|
||||
|
||||
@@ -33,6 +35,7 @@
|
||||
#include "PlayableProxyModel.h"
|
||||
#include "TrackView.h"
|
||||
#include "ViewHeader.h"
|
||||
#include "ViewManager.h"
|
||||
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
@@ -82,16 +85,6 @@ PlaylistItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModel
|
||||
}
|
||||
|
||||
|
||||
QWidget*
|
||||
PlaylistItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
Q_UNUSED( parent );
|
||||
Q_UNUSED( option );
|
||||
Q_UNUSED( index );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const
|
||||
{
|
||||
@@ -210,6 +203,7 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem&
|
||||
text = painter->fontMetrics().elidedText( lowerText, Qt::ElideRight, r.width() );
|
||||
painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_bottomOption );
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
@@ -228,7 +222,7 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
opt.text.clear();
|
||||
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
|
||||
|
||||
if ( m_view->hoveredIndex().row() == index.row() && m_view->hoveredIndex().column() == index.column() && !index.data().toString().isEmpty() &&
|
||||
if ( m_hoveringOver == index && !index.data().toString().isEmpty() &&
|
||||
( index.column() == PlayableModel::Artist || index.column() == PlayableModel::Album || index.column() == PlayableModel::Track ) )
|
||||
{
|
||||
opt.rect.setWidth( opt.rect.width() - opt.rect.height() - 2 );
|
||||
@@ -236,6 +230,8 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
|
||||
QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, arrowRect.size() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
|
||||
m_infoButtonRects[ index ] = arrowRect;
|
||||
}
|
||||
|
||||
painter->save();
|
||||
@@ -289,3 +285,103 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
QStyledItemDelegate::editorEvent( event, model, option, index );
|
||||
|
||||
if ( event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseMove &&
|
||||
event->type() != QEvent::Leave )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hoveringInfo = false;
|
||||
if ( m_infoButtonRects.contains( index ) )
|
||||
{
|
||||
const QRect infoRect = m_infoButtonRects[ index ];
|
||||
const QMouseEvent* ev = static_cast< QMouseEvent* >( event );
|
||||
hoveringInfo = infoRect.contains( ev->pos() );
|
||||
}
|
||||
|
||||
if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
if ( hoveringInfo )
|
||||
m_view->setCursor( Qt::PointingHandCursor );
|
||||
else
|
||||
m_view->setCursor( Qt::ArrowCursor );
|
||||
|
||||
if ( m_hoveringOver != index )
|
||||
{
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
item->requestRepaint();
|
||||
m_hoveringOver = index;
|
||||
emit updateIndex( m_hoveringOver );
|
||||
}
|
||||
|
||||
// We return false here so the view can still decide to process/trigger things like D&D events
|
||||
return false;
|
||||
}
|
||||
|
||||
// reset mouse cursor. we switch to a pointing hand cursor when hovering an info button
|
||||
m_view->setCursor( Qt::ArrowCursor );
|
||||
|
||||
if ( hoveringInfo )
|
||||
{
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
if ( !item )
|
||||
return false;
|
||||
|
||||
if ( m_model->style() != PlayableProxyModel::Detailed )
|
||||
{
|
||||
if ( item->query() )
|
||||
ViewManager::instance()->show( item->query()->displayQuery() );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( index.column() )
|
||||
{
|
||||
case PlayableModel::Artist:
|
||||
{
|
||||
ViewManager::instance()->show( Artist::get( item->query()->displayQuery()->artist() ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case PlayableModel::Album:
|
||||
{
|
||||
artist_ptr artist = Artist::get( item->query()->displayQuery()->artist() );
|
||||
ViewManager::instance()->show( Album::get( artist, item->query()->displayQuery()->album() ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case PlayableModel::Track:
|
||||
{
|
||||
ViewManager::instance()->show( item->query()->displayQuery() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistItemDelegate::resetHoverIndex()
|
||||
{
|
||||
m_hoveringOver = QModelIndex();
|
||||
m_infoButtonRects.clear();
|
||||
}
|
||||
|
@@ -40,6 +40,9 @@ public:
|
||||
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
public slots:
|
||||
void resetHoverIndex();
|
||||
|
||||
signals:
|
||||
void updateIndex( const QModelIndex& idx );
|
||||
|
||||
@@ -47,7 +50,10 @@ protected:
|
||||
void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const;
|
||||
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||
|
||||
QPersistentModelIndex hoveringOver() const { return m_hoveringOver; }
|
||||
void setInfoButtonRect( const QPersistentModelIndex& index, const QRect& rect ) const { m_infoButtonRects[ index ] = rect; }
|
||||
|
||||
private:
|
||||
void paintDetailed( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
@@ -56,6 +62,9 @@ private:
|
||||
QTextOption m_topOption;
|
||||
QTextOption m_bottomOption;
|
||||
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_infoButtonRects;
|
||||
QPersistentModelIndex m_hoveringOver;
|
||||
|
||||
TrackView* m_view;
|
||||
PlayableProxyModel* m_model;
|
||||
};
|
||||
|
@@ -190,8 +190,31 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
smallFont.setPointSize( TomahawkUtils::defaultFontSize() - 1 );
|
||||
|
||||
r.adjust( pixmapRect.width() + 12, 1, - 16, 0 );
|
||||
QRect leftRect = r.adjusted( 0, 0, -48, 0 );
|
||||
QRect rightRect = r.adjusted( r.width() - smallBoldFontMetrics.width( TomahawkUtils::timeToString( duration ) ), 0, 0, 0 );
|
||||
QRect leftRect = r.adjusted( 0, 0, -( rightRect.width() + 8 ), 0 );
|
||||
|
||||
const int sourceIconSize = avatarRect.width() - 6;
|
||||
|
||||
if ( hoveringOver() == index && !index.data().toString().isEmpty() && index.column() == 0 )
|
||||
{
|
||||
const QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, QSize( sourceIconSize, sourceIconSize ) );
|
||||
QRect arrowRect = QRect( rightRect.right() - sourceIconSize, r.center().y() - sourceIconSize / 2, infoIcon.width(), infoIcon.height() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
|
||||
setInfoButtonRect( index, arrowRect );
|
||||
rightRect.moveLeft( rightRect.left() - infoIcon.width() - 8 );
|
||||
leftRect.adjust( 0, 0, -( infoIcon.width() + 8 ), 0 );
|
||||
}
|
||||
else if ( q->numResults() && !q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) ).isNull() )
|
||||
{
|
||||
const QPixmap sourceIcon = q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) );
|
||||
painter->setOpacity( 0.8 );
|
||||
painter->drawPixmap( QRect( rightRect.right() - sourceIconSize, r.center().y() - sourceIconSize / 2, sourceIcon.width(), sourceIcon.height() ), sourceIcon );
|
||||
painter->setOpacity( 1.0 );
|
||||
|
||||
rightRect.moveLeft( rightRect.left() - sourceIcon.width() - 8 );
|
||||
leftRect.adjust( 0, 0, -( sourceIcon.width() + 8 ), 0 );
|
||||
}
|
||||
|
||||
painter->setFont( boldFont );
|
||||
QString text = painter->fontMetrics().elidedText( track, Qt::ElideRight, leftRect.width() );
|
||||
@@ -207,7 +230,8 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
textDoc.setDefaultFont( painter->font() );
|
||||
textDoc.setDefaultTextOption( m_topOption );
|
||||
|
||||
drawRichText( painter, opt, leftRect.adjusted( 0, boldFontMetrics.height() + 1, 0, 0 ), Qt::AlignTop, textDoc );
|
||||
if ( textDoc.idealWidth() <= leftRect.width() )
|
||||
drawRichText( painter, opt, leftRect.adjusted( 0, boldFontMetrics.height() + 1, 0, 0 ), Qt::AlignTop, textDoc );
|
||||
|
||||
if ( !( option.state & QStyle::State_Selected || item->isPlaying() ) )
|
||||
painter->setPen( Qt::gray );
|
||||
@@ -222,16 +246,6 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
|
||||
|
||||
drawRichText( painter, opt, leftRect, Qt::AlignBottom, textDoc );
|
||||
|
||||
const int sourceIconSize = avatarRect.width() - 6;
|
||||
if ( q->numResults() && !q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) ).isNull() )
|
||||
{
|
||||
const QPixmap sourceIcon = q->results().first()->sourceIcon( TomahawkUtils::RoundedCorners, QSize( sourceIconSize, sourceIconSize ) );
|
||||
painter->setOpacity( 0.8 );
|
||||
painter->drawPixmap( QRect( rightRect.right() - sourceIconSize, r.center().y() - sourceIconSize / 2, sourceIcon.width(), sourceIcon.height() ), sourceIcon );
|
||||
painter->setOpacity( 1.0 );
|
||||
rightRect.moveLeft( rightRect.left() - sourceIcon.width() - 8 );
|
||||
}
|
||||
|
||||
if ( duration > 0 )
|
||||
{
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
|
@@ -25,8 +25,6 @@
|
||||
#include "PlayableProxyModel.h"
|
||||
#include "PlayableItem.h"
|
||||
#include "DropJob.h"
|
||||
#include "Artist.h"
|
||||
#include "Album.h"
|
||||
#include "Source.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "audio/AudioEngine.h"
|
||||
@@ -154,14 +152,14 @@ TrackView::setProxyModel( PlayableProxyModel* model )
|
||||
disconnect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( verifySize() ) );
|
||||
disconnect( m_proxyModel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( verifySize() ) );
|
||||
}
|
||||
|
||||
|
||||
m_proxyModel = model;
|
||||
|
||||
connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) );
|
||||
connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) );
|
||||
connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( verifySize() ) );
|
||||
connect( m_proxyModel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), SLOT( verifySize() ) );
|
||||
|
||||
|
||||
m_delegate = new PlaylistItemDelegate( this, m_proxyModel );
|
||||
setItemDelegate( m_delegate );
|
||||
|
||||
@@ -360,6 +358,7 @@ TrackView::tryToPlayItem( const QModelIndex& index )
|
||||
PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) );
|
||||
if ( item && !item->query().isNull() )
|
||||
{
|
||||
m_model->setCurrentIndex( m_proxyModel->mapToSource( index ) );
|
||||
AudioEngine::instance()->playItem( playlistInterface(), item->query() );
|
||||
|
||||
return true;
|
||||
@@ -563,6 +562,16 @@ TrackView::paintEvent( QPaintEvent* event )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::wheelEvent( QWheelEvent* event )
|
||||
{
|
||||
QTreeView::wheelEvent( event );
|
||||
|
||||
m_delegate->resetHoverIndex();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::onFilterChanged( const QString& )
|
||||
{
|
||||
@@ -683,105 +692,6 @@ TrackView::onMenuTriggered( int action )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::updateHoverIndex( const QPoint& pos )
|
||||
{
|
||||
QModelIndex idx = indexAt( pos );
|
||||
|
||||
if ( idx != m_hoveredIndex )
|
||||
{
|
||||
m_hoveredIndex = idx;
|
||||
repaint();
|
||||
}
|
||||
|
||||
if ( !m_model || m_proxyModel->style() != PlayableProxyModel::Detailed )
|
||||
return;
|
||||
|
||||
if ( idx.column() == PlayableModel::Artist || idx.column() == PlayableModel::Album || idx.column() == PlayableModel::Track )
|
||||
{
|
||||
if ( pos.x() > header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) - 16 &&
|
||||
pos.x() < header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) )
|
||||
{
|
||||
setCursor( Qt::PointingHandCursor );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( cursor().shape() != Qt::ArrowCursor )
|
||||
setCursor( Qt::ArrowCursor );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::wheelEvent( QWheelEvent* event )
|
||||
{
|
||||
QTreeView::wheelEvent( event );
|
||||
|
||||
if ( m_hoveredIndex.isValid() )
|
||||
{
|
||||
m_hoveredIndex = QModelIndex();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::leaveEvent( QEvent* event )
|
||||
{
|
||||
QTreeView::leaveEvent( event );
|
||||
updateHoverIndex( QPoint( -1, -1 ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
QTreeView::mouseMoveEvent( event );
|
||||
updateHoverIndex( event->pos() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackView::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
QTreeView::mousePressEvent( event );
|
||||
|
||||
if ( !m_model || m_proxyModel->style() != PlayableProxyModel::Detailed )
|
||||
return;
|
||||
|
||||
QModelIndex idx = indexAt( event->pos() );
|
||||
if ( event->pos().x() > header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) - 16 &&
|
||||
event->pos().x() < header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) )
|
||||
{
|
||||
PlayableItem* item = proxyModel()->itemFromIndex( proxyModel()->mapToSource( idx ) );
|
||||
switch ( idx.column() )
|
||||
{
|
||||
case PlayableModel::Artist:
|
||||
{
|
||||
ViewManager::instance()->show( Artist::get( item->query()->displayQuery()->artist() ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case PlayableModel::Album:
|
||||
{
|
||||
artist_ptr artist = Artist::get( item->query()->displayQuery()->artist() );
|
||||
ViewManager::instance()->show( Album::get( artist, item->query()->displayQuery()->album() ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case PlayableModel::Track:
|
||||
{
|
||||
ViewManager::instance()->show( item->query()->displayQuery() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Tomahawk::playlistinterface_ptr
|
||||
TrackView::playlistInterface() const
|
||||
{
|
||||
|
@@ -75,7 +75,6 @@ public:
|
||||
virtual bool setFilter( const QString& filter );
|
||||
virtual bool jumpToCurrentTrack();
|
||||
|
||||
QModelIndex hoveredIndex() const { return m_hoveredIndex; }
|
||||
QModelIndex contextMenuIndex() const { return m_contextMenuIndex; }
|
||||
void setContextMenuIndex( const QModelIndex& idx ) { m_contextMenuIndex = idx; }
|
||||
|
||||
@@ -112,12 +111,9 @@ protected:
|
||||
virtual void dragMoveEvent( QDragMoveEvent* event );
|
||||
virtual void dropEvent( QDropEvent* event );
|
||||
|
||||
virtual void wheelEvent( QWheelEvent* event );
|
||||
virtual void mouseMoveEvent( QMouseEvent* event );
|
||||
virtual void mousePressEvent( QMouseEvent* event );
|
||||
virtual void leaveEvent( QEvent* event );
|
||||
virtual void paintEvent( QPaintEvent* event );
|
||||
virtual void keyPressEvent( QKeyEvent* event );
|
||||
virtual void wheelEvent( QWheelEvent* event );
|
||||
|
||||
protected slots:
|
||||
virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous );
|
||||
@@ -131,7 +127,7 @@ private slots:
|
||||
void autoPlayResolveFinished( const Tomahawk::query_ptr& query, int row );
|
||||
|
||||
void verifySize();
|
||||
|
||||
|
||||
private:
|
||||
void startAutoPlay( const QModelIndex& index );
|
||||
bool tryToPlayItem( const QModelIndex& index );
|
||||
@@ -153,7 +149,6 @@ private:
|
||||
bool m_updateContextView;
|
||||
bool m_autoResize;
|
||||
|
||||
QModelIndex m_hoveredIndex;
|
||||
QModelIndex m_contextMenuIndex;
|
||||
|
||||
Tomahawk::query_ptr m_autoPlaying;
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <QPainter>
|
||||
#include <QAbstractItemView>
|
||||
#include <QHeaderView>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "Query.h"
|
||||
#include "Result.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "PlayableItem.h"
|
||||
#include "TreeProxyModel.h"
|
||||
#include "TreeView.h"
|
||||
#include "ViewManager.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
|
||||
@@ -73,7 +75,7 @@ TreeItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelInde
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// artist per default
|
||||
size.setHeight( option.fontMetrics.height() * 4 );
|
||||
return size;
|
||||
@@ -135,13 +137,15 @@ TreeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
if ( oldX > 0 )
|
||||
o.rect.setX( oldX );
|
||||
|
||||
if ( m_view->hoveredIndex() == index && !index.data().toString().isEmpty() && index.column() == 0 )
|
||||
if ( m_hoveringOver == index && !index.data().toString().isEmpty() && index.column() == 0 )
|
||||
{
|
||||
o.rect.setWidth( o.rect.width() - o.rect.height() );
|
||||
QRect arrowRect( o.rect.x() + o.rect.width(), o.rect.y() + 1, o.rect.height() - 2, o.rect.height() - 2 );
|
||||
|
||||
QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, arrowRect.size() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
|
||||
m_infoButtonRects[ index ] = arrowRect;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -182,6 +186,15 @@ TreeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
opt.palette.setColor( QPalette::Text, opt.palette.color( QPalette::HighlightedText ) );
|
||||
}
|
||||
|
||||
QRect arrowRect( m_view->viewport()->width() - option.rect.height(), option.rect.y() + 1, option.rect.height() - 2, option.rect.height() - 2 );
|
||||
if ( m_hoveringOver.row() == index.row() && m_hoveringOver.parent() == index.parent() )
|
||||
{
|
||||
QPixmap infoIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::InfoIcon, TomahawkUtils::Original, arrowRect.size() );
|
||||
painter->drawPixmap( arrowRect, infoIcon );
|
||||
|
||||
m_infoButtonRects[ index ] = arrowRect;
|
||||
}
|
||||
|
||||
if ( index.column() > 0 )
|
||||
return;
|
||||
|
||||
@@ -209,7 +222,6 @@ TreeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
}
|
||||
|
||||
const QPixmap cover = m_pixmaps[ index ]->currentPixmap();
|
||||
|
||||
painter->drawPixmap( r, cover );
|
||||
|
||||
r = option.rect.adjusted( option.rect.height(), 6, -4, -option.rect.height() + 22 );
|
||||
@@ -226,3 +238,88 @@ TreeItemDelegate::doUpdateIndex( const QPersistentModelIndex& index )
|
||||
emit updateIndex( index );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TreeItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
Q_UNUSED( model );
|
||||
Q_UNUSED( option );
|
||||
|
||||
if ( event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseMove &&
|
||||
event->type() != QEvent::MouseButtonPress &&
|
||||
event->type() != QEvent::Leave )
|
||||
return false;
|
||||
|
||||
bool hoveringInfo = false;
|
||||
if ( m_infoButtonRects.contains( index ) )
|
||||
{
|
||||
const QRect infoRect = m_infoButtonRects[ index ];
|
||||
const QMouseEvent* ev = static_cast< QMouseEvent* >( event );
|
||||
hoveringInfo = infoRect.contains( ev->pos() );
|
||||
}
|
||||
|
||||
if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
if ( hoveringInfo )
|
||||
m_view->setCursor( Qt::PointingHandCursor );
|
||||
else
|
||||
m_view->setCursor( Qt::ArrowCursor );
|
||||
|
||||
if ( m_hoveringOver != index )
|
||||
{
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
item->requestRepaint();
|
||||
m_hoveringOver = index;
|
||||
emit updateIndex( m_hoveringOver );
|
||||
}
|
||||
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
// reset mouse cursor. we switch to a pointing hand cursor when hovering an info button
|
||||
m_view->setCursor( Qt::ArrowCursor );
|
||||
|
||||
if ( hoveringInfo )
|
||||
{
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
if ( !item )
|
||||
return false;
|
||||
|
||||
if ( item->query() )
|
||||
{
|
||||
ViewManager::instance()->show( item->query()->displayQuery() );
|
||||
}
|
||||
else if ( item->artist() )
|
||||
{
|
||||
ViewManager::instance()->show( item->artist() );
|
||||
}
|
||||
else if ( item->album() )
|
||||
{
|
||||
ViewManager::instance()->show( item->album() );
|
||||
}
|
||||
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
else if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
// Stop the whole item from having a down click action as we just want the info button to be clicked
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeItemDelegate::resetHoverIndex()
|
||||
{
|
||||
m_hoveringOver = QModelIndex();
|
||||
m_infoButtonRects.clear();
|
||||
}
|
||||
|
@@ -40,8 +40,12 @@ public:
|
||||
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
public slots:
|
||||
void resetHoverIndex();
|
||||
|
||||
protected:
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||
|
||||
signals:
|
||||
void updateIndex( const QModelIndex& idx );
|
||||
@@ -54,6 +58,8 @@ private:
|
||||
TreeProxyModel* m_model;
|
||||
|
||||
mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_pixmaps;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_infoButtonRects;
|
||||
QPersistentModelIndex m_hoveringOver;
|
||||
};
|
||||
|
||||
#endif // TREEITEMDELEGATE_H
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "database/DatabaseImpl.h"
|
||||
#include "collection/AlbumsRequest.h"
|
||||
#include "collection/ArtistsRequest.h"
|
||||
#include "database/DatabaseCommand_AllAlbums.h"
|
||||
#include "PlayableItem.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
@@ -73,7 +74,11 @@ TreeProxyModel::onRowsInserted( const QModelIndex& parent, int /* start */, int
|
||||
if ( pi->artist().isNull() )
|
||||
return;
|
||||
|
||||
Tomahawk::AlbumsRequest* cmd = m_model->collection()->requestAlbums( pi->artist() );
|
||||
Tomahawk::AlbumsRequest* cmd = 0;
|
||||
if ( !m_model->collection().isNull() )
|
||||
cmd = m_model->collection()->requestAlbums( pi->artist() );
|
||||
else
|
||||
cmd = new DatabaseCommand_AllAlbums( Tomahawk::collection_ptr(), pi->artist() );
|
||||
|
||||
cmd->setFilter( m_filter );
|
||||
|
||||
@@ -115,7 +120,11 @@ TreeProxyModel::setFilter( const QString& pattern )
|
||||
}
|
||||
else
|
||||
{
|
||||
Tomahawk::ArtistsRequest* cmd = m_model->collection()->requestArtists();
|
||||
Tomahawk::ArtistsRequest* cmd = 0;
|
||||
if ( !m_model->collection().isNull() )
|
||||
cmd = m_model->collection()->requestArtists();
|
||||
else
|
||||
cmd = new DatabaseCommand_AllArtists(); //for SuperCollection, TODO: replace with a proper proxy-ArtistsRequest
|
||||
|
||||
cmd->setFilter( pattern );
|
||||
m_artistsFilterCmd = cmd;
|
||||
|
@@ -53,6 +53,7 @@ TreeView::TreeView( QWidget* parent )
|
||||
, m_overlay( new OverlayWidget( this ) )
|
||||
, m_model( 0 )
|
||||
, m_proxyModel( 0 )
|
||||
, m_delegate( 0 )
|
||||
, m_loadingSpinner( new LoadingSpinner( this ) )
|
||||
, m_updateContextView( true )
|
||||
, m_contextMenu( new ContextMenu( this ) )
|
||||
@@ -99,9 +100,9 @@ void
|
||||
TreeView::setProxyModel( TreeProxyModel* model )
|
||||
{
|
||||
m_proxyModel = model;
|
||||
TreeItemDelegate* del = new TreeItemDelegate( this, m_proxyModel );
|
||||
connect( del, SIGNAL( updateIndex( QModelIndex ) ), this, SLOT( update( QModelIndex ) ) );
|
||||
setItemDelegate( del );
|
||||
m_delegate = new TreeItemDelegate( this, m_proxyModel );
|
||||
connect( m_delegate, SIGNAL( updateIndex( QModelIndex ) ), SLOT( update( QModelIndex ) ) );
|
||||
setItemDelegate( m_delegate );
|
||||
|
||||
QTreeView::setModel( m_proxyModel );
|
||||
}
|
||||
@@ -234,7 +235,7 @@ TreeView::onItemActivated( const QModelIndex& index )
|
||||
PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) );
|
||||
if ( item )
|
||||
{
|
||||
if ( !item->artist().isNull() )
|
||||
/* if ( !item->artist().isNull() )
|
||||
{
|
||||
ViewManager::instance()->show( item->artist() );
|
||||
}
|
||||
@@ -242,7 +243,7 @@ TreeView::onItemActivated( const QModelIndex& index )
|
||||
{
|
||||
ViewManager::instance()->show( item->album() );
|
||||
}
|
||||
else if ( !item->result().isNull() && item->result()->isOnline() )
|
||||
else */ if ( !item->result().isNull() && item->result()->isOnline() )
|
||||
{
|
||||
AudioEngine::instance()->playItem( m_proxyModel->playlistInterface(), item->result() );
|
||||
}
|
||||
@@ -285,6 +286,16 @@ TreeView::resizeEvent( QResizeEvent* event )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::wheelEvent( QWheelEvent* event )
|
||||
{
|
||||
QTreeView::wheelEvent( event );
|
||||
|
||||
m_delegate->resetHoverIndex();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::onFilterChangeFinished()
|
||||
{
|
||||
@@ -427,96 +438,6 @@ TreeView::jumpToCurrentTrack()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::updateHoverIndex( const QPoint& pos )
|
||||
{
|
||||
QModelIndex idx = indexAt( pos );
|
||||
|
||||
if ( idx != m_hoveredIndex )
|
||||
{
|
||||
m_hoveredIndex = idx;
|
||||
repaint();
|
||||
}
|
||||
|
||||
if ( !m_model || m_proxyModel->style() != PlayableProxyModel::Collection )
|
||||
return;
|
||||
|
||||
PlayableItem* item = proxyModel()->itemFromIndex( proxyModel()->mapToSource( idx ) );
|
||||
if ( idx.column() == 0 && !item->query().isNull() )
|
||||
{
|
||||
if ( pos.x() > header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) - 16 &&
|
||||
pos.x() < header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) )
|
||||
{
|
||||
setCursor( Qt::PointingHandCursor );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( cursor().shape() != Qt::ArrowCursor )
|
||||
setCursor( Qt::ArrowCursor );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::wheelEvent( QWheelEvent* event )
|
||||
{
|
||||
QTreeView::wheelEvent( event );
|
||||
|
||||
if ( m_hoveredIndex.isValid() )
|
||||
{
|
||||
m_hoveredIndex = QModelIndex();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::leaveEvent( QEvent* event )
|
||||
{
|
||||
QTreeView::leaveEvent( event );
|
||||
updateHoverIndex( QPoint( -1, -1 ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
QTreeView::mouseMoveEvent( event );
|
||||
updateHoverIndex( event->pos() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeView::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
QTreeView::mousePressEvent( event );
|
||||
|
||||
if ( !m_model || m_proxyModel->style() != PlayableProxyModel::Collection )
|
||||
return;
|
||||
|
||||
QModelIndex idx = indexAt( event->pos() );
|
||||
if ( event->pos().x() > header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) - 16 &&
|
||||
event->pos().x() < header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) )
|
||||
{
|
||||
PlayableItem* item = proxyModel()->itemFromIndex( proxyModel()->mapToSource( idx ) );
|
||||
if ( item->query().isNull() )
|
||||
return;
|
||||
|
||||
switch ( idx.column() )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ViewManager::instance()->show( item->query()->displayQuery() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
TreeView::guid() const
|
||||
{
|
||||
|
@@ -40,6 +40,7 @@ class ViewHeader;
|
||||
class AnimatedSpinner;
|
||||
class OverlayWidget;
|
||||
class TreeModel;
|
||||
class TreeItemDelegate;
|
||||
|
||||
class DLLEXPORT TreeView : public QTreeView
|
||||
{
|
||||
@@ -65,8 +66,6 @@ public:
|
||||
|
||||
virtual bool jumpToCurrentTrack();
|
||||
|
||||
QModelIndex hoveredIndex() const { return m_hoveredIndex; }
|
||||
|
||||
bool updatesContextView() const { return m_updateContextView; }
|
||||
void setUpdatesContextView( bool b ) { m_updateContextView = b; }
|
||||
|
||||
@@ -81,10 +80,7 @@ protected:
|
||||
virtual void resizeEvent( QResizeEvent* event );
|
||||
|
||||
virtual void keyPressEvent( QKeyEvent* event );
|
||||
void wheelEvent( QWheelEvent* event );
|
||||
void mouseMoveEvent( QMouseEvent* event );
|
||||
void mousePressEvent( QMouseEvent* event );
|
||||
void leaveEvent( QEvent* event );
|
||||
virtual void wheelEvent( QWheelEvent* event );
|
||||
|
||||
protected slots:
|
||||
virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous );
|
||||
@@ -99,17 +95,15 @@ private slots:
|
||||
void onMenuTriggered( int action );
|
||||
|
||||
private:
|
||||
void updateHoverIndex( const QPoint& pos );
|
||||
|
||||
ViewHeader* m_header;
|
||||
OverlayWidget* m_overlay;
|
||||
TreeModel* m_model;
|
||||
TreeProxyModel* m_proxyModel;
|
||||
TreeItemDelegate* m_delegate;
|
||||
AnimatedSpinner* m_loadingSpinner;
|
||||
|
||||
bool m_updateContextView;
|
||||
|
||||
QModelIndex m_hoveredIndex;
|
||||
QModelIndex m_contextMenuIndex;
|
||||
Tomahawk::ContextMenu* m_contextMenu;
|
||||
|
||||
|
@@ -30,7 +30,7 @@
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
QHash< QString, peerinfo_ptr > PeerInfo::s_peersByCacheKey = QHash< QString, peerinfo_ptr >();
|
||||
QHash< QString, peerinfo_wptr > PeerInfo::s_peersByCacheKey = QHash< QString, peerinfo_wptr >();
|
||||
QHash< SipPlugin*, peerinfo_ptr > PeerInfo::s_selfPeersBySipPlugin = QHash< SipPlugin*, peerinfo_ptr >();
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ PeerInfo::getSelf( SipPlugin* parent, PeerInfo::GetOptions options )
|
||||
|
||||
peerinfo_ptr selfPeer( new PeerInfo( parent, "local peerinfo don't use this id for anything" ) );
|
||||
selfPeer->setWeakRef( selfPeer.toWeakRef() );
|
||||
selfPeer->setContactId( "localpeer" );
|
||||
|
||||
// parent->setSelfPeer( selfPeer );
|
||||
s_selfPeersBySipPlugin.insert( parent, selfPeer );
|
||||
@@ -76,9 +77,9 @@ Tomahawk::peerinfo_ptr
|
||||
PeerInfo::get( SipPlugin* parent, const QString& id, GetOptions options )
|
||||
{
|
||||
const QString key = peerCacheKey( parent, id );
|
||||
if ( s_peersByCacheKey.contains( key ) )
|
||||
if ( s_peersByCacheKey.contains( key ) && !s_peersByCacheKey.value( key ).isNull() )
|
||||
{
|
||||
return s_peersByCacheKey.value( key );
|
||||
return s_peersByCacheKey.value( key ).toStrongRef();
|
||||
}
|
||||
|
||||
// if AutoCreate isn't enabled nothing to do here
|
||||
@@ -89,7 +90,7 @@ PeerInfo::get( SipPlugin* parent, const QString& id, GetOptions options )
|
||||
|
||||
peerinfo_ptr peerInfo( new PeerInfo( parent, id ) );
|
||||
peerInfo->setWeakRef( peerInfo.toWeakRef() );
|
||||
s_peersByCacheKey.insert( key, peerInfo );
|
||||
s_peersByCacheKey.insert( key, peerInfo.toWeakRef() );
|
||||
|
||||
return peerInfo;
|
||||
}
|
||||
@@ -98,7 +99,13 @@ PeerInfo::get( SipPlugin* parent, const QString& id, GetOptions options )
|
||||
QList< Tomahawk::peerinfo_ptr >
|
||||
PeerInfo::getAll()
|
||||
{
|
||||
return s_peersByCacheKey.values();
|
||||
QList< Tomahawk::peerinfo_ptr > strongRefs;
|
||||
foreach ( Tomahawk::peerinfo_wptr wptr, s_peersByCacheKey.values() )
|
||||
{
|
||||
if ( !wptr.isNull() )
|
||||
strongRefs << wptr.toStrongRef();
|
||||
}
|
||||
return strongRefs;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +124,7 @@ PeerInfo::PeerInfo( SipPlugin* parent, const QString& id )
|
||||
PeerInfo::~PeerInfo()
|
||||
{
|
||||
// tDebug() << Q_FUNC_INFO;
|
||||
s_peersByCacheKey.remove( s_peersByCacheKey.key( weakRef() ) );
|
||||
delete m_avatar;
|
||||
delete m_fancyAvatar;
|
||||
}
|
||||
@@ -256,7 +264,7 @@ PeerInfo::setSipInfo( const SipInfo& sipInfo )
|
||||
|
||||
m_sipInfo = sipInfo;
|
||||
|
||||
tLog() << "id: " << id() << " info changed" << sipInfo;
|
||||
tLog() << "id:" << id() << "info changed" << sipInfo;
|
||||
emit sipInfoChanged();
|
||||
}
|
||||
|
||||
@@ -297,13 +305,14 @@ PeerInfo::setAvatar( const QPixmap& avatar )
|
||||
|
||||
m_avatarHash = hash;
|
||||
m_avatarBuffer = ba;
|
||||
|
||||
|
||||
delete m_avatar;
|
||||
delete m_fancyAvatar;
|
||||
m_avatar = 0;
|
||||
m_fancyAvatar = 0;
|
||||
|
||||
TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, id(), ba );
|
||||
Q_ASSERT( !contactId().isEmpty() );
|
||||
TomahawkUtils::Cache::instance()->putData( "Sources", 7776000000 /* 90 days */, contactId(), ba );
|
||||
}
|
||||
|
||||
|
||||
@@ -312,19 +321,15 @@ PeerInfo::avatar( TomahawkUtils::ImageMode style, const QSize& size ) const
|
||||
{
|
||||
if ( !m_avatar )
|
||||
{
|
||||
if ( m_avatarBuffer.isEmpty() )
|
||||
m_avatarBuffer = TomahawkUtils::Cache::instance()->getData( "Sources", id() ).toByteArray();
|
||||
tDebug() << "Avatar for:" << id();
|
||||
Q_ASSERT( !contactId().isEmpty() );
|
||||
if ( m_avatarBuffer.isEmpty() && !contactId().isEmpty() )
|
||||
m_avatarBuffer = TomahawkUtils::Cache::instance()->getData( "Sources", contactId() ).toByteArray();
|
||||
|
||||
m_avatar = new QPixmap();
|
||||
if ( !m_avatarBuffer.isEmpty() )
|
||||
m_avatar->loadFromData( m_avatarBuffer );
|
||||
|
||||
if ( m_avatar->isNull() )
|
||||
{
|
||||
delete m_avatar;
|
||||
m_avatar = 0;
|
||||
}
|
||||
|
||||
m_avatarBuffer.clear();
|
||||
}
|
||||
|
||||
@@ -336,7 +341,7 @@ PeerInfo::avatar( TomahawkUtils::ImageMode style, const QSize& size ) const
|
||||
{
|
||||
pixmap = *m_fancyAvatar;
|
||||
}
|
||||
else if ( m_avatar )
|
||||
else if ( m_avatar && !m_avatar->isNull() )
|
||||
{
|
||||
pixmap = *m_avatar;
|
||||
}
|
||||
|
@@ -119,7 +119,7 @@ private:
|
||||
PeerInfo( SipPlugin* parent, const QString& id );
|
||||
void announce();
|
||||
|
||||
static QHash< QString, peerinfo_ptr > s_peersByCacheKey;
|
||||
static QHash< QString, peerinfo_wptr > s_peersByCacheKey;
|
||||
static QHash< SipPlugin*, peerinfo_ptr > s_selfPeersBySipPlugin;
|
||||
|
||||
QWeakPointer< Tomahawk::PeerInfo > m_ownRef;
|
||||
|
@@ -35,12 +35,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
SipInfoPrivate( const SipInfoPrivate& other ) : QSharedData( other ),
|
||||
visible(other.visible),
|
||||
host(other.host),
|
||||
port(other.port),
|
||||
nodeId(other.nodeId),
|
||||
key(other.key)
|
||||
SipInfoPrivate( const SipInfoPrivate& other )
|
||||
: QSharedData( other )
|
||||
, visible( other.visible )
|
||||
, host( other.host )
|
||||
, port( other.port )
|
||||
, nodeId( other.nodeId )
|
||||
, key( other.key )
|
||||
{
|
||||
}
|
||||
~SipInfoPrivate() { }
|
||||
@@ -93,10 +94,10 @@ SipInfo::clear()
|
||||
bool
|
||||
SipInfo::isValid() const
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << d->visible << d->host.hostName() << d->port << d->nodeId << d->key;
|
||||
if( !d->visible.isNull() )
|
||||
// tDebug() << Q_FUNC_INFO << d->visible << d->host << d->port << d->nodeId << d->key;
|
||||
if ( !d->visible.isNull() )
|
||||
{
|
||||
if(
|
||||
if (
|
||||
// visible and all data available
|
||||
( d->visible.toBool() && !d->host.isEmpty() && ( d->port > 0 ) && !d->nodeId.isNull() && !d->key.isNull() )
|
||||
// invisible and no data available
|
||||
@@ -112,7 +113,7 @@ SipInfo::isValid() const
|
||||
void
|
||||
SipInfo::setVisible( bool visible )
|
||||
{
|
||||
d->visible.setValue(visible);
|
||||
d->visible.setValue( visible );
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +196,7 @@ SipInfo::toJson() const
|
||||
// build variant map
|
||||
QVariantMap m;
|
||||
m["visible"] = isVisible();
|
||||
if( isVisible() )
|
||||
if ( isVisible() )
|
||||
{
|
||||
m["ip"] = host();
|
||||
m["port"] = port();
|
||||
@@ -227,7 +228,7 @@ SipInfo::fromJson( QString json )
|
||||
QVariantMap m = v.toMap();
|
||||
|
||||
info.setVisible( m["visible"].toBool() );
|
||||
if( m["visible"].toBool() )
|
||||
if ( m["visible"].toBool() )
|
||||
{
|
||||
info.setHost( m["host"].toString() );
|
||||
info.setPort( m["port"].toInt() );
|
||||
@@ -242,7 +243,7 @@ SipInfo::fromJson( QString json )
|
||||
QDebug
|
||||
operator<< ( QDebug dbg, const SipInfo& info )
|
||||
{
|
||||
if( !info.isValid() )
|
||||
if ( !info.isValid() )
|
||||
dbg.nospace() << "info is invalid";
|
||||
else
|
||||
dbg.nospace() << info.toJson();
|
||||
@@ -250,7 +251,9 @@ operator<< ( QDebug dbg, const SipInfo& info )
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
bool operator==( const SipInfo& one, const SipInfo& two )
|
||||
|
||||
bool
|
||||
operator==( const SipInfo& one, const SipInfo& two )
|
||||
{
|
||||
// check valid/invalid combinations first, so we don't try to access any invalid sipInfos (->assert)
|
||||
if ( ( one.isValid() && !two.isValid() ) || ( !one.isValid() && two.isValid() ) )
|
||||
@@ -272,6 +275,7 @@ bool operator==( const SipInfo& one, const SipInfo& two )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const QString
|
||||
SipInfo::debugString() const
|
||||
{
|
||||
@@ -281,6 +285,5 @@ SipInfo::debugString() const
|
||||
.arg( d->port )
|
||||
.arg( d->nodeId )
|
||||
.arg( d->key );
|
||||
|
||||
}
|
||||
|
||||
|
@@ -73,6 +73,9 @@ ChartDataLoader::go()
|
||||
|
||||
foreach ( const Tomahawk::InfoSystem::InfoStringHash& album, m_data )
|
||||
{
|
||||
if ( album["artist"].isEmpty() )
|
||||
continue;
|
||||
|
||||
artist_ptr artistPtr = Artist::get( album[ "artist" ], false );
|
||||
album_ptr albumPtr = Album::get( artistPtr, album[ "album" ], false );
|
||||
album_ptrs << albumPtr;
|
||||
|
@@ -34,7 +34,9 @@
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "TomahawkSettingsGui.h"
|
||||
#include "breakpad/BreakPad.h"
|
||||
#ifdef WITH_BREAKPAD
|
||||
#include "breakpad/BreakPad.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
@@ -229,9 +229,13 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem&
|
||||
|
||||
QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - ( figWidth ? 28 : 0 ), 0 );
|
||||
QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
|
||||
painter->drawText( textRect, text );
|
||||
{
|
||||
QTextOption to;
|
||||
to.setWrapMode( QTextOption::NoWrap );
|
||||
painter->drawText( textRect, text, to );
|
||||
}
|
||||
|
||||
QColor descColor = QColor( "#8d8d8d" );
|
||||
QColor descColor = option.palette.color( QPalette::Text ).lighter( 180 );
|
||||
if ( type == SourcesModel::ScriptCollection && //you cannot select a non-script collection anyway
|
||||
option.state.testFlag( QStyle::State_Selected ) )
|
||||
{
|
||||
@@ -300,7 +304,7 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem&
|
||||
m_lockRects.remove( index );
|
||||
|
||||
if ( isPlaying )
|
||||
descColor = Qt::black;
|
||||
descColor = option.palette.color( QPalette::Text );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,10 +316,12 @@ SourceDelegate::paintCollection( QPainter* painter, const QStyleOptionViewItem&
|
||||
}
|
||||
textRect.adjust( 0, 0, 0, 2 );
|
||||
text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() - 8 );
|
||||
QTextOption to( Qt::AlignVCenter );
|
||||
to.setWrapMode( QTextOption::NoWrap );
|
||||
painter->setPen( descColor );
|
||||
painter->drawText( textRect, text, to );
|
||||
{
|
||||
QTextOption to( Qt::AlignVCenter );
|
||||
to.setWrapMode( QTextOption::NoWrap );
|
||||
painter->setPen( descColor );
|
||||
painter->drawText( textRect, text, to );
|
||||
}
|
||||
|
||||
bool shouldPaintTrackCount = false;
|
||||
if ( type == SourcesModel::Collection )
|
||||
|
@@ -271,7 +271,7 @@ SourceTreeView::setupMenus()
|
||||
connect( deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
|
||||
connect( copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
|
||||
connect( addToLocalAction, SIGNAL( triggered() ), SLOT( addToLocal() ) );
|
||||
connect( latchOnAction, SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ), Qt::QueuedConnection );
|
||||
connect( latchOnAction, SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ) );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -34,7 +34,6 @@ ScriptCollectionItem::~ScriptCollectionItem()
|
||||
{
|
||||
model()->removeSourceItemLink( this );
|
||||
ViewManager::instance()->destroyPage( m_page );
|
||||
dynamic_cast< QObject* >( m_page )->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "utils/ImageRegistry.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "TomahawkApp.h"
|
||||
|
||||
/// SourceItem
|
||||
|
||||
@@ -156,23 +157,26 @@ SourceItem::tooltip() const
|
||||
|
||||
QString t;
|
||||
|
||||
|
||||
// This is kind of debug output for now.
|
||||
t.append( "<PRE>" );
|
||||
|
||||
QString narf("%1: %2\n");
|
||||
t.append( narf.arg( "id" ).arg( m_source->id() ) );
|
||||
t.append( narf.arg( "username" ).arg( m_source->nodeId() ) );
|
||||
t.append( narf.arg( "friendlyname" ).arg( m_source->friendlyName() ) );
|
||||
t.append( narf.arg( "dbfriendlyname" ).arg( m_source->dbFriendlyName() ) );
|
||||
|
||||
t.append("\n");
|
||||
foreach( Tomahawk::peerinfo_ptr p, m_source->peerInfos() )
|
||||
bool showDebugInfo = APP->arguments().contains( "--verbose" );
|
||||
if ( showDebugInfo )
|
||||
{
|
||||
QString line( p->sipPlugin()->serviceName() + p->sipPlugin()->friendlyName() + ": " + p->id() + " " + p->friendlyName() );
|
||||
t.append( line + "\n\n" );
|
||||
// This is kind of debug output for now.
|
||||
t.append( "<PRE>" );
|
||||
|
||||
QString narf("%1: %2\n");
|
||||
t.append( narf.arg( "id" ).arg( m_source->id() ) );
|
||||
t.append( narf.arg( "username" ).arg( m_source->nodeId() ) );
|
||||
t.append( narf.arg( "friendlyname" ).arg( m_source->friendlyName() ) );
|
||||
t.append( narf.arg( "dbfriendlyname" ).arg( m_source->dbFriendlyName() ) );
|
||||
|
||||
t.append("\n");
|
||||
foreach( Tomahawk::peerinfo_ptr p, m_source->peerInfos() )
|
||||
{
|
||||
QString line( p->sipPlugin()->serviceName() + p->sipPlugin()->friendlyName() + ": " + p->id() + " " + p->friendlyName() );
|
||||
t.append( line + "\n\n" );
|
||||
}
|
||||
t.append( "</PRE>" );
|
||||
}
|
||||
t.append( "</PRE>" );
|
||||
|
||||
if ( !m_source->currentTrack().isNull() )
|
||||
t.append( m_source->textStatus() );
|
||||
|
@@ -126,8 +126,6 @@ TemporaryPageItem::IDValue() const
|
||||
void
|
||||
TemporaryPageItem::removeFromList()
|
||||
{
|
||||
ViewManager::instance()->destroyPage( m_page );
|
||||
|
||||
model()->removeSourceItemLink( this );
|
||||
|
||||
int idx = parent()->children().indexOf( this );
|
||||
@@ -137,7 +135,7 @@ TemporaryPageItem::removeFromList()
|
||||
|
||||
emit removed();
|
||||
|
||||
delete m_page;
|
||||
ViewManager::instance()->destroyPage( m_page );
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
@@ -201,16 +201,19 @@ Api_v1::sid( QxtWebRequestEvent* event, QString unused )
|
||||
void
|
||||
Api_v1::processSid( QxtWebRequestEvent* event, Tomahawk::result_ptr& rp, QSharedPointer< QIODevice >& iodev )
|
||||
{
|
||||
if ( !iodev || iodev.isNull() )
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
|
||||
if ( !iodev || !rp )
|
||||
{
|
||||
return send404( event ); // 503?
|
||||
}
|
||||
m_ioDevice = iodev;
|
||||
|
||||
QxtWebPageEvent* e = new QxtWebPageEvent( event->sessionID, event->requestID, iodev.data() );
|
||||
e->streaming = iodev->isSequential();
|
||||
e->contentType = rp->mimetype().toLatin1();
|
||||
if ( rp->size() > 0 )
|
||||
e->headers.insert( "Content-Length", QString::number( rp->size() ) );
|
||||
|
||||
postEvent( e );
|
||||
}
|
||||
|
||||
|
@@ -78,7 +78,9 @@ public slots:
|
||||
|
||||
private:
|
||||
void processSid( QxtWebRequestEvent* event, Tomahawk::result_ptr&, QSharedPointer< QIODevice >& );
|
||||
|
||||
QxtWebRequestEvent* m_storedEvent;
|
||||
QSharedPointer< QIODevice > m_ioDevice;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
31
thirdparty/qxt/qxtweb-standalone/CMakeLists.txt
vendored
@@ -7,16 +7,18 @@ ENDIF( ${CMAKE_VERSION} VERSION_GREATER 2.8.3 )
|
||||
|
||||
setup_qt()
|
||||
|
||||
SET(qxtweb "qxtweb")
|
||||
SET( qxtcore "core" )
|
||||
SET( qxtnet "network" )
|
||||
SET( qxtweb "web" )
|
||||
|
||||
ADD_DEFINITIONS(-Wall -O2 -DNDEBUG)
|
||||
IF(NOT WIN32)
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ADD_DEFINITIONS( -Wall -O2 -DNDEBUG )
|
||||
IF( NOT WIN32 )
|
||||
ADD_DEFINITIONS( -fPIC )
|
||||
ENDIF()
|
||||
ADD_DEFINITIONS( -DBUILD_QXT_CORE -DBUILD_QXT_WEB )
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES( ${qxtweb} )
|
||||
INCLUDE_DIRECTORIES( ${qxtweb} ${qxtcore} ${qxtnet} )
|
||||
|
||||
macro(create_qxtweb_fancy_header simpleHeader fancyHeader)
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/QxtWeb/${fancyHeader} "#include \"${simpleHeader}\"" )
|
||||
@@ -41,24 +43,23 @@ SET( sources
|
||||
${qxtweb}/qxtwebcontent.cpp
|
||||
${qxtweb}/qxtwebevent.cpp
|
||||
${qxtweb}/qxtwebservicedirectory.cpp
|
||||
${qxtweb}/qxtwebslotservice.cpp
|
||||
${qxtweb}/qxtwebcgiservice.cpp
|
||||
${qxtweb}/qhttpheader.cpp
|
||||
${qxtweb}/qxtwebslotservice.cpp
|
||||
|
||||
# Ripped bits of QxtCore:
|
||||
${qxtweb}/qxtmetaobject.cpp
|
||||
${qxtweb}/qxtnull.cpp
|
||||
${qxtweb}/qxtfifo.cpp
|
||||
${qxtcore}/qxtmetaobject.cpp
|
||||
${qxtcore}/qxtnull.cpp
|
||||
${qxtcore}/qxtfifo.cpp
|
||||
|
||||
# QxtNetwork
|
||||
${qxtweb}/qxtsslserver.cpp
|
||||
${qxtnet}/qxtsslserver.cpp
|
||||
|
||||
# automoc hack
|
||||
${qxtweb}/qxtboundfunction.h
|
||||
${qxtcore}/qxtboundfunction.h
|
||||
)
|
||||
|
||||
|
||||
ADD_LIBRARY(qxtweb-standalone STATIC
|
||||
ADD_LIBRARY( qxtweb-standalone STATIC
|
||||
${mocstuff}
|
||||
${headers}
|
||||
${sources}
|
||||
@@ -69,6 +70,6 @@ target_link_libraries( qxtweb-standalone
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
|
||||
qt5_use_modules(qxtweb-standalone Network)
|
||||
qt5_use_modules( qxtweb-standalone Network )
|
||||
|
||||
set_target_properties(qxtweb-standalone PROPERTIES AUTOMOC TRUE)
|
||||
set_target_properties( qxtweb-standalone PROPERTIES AUTOMOC TRUE )
|
||||
|
@@ -137,17 +137,14 @@ QxtFifo::QxtFifo(const QByteArray &prime, QObject *parent) : QIODevice(parent)
|
||||
QXT_INIT_PRIVATE(QxtFifo);
|
||||
setOpenMode(QIODevice::ReadWrite);
|
||||
// Since we're being constructed, access to the internals is safe
|
||||
|
||||
QxtFifoNode *head;
|
||||
int available;
|
||||
QxtFifoNode* node;
|
||||
#if QT_VERSION >= 0x50000
|
||||
head = qxt_d().head.load();
|
||||
available = qxt_d().available.load();
|
||||
node = qxt_d().head.load();
|
||||
#else
|
||||
head = qxt_d().head;
|
||||
available = qxt_d().available;
|
||||
node = qxt_d().head;
|
||||
#endif
|
||||
|
||||
node->content = prime;
|
||||
qxt_d().available.QXT_ADD( prime.size() );
|
||||
}
|
||||
|
||||
/*!
|
@@ -51,6 +51,7 @@
|
||||
|
||||
#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE
|
||||
|
||||
// Define QXT_STATIC here so that the linker of projects that include the static library use the correct call method.
|
||||
#define QXT_STATIC
|
||||
|
||||
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
|
@@ -1,27 +1,33 @@
|
||||
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||
**
|
||||
** This file is part of the QxtCore module of the Qxt library.
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or modify it
|
||||
** under the terms of the Common Public License, version 1.0, as published
|
||||
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||
** version 2.1, as published by the Free Software Foundation.
|
||||
**
|
||||
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||
**
|
||||
** You should have received a copy of the CPL and the LGPL along with this
|
||||
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||
** included with the source distribution for more information.
|
||||
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
**
|
||||
****************************************************************************/
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of the LibQxt project nor the
|
||||
** names of its contributors may be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QXTMETATYPE_H
|
||||
#define QXTMETATYPE_H
|
||||
@@ -32,13 +38,19 @@
|
||||
#include <QtDebug>
|
||||
#include <qxtglobal.h>
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
|
||||
#define qxtcreate create
|
||||
#else
|
||||
#define qxtcreate construct
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class /*QXT_CORE_EXPORT*/ QxtMetaType
|
||||
{
|
||||
public:
|
||||
static inline T* construct(const T* copy = 0)
|
||||
{
|
||||
return QMetaType::construct(qMetaTypeId<T>(), reinterpret_cast<const void*>(copy));
|
||||
return QMetaType::qxtcreate(qMetaTypeId<T>(), reinterpret_cast<const void*>(copy));
|
||||
}
|
||||
|
||||
static inline void destroy(T* data)
|
||||
@@ -111,11 +123,7 @@ public:
|
||||
|
||||
inline void* qxtConstructByName(const char* typeName, const void* copy = 0)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
|
||||
return QMetaType::create(QMetaType::type(typeName), copy);
|
||||
#else
|
||||
return QMetaType::construct(QMetaType::type(typeName), copy);
|
||||
#endif
|
||||
return QMetaType::qxtcreate(QMetaType::type(typeName), copy);
|
||||
}
|
||||
|
||||
inline void qxtDestroyByName(const char* typeName, void* data)
|
@@ -39,7 +39,7 @@
|
||||
#include <QSslSocket>
|
||||
|
||||
class QxtSslServerPrivate;
|
||||
class QxtSslServer : public QTcpServer
|
||||
class QXT_NETWORK_EXPORT QxtSslServer : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtabstracthttpconnector.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtabstractwebservice.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtabstractwebsessionmanager.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxthtmltemplate.h"
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "qxtabstracthttpconnector.h"
|
@@ -1,2 +0,0 @@
|
||||
#include "qxthttpsessionmanager.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtmail.h"
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "qxtabstracthttpconnector.h"
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtsendmail.h"
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "qxtweb.h"
|
@@ -1 +0,0 @@
|
||||
#include "qxtwebcgiservice.h"
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebcontent.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebservicedirectory.h"
|
||||
|
@@ -1,2 +0,0 @@
|
||||
#include "qxtwebslotservice.h"
|
||||
|
@@ -1 +0,0 @@
|
||||
#include "qxtwebevent.h"
|
@@ -1,251 +0,0 @@
|
||||
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of the LibQxt project nor the
|
||||
** names of its contributors may be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qxtglobal.h"
|
||||
|
||||
/*!
|
||||
\headerfile <QxtGlobal>
|
||||
\title Global Qxt Declarations
|
||||
\inmodule QxtCore
|
||||
|
||||
\brief The <QxtGlobal> header provides basic declarations and
|
||||
is included by all other Qxt headers.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\macro QXT_VERSION
|
||||
\relates <QxtGlobal>
|
||||
|
||||
This macro expands a numeric value of the form 0xMMNNPP (MM =
|
||||
major, NN = minor, PP = patch) that specifies Qxt's version
|
||||
number. For example, if you compile your application against Qxt
|
||||
0.4.0, the QXT_VERSION macro will expand to 0x000400.
|
||||
|
||||
You can use QXT_VERSION to use the latest Qt features where
|
||||
available. For example:
|
||||
\code
|
||||
#if QXT_VERSION >= 0x000400
|
||||
qxtTabWidget->setTabMovementMode(QxtTabWidget::InPlaceMovement);
|
||||
#endif
|
||||
\endcode
|
||||
|
||||
\sa QXT_VERSION_STR, qxtVersion()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\macro QXT_VERSION_STR
|
||||
\relates <QxtGlobal>
|
||||
|
||||
This macro expands to a string that specifies Qxt's version number
|
||||
(for example, "0.4.0"). This is the version against which the
|
||||
application is compiled.
|
||||
|
||||
\sa qxtVersion(), QXT_VERSION
|
||||
*/
|
||||
|
||||
/*!
|
||||
\relates <QxtGlobal>
|
||||
|
||||
Returns the version number of Qxt at run-time as a string (for
|
||||
example, "0.4.0"). This may be a different version than the
|
||||
version the application was compiled against.
|
||||
|
||||
\sa QXT_VERSION_STR
|
||||
*/
|
||||
const char * qxtVersion()
|
||||
{
|
||||
return QXT_VERSION_STR;
|
||||
}
|
||||
|
||||
/*!
|
||||
\headerfile <QxtPimpl>
|
||||
\title The Qxt private implementation
|
||||
\inmodule QxtCore
|
||||
|
||||
\brief The <QxtPimpl> header provides tools for hiding
|
||||
details of a class.
|
||||
|
||||
Application code generally doesn't have to be concerned about hiding its
|
||||
implementation details, but when writing library code it is important to
|
||||
maintain a constant interface, both source and binary. Maintaining a constant
|
||||
source interface is easy enough, but keeping the binary interface constant
|
||||
means moving implementation details into a private class. The PIMPL, or
|
||||
d-pointer, idiom is a common method of implementing this separation. QxtPimpl
|
||||
offers a convenient way to connect the public and private sides of your class.
|
||||
|
||||
\section1 Getting Started
|
||||
Before you declare the public class, you need to make a forward declaration
|
||||
of the private class. The private class must have the same name as the public
|
||||
class, followed by the word Private. For example, a class named MyTest would
|
||||
declare the private class with:
|
||||
\code
|
||||
class MyTestPrivate;
|
||||
\endcode
|
||||
|
||||
\section1 The Public Class
|
||||
Generally, you shouldn't keep any data members in the public class without a
|
||||
good reason. Functions that are part of the public interface should be declared
|
||||
in the public class, and functions that need to be available to subclasses (for
|
||||
calling or overriding) should be in the protected section of the public class.
|
||||
To connect the private class to the public class, include the
|
||||
QXT_DECLARE_PRIVATE macro in the private section of the public class. In the
|
||||
example above, the private class is connected as follows:
|
||||
\code
|
||||
private:
|
||||
QXT_DECLARE_PRIVATE(MyTest)
|
||||
\endcode
|
||||
|
||||
Additionally, you must include the QXT_INIT_PRIVATE macro in the public class's
|
||||
constructor. Continuing with the MyTest example, your constructor might look
|
||||
like this:
|
||||
\code
|
||||
MyTest::MyTest() {
|
||||
// initialization
|
||||
QXT_INIT_PRIVATE(MyTest);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\section1 The Private Class
|
||||
As mentioned above, data members should usually be kept in the private class.
|
||||
This allows the memory layout of the private class to change without breaking
|
||||
binary compatibility for the public class. Functions that exist only as
|
||||
implementation details, or functions that need access to private data members,
|
||||
should be implemented here.
|
||||
|
||||
To define the private class, inherit from the template QxtPrivate class, and
|
||||
include the QXT_DECLARE_PUBLIC macro in its public section. The template
|
||||
parameter should be the name of the public class. For example:
|
||||
\code
|
||||
class MyTestPrivate : public QxtPrivate<MyTest> {
|
||||
public:
|
||||
MyTestPrivate();
|
||||
QXT_DECLARE_PUBLIC(MyTest)
|
||||
};
|
||||
\endcode
|
||||
|
||||
\section1 Accessing Private Members
|
||||
Use the qxt_d() function (actually a function-like object) from functions in
|
||||
the public class to access the private class. Similarly, functions in the
|
||||
private class can invoke functions in the public class by using the qxt_p()
|
||||
function (this one's actually a function).
|
||||
|
||||
For example, assume that MyTest has methods named getFoobar and doBaz(),
|
||||
and MyTestPrivate has a member named foobar and a method named doQuux().
|
||||
The code might resemble this example:
|
||||
\code
|
||||
int MyTest::getFoobar() {
|
||||
return qxt_d().foobar;
|
||||
}
|
||||
|
||||
void MyTestPrivate::doQuux() {
|
||||
qxt_p().doBaz(foobar);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \macro QXT_DECLARE_PRIVATE(PUB)
|
||||
* \relates <QxtPimpl>
|
||||
* Declares that a public class has a related private class.
|
||||
*
|
||||
* This shuold be put in the private section of the public class. The
|
||||
* parameter \a PUB must be the name of the public class.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \macro QXT_DECLARE_PUBLIC(PUB)
|
||||
* \relates <QxtPimpl>
|
||||
* Declares that a private class has a related public class named \a PUB.
|
||||
*
|
||||
* This may be put anywhere in the declaration of the private class. The parameter is the name of the public class.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \macro QXT_INIT_PRIVATE(PUB)
|
||||
* \relates <QxtPimpl>
|
||||
* Initializes resources owned by the private class.
|
||||
*
|
||||
* This should be called from the public class's constructor,
|
||||
* before qxt_d() is used for the first time. The parameter \a PUB must be
|
||||
* the name of the public class.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \macro QXT_D(PUB)
|
||||
* \relates <QxtPimpl>
|
||||
* Returns a reference in the current scope named "d" to the private class
|
||||
* associated with the public class \a PUB.
|
||||
*
|
||||
* This function is only available in a class using QXT_DECLARE_PRIVATE().
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \macro QXT_P(PUB)
|
||||
* \relates <QxtPimpl>
|
||||
* Creates a reference in the current scope named "q" to the public class
|
||||
* named \a PUB.
|
||||
*
|
||||
* This macro only works in a class using QXT_DECLARE_PUBLIC().
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn QxtPrivate<PUB>& PUB::qxt_d()
|
||||
* \relates <QxtPimpl>
|
||||
* Returns a reference to the private class.
|
||||
*
|
||||
* This function is only available in a class using \a QXT_DECLARE_PRIVATE.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn const QxtPrivate<PUB>& PUB::qxt_d() const
|
||||
* \relates <QxtPimpl>
|
||||
* Returns a const reference to the private class.
|
||||
*
|
||||
* This function is only available in a class using \a QXT_DECLARE_PRIVATE.
|
||||
* This overload will be automatically used in const functions.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn PUB& QxtPrivate::qxt_p()
|
||||
* \relates <QxtPimpl>
|
||||
* Returns a reference to the public class.
|
||||
*
|
||||
* This function is only available in a class using QXT_DECLARE_PUBLIC().
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \fn const PUB& QxtPrivate::qxt_p() const
|
||||
* \relates <QxtPimpl>
|
||||
* Returns a const reference to the public class.
|
||||
*
|
||||
* This function is only available in a class using QXT_DECLARE_PUBLIC().
|
||||
* This overload will be automatically used in const functions.
|
||||
*/
|
46
thirdparty/qxt/qxtweb-standalone/qxtweb/qxtweb.h
vendored
@@ -1,46 +0,0 @@
|
||||
#ifndef QXTWEB_H_INCLUDED
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of the LibQxt project nor the
|
||||
** names of its contributors may be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#define QXTWEB_H_INCLUDED
|
||||
|
||||
#include "qxtabstracthttpconnector.h"
|
||||
#include "qxtabstractwebservice.h"
|
||||
#include "qxtabstractwebsessionmanager.h"
|
||||
#include "qxthtmltemplate.h"
|
||||
#include "qxthttpsessionmanager.h"
|
||||
#include "qxtwebcgiservice.h"
|
||||
#include "qxtwebcontent.h"
|
||||
#include "qxtwebevent.h"
|
||||
#include "qxtwebjsonrpcservice.h"
|
||||
#include "qxtwebservicedirectory.h"
|
||||
#include "qxtwebslotservice.h"
|
||||
|
||||
#endif // QXTWEB_H_INCLUDED
|
@@ -1,445 +0,0 @@
|
||||
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of the LibQxt project nor the
|
||||
** names of its contributors may be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
/*!
|
||||
\class QxtWebCgiService
|
||||
|
||||
\inmodule QxtWeb
|
||||
|
||||
\brief The QxtWebCgiService class provides a CGI/1.1 gateway for QxtWeb
|
||||
|
||||
TODO: write docs
|
||||
TODO: implement timeout
|
||||
*/
|
||||
|
||||
#include "qxtwebcgiservice.h"
|
||||
#include "qxtwebcgiservice_p.h"
|
||||
#include "qxtwebevent.h"
|
||||
#include "qxtwebcontent.h"
|
||||
#include <QMap>
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#include <QtDebug>
|
||||
|
||||
QxtCgiRequestInfo::QxtCgiRequestInfo() : sessionID(0), requestID(0), eventSent(false), terminateSent(false) {}
|
||||
QxtCgiRequestInfo::QxtCgiRequestInfo(QxtWebRequestEvent* req) : sessionID(req->sessionID), requestID(req->requestID), eventSent(false), terminateSent(false) {}
|
||||
|
||||
/*!
|
||||
* Constructs a QxtWebCgiService object with the specified session \a manager and \a parent.
|
||||
* This service will invoke the specified \a binary to handle incoming requests.
|
||||
*
|
||||
* Often, the session manager will also be the parent, but this is not a requirement.
|
||||
*/
|
||||
QxtWebCgiService::QxtWebCgiService(const QString& binary, QxtAbstractWebSessionManager* manager, QObject* parent) : QxtAbstractWebService(manager, parent)
|
||||
{
|
||||
QXT_INIT_PRIVATE(QxtWebCgiService);
|
||||
qxt_d().binary = binary;
|
||||
QObject::connect(&qxt_d().timeoutMapper, SIGNAL(mapped(QObject*)), &qxt_d(), SLOT(terminateProcess(QObject*)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns the path to the CGI script that will be executed to handle requests.
|
||||
*
|
||||
* \sa setBinary()
|
||||
*/
|
||||
QString QxtWebCgiService::binary() const
|
||||
{
|
||||
return qxt_d().binary;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sets the path to the CGI script \a bin that will be executed to handle requests.
|
||||
*
|
||||
* \sa binary()
|
||||
*/
|
||||
void QxtWebCgiService::setBinary(const QString& bin)
|
||||
{
|
||||
if (!QFile::exists(bin) || !(QFile::permissions(bin) & (QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther)))
|
||||
{
|
||||
qWarning() << "QxtWebCgiService::setBinary: " + bin + " does not appear to be executable.";
|
||||
}
|
||||
qxt_d().binary = bin;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns the maximum time a CGI script may execute, in milliseconds.
|
||||
*
|
||||
* The default value is 0, which indicates that CGI scripts will not be terminated
|
||||
* due to long running times.
|
||||
*
|
||||
* \sa setTimeout()
|
||||
*/
|
||||
int QxtWebCgiService::timeout() const
|
||||
{
|
||||
return qxt_d().timeout;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sets the maximum \a time a CGI script may execute, in milliseconds.
|
||||
*
|
||||
* The timer is started when the script is launched. After the timeout elapses once,
|
||||
* the script will be asked to stop, as QProcess::terminate(). (That is, the script
|
||||
* will receive WM_CLOSE on Windows or SIGTERM on UNIX.) If the process has still
|
||||
* failed to terminate after another timeout, it will be forcibly terminated, as
|
||||
* QProcess::kill(). (That is, the script will receive TerminateProcess on Windows
|
||||
* or SIGKILL on UNIX.)
|
||||
*
|
||||
* Set the timeout to 0 to disable this behavior; scripts will not be terminated
|
||||
* due to excessive run time. This is the default behavior.
|
||||
*
|
||||
* CAUTION: Keep in mind that the timeout applies to the real running time of the
|
||||
* script, not processor time used. A script that initiates a lengthy download
|
||||
* may be interrupted while transferring data to the web browser. To avoid this
|
||||
* behavior, see the timeoutOverride property to allow the script to request
|
||||
* an extended timeout, or use a different QxtAbstractWebService object for
|
||||
* serving streaming content or large files.
|
||||
*
|
||||
*
|
||||
* \sa timeout(), timeoutOverride(), setTimeoutOverride(), QProcess::terminate(), QProcess::kill()
|
||||
*/
|
||||
void QxtWebCgiService::setTimeout(int time)
|
||||
{
|
||||
qxt_d().timeout = time;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns whether or not to allow scripts to override the timeout.
|
||||
*
|
||||
* \sa setTimeoutOverride(), setTimeout()
|
||||
*/
|
||||
bool QxtWebCgiService::timeoutOverride() const
|
||||
{
|
||||
return qxt_d().timeoutOverride;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sets whether or not to allow scripts to override the timeout.
|
||||
* Scripts are allowed to override if \a enable is \c true.
|
||||
*
|
||||
* As an extension to the CGI/1.1 gateway specification, a CGI script may
|
||||
* output a "X-QxtWeb-Timeout" header to change the termination timeout
|
||||
* on a per-script basis. Only enable this option if you trust the scripts
|
||||
* being executed.
|
||||
*
|
||||
* \sa timeoutOverride(), setTimeout()
|
||||
*/
|
||||
void QxtWebCgiService::setTimeoutOverride(bool enable)
|
||||
{
|
||||
qxt_d().timeoutOverride = enable;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \reimp
|
||||
*/
|
||||
void QxtWebCgiService::pageRequestedEvent(QxtWebRequestEvent* event)
|
||||
{
|
||||
// Create the process object and initialize connections
|
||||
QProcess* process = new QProcess(this);
|
||||
qxt_d().requests[process] = QxtCgiRequestInfo(event);
|
||||
qxt_d().processes[event->content] = process;
|
||||
QxtCgiRequestInfo& requestInfo = qxt_d().requests[process];
|
||||
QObject::connect(process, SIGNAL(readyRead()), &qxt_d(), SLOT(processReadyRead()));
|
||||
QObject::connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), &qxt_d(), SLOT(processFinished()));
|
||||
QObject::connect(process, SIGNAL(error(QProcess::ProcessError)), &qxt_d(), SLOT(processFinished()));
|
||||
requestInfo.timeout = new QTimer(process);
|
||||
qxt_d().timeoutMapper.setMapping(requestInfo.timeout, process);
|
||||
QObject::connect(requestInfo.timeout, SIGNAL(timeout()), &qxt_d().timeoutMapper, SLOT(map()));
|
||||
|
||||
// Initialize the system environment
|
||||
QStringList s_env = process->systemEnvironment();
|
||||
QMap<QString, QString> env;
|
||||
foreach(const QString& entry, s_env)
|
||||
{
|
||||
int pos = entry.indexOf('=');
|
||||
env[entry.left(pos)] = entry.mid(pos + 1);
|
||||
}
|
||||
|
||||
// Populate CGI/1.1 environment variables
|
||||
env["SERVER_SOFTWARE"] = QString("QxtWeb/" QXT_VERSION_STR);
|
||||
env["SERVER_NAME"] = event->url.host();
|
||||
env["GATEWAY_INTERFACE"] = "CGI/1.1";
|
||||
if (event->headers.contains("X-Request-Protocol"))
|
||||
env["SERVER_PROTOCOL"] = event->headers.value("X-Request-Protocol");
|
||||
else
|
||||
env.remove("SERVER_PROTOCOL");
|
||||
if (event->url.port() != -1)
|
||||
env["SERVER_PORT"] = QString::number(event->url.port());
|
||||
else
|
||||
env.remove("SERVER_PORT");
|
||||
env["REQUEST_METHOD"] = event->method;
|
||||
env["PATH_INFO"] = event->url.path();
|
||||
env["PATH_TRANSLATED"] = event->url.path(); // CGI/1.1 says we should resolve this, but we have no logical interpretation
|
||||
env["SCRIPT_NAME"] = event->originalUrl.path().remove(QRegExp(QRegExp::escape(event->url.path()) + '$'));
|
||||
env["SCRIPT_FILENAME"] = qxt_d().binary; // CGI/1.1 doesn't define this but PHP demands it
|
||||
env.remove("REMOTE_HOST");
|
||||
env["REMOTE_ADDR"] = event->remoteAddress.toString();
|
||||
// TODO: If we ever support HTTP authentication, we should use these
|
||||
env.remove("AUTH_TYPE");
|
||||
env.remove("REMOTE_USER");
|
||||
env.remove("REMOTE_IDENT");
|
||||
if (event->contentType.isEmpty())
|
||||
{
|
||||
env.remove("CONTENT_TYPE");
|
||||
env.remove("CONTENT_LENGTH");
|
||||
}
|
||||
else
|
||||
{
|
||||
env["CONTENT_TYPE"] = event->contentType;
|
||||
env["CONTENT_LENGTH"] = QString::number(event->content->unreadBytes());
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
|
||||
env["QUERY_STRING"] = event->url.query();
|
||||
#else
|
||||
env["QUERY_STRING"] = event->url.encodedQuery();
|
||||
#endif
|
||||
|
||||
// Populate HTTP header environment variables
|
||||
QMultiHash<QString, QString>::const_iterator iter = event->headers.constBegin();
|
||||
while (iter != event->headers.constEnd())
|
||||
{
|
||||
QString key = "HTTP_" + iter.key().toUpper().replace('-', '_');
|
||||
if (key != "HTTP_CONTENT_TYPE" && key != "HTTP_CONTENT_LENGTH")
|
||||
env[key] = iter.value();
|
||||
iter++;
|
||||
}
|
||||
|
||||
// Populate HTTP_COOKIE parameter
|
||||
iter = event->cookies.constBegin();
|
||||
QString cookies;
|
||||
while (iter != event->cookies.constEnd())
|
||||
{
|
||||
if (!cookies.isEmpty())
|
||||
cookies += "; ";
|
||||
cookies += iter.key() + '=' + iter.value();
|
||||
iter++;
|
||||
}
|
||||
if (!cookies.isEmpty())
|
||||
env["HTTP_COOKIE"] = cookies;
|
||||
|
||||
// Load environment into process space
|
||||
QStringList p_env;
|
||||
QMap<QString, QString>::iterator env_iter = env.begin();
|
||||
while (env_iter != env.end())
|
||||
{
|
||||
p_env << env_iter.key() + '=' + env_iter.value();
|
||||
env_iter++;
|
||||
}
|
||||
process->setEnvironment(p_env);
|
||||
|
||||
// Launch process
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
|
||||
if (event->url.hasQuery() && event->url.query().contains('='))
|
||||
#else
|
||||
if (event->url.hasQuery() && event->url.encodedQuery().contains('='))
|
||||
#endif
|
||||
{
|
||||
// CGI/1.1 spec says to pass the query on the command line if there's no embedded = sign
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
|
||||
process->start(qxt_d().binary + ' ' + event->url.query(), QIODevice::ReadWrite);
|
||||
#else
|
||||
process->start(qxt_d().binary + ' ' + event->url.encodedQuery(), QIODevice::ReadWrite);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
process->start(qxt_d().binary, QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
// Start the timeout
|
||||
if(qxt_d().timeout > 0)
|
||||
{
|
||||
requestInfo.timeout->start(qxt_d().timeout);
|
||||
}
|
||||
|
||||
// Transmit POST data
|
||||
if (event->content)
|
||||
{
|
||||
QObject::connect(event->content, SIGNAL(readyRead()), &qxt_d(), SLOT(browserReadyRead()));
|
||||
qxt_d().browserReadyRead(event->content);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
*/
|
||||
void QxtWebCgiServicePrivate::browserReadyRead(QObject* o_content)
|
||||
{
|
||||
if (!o_content) o_content = sender();
|
||||
QxtWebContent* content = static_cast<QxtWebContent*>(o_content); // this is a private class, no worries about type safety
|
||||
|
||||
// Read POST data and copy it to the process
|
||||
QByteArray data = content->readAll();
|
||||
if (!data.isEmpty())
|
||||
processes[content]->write(data);
|
||||
|
||||
// If no POST data remains unsent, clean up
|
||||
if (!content->unreadBytes() && processes.contains(content))
|
||||
{
|
||||
processes[content]->closeWriteChannel();
|
||||
processes.remove(content);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
*/
|
||||
void QxtWebCgiServicePrivate::processReadyRead()
|
||||
{
|
||||
QProcess* process = static_cast<QProcess*>(sender());
|
||||
QxtCgiRequestInfo& request = requests[process];
|
||||
|
||||
QByteArray line;
|
||||
while (process->canReadLine())
|
||||
{
|
||||
// Read in a CGI/1.1 header line
|
||||
line = process->readLine().replace(QByteArray("\r"), ""); //krazy:exclude=doublequote_chars
|
||||
if (line == "\n")
|
||||
{
|
||||
// An otherwise-empty line indicates the end of CGI/1.1 headers and the start of content
|
||||
QObject::disconnect(process, SIGNAL(readyRead()), this, 0);
|
||||
QxtWebPageEvent* event = 0;
|
||||
int code = 200;
|
||||
if (request.headers.contains("status"))
|
||||
{
|
||||
// CGI/1.1 defines a "Status:" header that dictates the HTTP response code
|
||||
code = request.headers["status"].left(3).toInt();
|
||||
if (code >= 300 && code < 400) // redirect
|
||||
{
|
||||
event = new QxtWebRedirectEvent(request.sessionID, request.requestID, request.headers["location"], code);
|
||||
}
|
||||
}
|
||||
// If a previous header (currently just status) hasn't created an event, create a normal page event here
|
||||
if (!event)
|
||||
{
|
||||
event = new QxtWebPageEvent(request.sessionID, request.requestID, process);
|
||||
event->status = code;
|
||||
}
|
||||
// Add other response headers passed from CGI (currently only Content-Type is supported)
|
||||
if (request.headers.contains("content-type"))
|
||||
event->contentType = request.headers["content-type"].toUtf8();
|
||||
// TODO: QxtWeb doesn't support transmitting arbitrary HTTP headers right now, but it may be desirable
|
||||
// for applications that know what kind of server frontend they're using to allow scripts to send
|
||||
// protocol-specific headers.
|
||||
|
||||
// Post the event
|
||||
qxt_p().postEvent(event);
|
||||
request.eventSent = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Since we haven't reached the end of headers yet, parse a header
|
||||
int pos = line.indexOf(": ");
|
||||
QByteArray hdrName = line.left(pos).toLower();
|
||||
QByteArray hdrValue = line.mid(pos + 2).replace(QByteArray("\n"), ""); //krazy:exclude=doublequote_chars
|
||||
if (hdrName == "set-cookie")
|
||||
{
|
||||
// Parse a new cookie and post an event to send it to the client
|
||||
QList<QByteArray> cookies = hdrValue.split(',');
|
||||
foreach(const QByteArray& cookie, cookies)
|
||||
{
|
||||
int equals = cookie.indexOf("=");
|
||||
int semi = cookie.indexOf(";");
|
||||
QByteArray cookieName = cookie.left(equals);
|
||||
int age = cookie.toLower().indexOf("max-age=", semi);
|
||||
int secs = -1;
|
||||
if (age >= 0)
|
||||
secs = cookie.mid(age + 8, cookie.indexOf(";", age) - age - 8).toInt();
|
||||
if (secs == 0)
|
||||
{
|
||||
qxt_p().postEvent(new QxtWebRemoveCookieEvent(request.sessionID, cookieName));
|
||||
}
|
||||
else
|
||||
{
|
||||
QByteArray cookieValue = cookie.mid(equals + 1, semi - equals - 1);
|
||||
QDateTime cookieExpires;
|
||||
if (secs != -1)
|
||||
cookieExpires = QDateTime::currentDateTime().addSecs(secs);
|
||||
qxt_p().postEvent(new QxtWebStoreCookieEvent(request.sessionID, cookieName, cookieValue, cookieExpires));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(hdrName == "x-qxtweb-timeout")
|
||||
{
|
||||
if(timeoutOverride)
|
||||
request.timeout->setInterval(hdrValue.toInt());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store other headers for later inspection
|
||||
request.headers[hdrName] = hdrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
*/
|
||||
void QxtWebCgiServicePrivate::processFinished()
|
||||
{
|
||||
QProcess* process = static_cast<QProcess*>(sender());
|
||||
QxtCgiRequestInfo& request = requests[process];
|
||||
|
||||
if (!request.eventSent)
|
||||
{
|
||||
// If no event was posted, issue an internal error
|
||||
qxt_p().postEvent(new QxtWebErrorEvent(request.sessionID, request.requestID, 500, "Internal Server Error"));
|
||||
}
|
||||
|
||||
// Clean up data structures
|
||||
process->close();
|
||||
QxtWebContent* key = processes.key(process);
|
||||
if (key) processes.remove(key);
|
||||
timeoutMapper.removeMappings(request.timeout);
|
||||
requests.remove(process);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
*/
|
||||
void QxtWebCgiServicePrivate::terminateProcess(QObject* o_process)
|
||||
{
|
||||
QProcess* process = static_cast<QProcess*>(o_process);
|
||||
QxtCgiRequestInfo& request = requests[process];
|
||||
|
||||
if(request.terminateSent)
|
||||
{
|
||||
// kill with fire
|
||||
process->kill();
|
||||
}
|
||||
else
|
||||
{
|
||||
// kill nicely
|
||||
process->terminate();
|
||||
request.terminateSent = true;
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2006 - 2011, the LibQxt project.
|
||||
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of the LibQxt project nor the
|
||||
** names of its contributors may be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
** <http://libqxt.org> <foundation@libqxt.org>
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QXTWEBCGISERVICE_H
|
||||
#define QXTWEBCGISERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qxtglobal.h>
|
||||
#include "qxtabstractwebsessionmanager.h"
|
||||
#include "qxtabstractwebservice.h"
|
||||
class QxtWebEvent;
|
||||
class QxtWebRequestEvent;
|
||||
|
||||
class QxtWebCgiServicePrivate;
|
||||
class QXT_WEB_EXPORT QxtWebCgiService : public QxtAbstractWebService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QxtWebCgiService(const QString& binary, QxtAbstractWebSessionManager* manager, QObject* parent = 0);
|
||||
|
||||
QString binary() const;
|
||||
void setBinary(const QString& bin);
|
||||
|
||||
int timeout() const;
|
||||
void setTimeout(int time);
|
||||
|
||||
bool timeoutOverride() const;
|
||||
void setTimeoutOverride(bool enable);
|
||||
|
||||
virtual void pageRequestedEvent(QxtWebRequestEvent* event);
|
||||
|
||||
private:
|
||||
QXT_DECLARE_PRIVATE(QxtWebCgiService)
|
||||
};
|
||||
|
||||
#endif // QXTWEBCGISERVICE_H
|