mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-06 20:20:41 +02:00
Compare commits
124 Commits
whatsnew_0
...
0.3.2
Author | SHA1 | Date | |
---|---|---|---|
|
a05972e9ce | ||
|
5157e13ba1 | ||
|
9f97afc148 | ||
|
8b1b0091c6 | ||
|
3e9aee3687 | ||
|
48bb0a82f9 | ||
|
1efdf38085 | ||
|
3e4f4d2f38 | ||
|
a2f870f2b8 | ||
|
2ac167d438 | ||
|
c218695a3d | ||
|
fae5f1dbbe | ||
|
54d29cc05d | ||
|
5aea02def2 | ||
|
368aa20b75 | ||
|
d2a07f2b6c | ||
|
14253a9c66 | ||
|
6881f4218a | ||
|
17badb972e | ||
|
2ea09dd60d | ||
|
87f7b6b2c6 | ||
|
01986a4129 | ||
|
2b404b517f | ||
|
b21b2d10f7 | ||
|
04deaba788 | ||
|
5cabc62733 | ||
|
01c6c3f0b6 | ||
|
b1a5cd4dcb | ||
|
58f78725db | ||
|
4210e8eab8 | ||
|
115492d1cc | ||
|
edadbb0c95 | ||
|
6c67dfcab7 | ||
|
b9453ab77b | ||
|
9507ffdd86 | ||
|
ff768954f6 | ||
|
15729bb66a | ||
|
41f46aaeea | ||
|
9e0d884f80 | ||
|
d34491b85f | ||
|
45070fb4e1 | ||
|
18612b48d3 | ||
|
a38c0a544d | ||
|
d38c9730fb | ||
|
d25320833c | ||
|
d38600dd6a | ||
|
6fa48587e1 | ||
|
8da0f3e9a3 | ||
|
ab402c0867 | ||
|
545a915439 | ||
|
d026902d91 | ||
|
ff72157c5f | ||
|
faab306dbe | ||
|
57fef9f3f2 | ||
|
89fac77951 | ||
|
ef02e9b4ac | ||
|
99b09c1faa | ||
|
d66e86f5c6 | ||
|
9bd46984e0 | ||
|
3992392245 | ||
|
198e92bc2c | ||
|
2f899eed2a | ||
|
8cdd4bdea3 | ||
|
3d53b0c251 | ||
|
0ac9512eb9 | ||
|
3f0ac7c666 | ||
|
faf7d00fdd | ||
|
b31abb0979 | ||
|
f2009cf99b | ||
|
0d97a47cc5 | ||
|
7db6beb896 | ||
|
e56a629ad7 | ||
|
ef918bbbcf | ||
|
60911ab887 | ||
|
e10a96ecd5 | ||
|
e99973925a | ||
|
949c6f6341 | ||
|
e041723ffc | ||
|
89919928da | ||
|
d4fc504f3d | ||
|
05924b8deb | ||
|
6d4aa50596 | ||
|
7ee2755617 | ||
|
35406ceb5a | ||
|
9efb536e55 | ||
|
b8d27f1811 | ||
|
0939ba0705 | ||
|
3788bc7cbf | ||
|
54723abc07 | ||
|
900f57437f | ||
|
300c9d5d68 | ||
|
96c9996284 | ||
|
8a15bcaa66 | ||
|
d17d67869c | ||
|
c491f33ce4 | ||
|
1dee5c809c | ||
|
924ede61b4 | ||
|
0d64d9c42d | ||
|
6b6fb909cd | ||
|
b51ff46085 | ||
|
46ec23990f | ||
|
eb46feac2c | ||
|
2c206f4193 | ||
|
c1bd19b35b | ||
|
370154cc46 | ||
|
9a81ce8b89 | ||
|
c805d283d4 | ||
|
03379f361c | ||
|
c671c0e898 | ||
|
edaf49b4c5 | ||
|
682903b0cb | ||
|
53f7f599d5 | ||
|
cc669fc20f | ||
|
4e7496a38a | ||
|
5842cdceee | ||
|
b7e0be8d9d | ||
|
a203b60cbb | ||
|
2be08af321 | ||
|
ad4c229a6b | ||
|
b2e0206e34 | ||
|
743ae013ea | ||
|
767cf7c1b9 | ||
|
6be94ab81c | ||
|
b1ed304a61 |
@@ -16,7 +16,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 3 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 0 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 2 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
@@ -108,7 +108,7 @@ macro_optional_find_package(LibAttica)
|
||||
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" FALSE "" "")
|
||||
|
||||
macro_optional_find_package(QuaZip)
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers autmatically. Will build internal copy instead." "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically." "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
|
||||
IF( NOT QuaZip_FOUND )
|
||||
add_subdirectory( ${CMAKE_SOURCE_DIR}/src/libtomahawk/thirdparty/quazip )
|
||||
@@ -116,6 +116,7 @@ IF( NOT QuaZip_FOUND )
|
||||
SET( QuaZip_LIBRARY quazip )
|
||||
SET( QuaZip_LIBRARIES ${QuaZip_LIBRARY} )
|
||||
SET( QuaZip_FOUND true )
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically. Building internal copy" "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
|
||||
# copy headers to build/quazip so we can use proper includes inside the code
|
||||
FILE( COPY ${CMAKE_SOURCE_DIR}/src/libtomahawk/thirdparty/quazip/quazip/ DESTINATION ${CMAKE_BINARY_DIR}/libtomahawk/thirdparty/quazip )
|
||||
@@ -211,4 +212,7 @@ ADD_SUBDIRECTORY( src/libtomahawk )
|
||||
SET( TOMAHAWK_LIBRARIES tomahawklib )
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( admin )
|
||||
ADD_SUBDIRECTORY( src/breakpad/CrashReporter )
|
||||
|
||||
IF( NOT DISABLE_CRASHREPORTER )
|
||||
ADD_SUBDIRECTORY( src/breakpad/CrashReporter )
|
||||
ENDIF()
|
||||
|
@@ -2,6 +2,7 @@
|
||||
# This module looks for clucene (http://clucene.sf.net) support
|
||||
# It will define the following values
|
||||
#
|
||||
# CLUCENE_INCLUDE_DIRS = CLUCENE_INCLUDE_DIR + CLUCENE_LIBRARY_DIR
|
||||
# CLUCENE_INCLUDE_DIR = where CLucene/StdHeader.h can be found
|
||||
# CLUCENE_LIBRARY_DIR = where CLucene/clucene-config.h can be found
|
||||
# CLUCENE_LIBRARIES = the libraries to link against CLucene
|
||||
@@ -17,6 +18,7 @@ FIND_PACKAGE(CLuceneUnstable)
|
||||
IF(CLUCENEUNSTABLE_FOUND)
|
||||
SET(CLucene_FOUND TRUE)
|
||||
SET(CLUCENE_INCLUDE_DIR ${CLUCENE_UNSTABLE_INCLUDE_DIRS})
|
||||
SET(CLUCENE_INCLUDE_DIRS ${CLUCENE_INCLUDE_DIR})
|
||||
SET(CLUCENE_LIBRARIES ${CLUCENE_UNSTABLE_LIBS})
|
||||
|
||||
#MESSAGE(FATAL_ERROR NARF)
|
||||
@@ -106,7 +108,9 @@ ENDIF (CLUCENE_LIBRARY_DIR)
|
||||
|
||||
IF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
|
||||
SET(CLucene_FOUND TRUE)
|
||||
SET(CLUCENE_INCLUDE_DIRS ${CLUCENE_LIBRARY_DIR} ${CLUCENE_INCLUDE_DIR})
|
||||
ENDIF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
|
||||
|
||||
ENDIF(CLUCENEUNSTABLE_FOUND)
|
||||
|
||||
IF(CLucene_FOUND)
|
||||
@@ -120,7 +124,8 @@ ELSE(CLucene_FOUND)
|
||||
ENDIF(CLucene_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
CLUCENE_INCLUDE_DIR
|
||||
CLUCENE_LIBRARY_DIR
|
||||
CLUCENE_INCLUDE_DIRS
|
||||
CLUCENE_INCLUDE_DIR
|
||||
CLUCENE_LIBRARY_DIR
|
||||
CLUCENE_LIBRARIES
|
||||
)
|
||||
|
182
CMakeModules/GNUInstallDirs.cmake
Normal file
182
CMakeModules/GNUInstallDirs.cmake
Normal file
@@ -0,0 +1,182 @@
|
||||
# - Define GNU standard installation directories
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
# Inclusion of this module defines the following variables:
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
# where <dir> is one of:
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||
# install() commands for the corresponding file type. If the includer does
|
||||
# not define a value the above-shown default will be used and the value will
|
||||
# appear in the cache for editing by the user.
|
||||
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the value
|
||||
# of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# Note that the future of multi-arch handling may be even
|
||||
# more complicated than that: http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING
|
||||
AND NOT EXISTS "/etc/debian_version")
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
@@ -273,7 +273,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
;Main executable.
|
||||
File "${INSTALL_PATH}\bin\tomahawk.exe"
|
||||
|
||||
File "${INSTALL_PATH}\bin\CrashReporter.exe"
|
||||
File "${INSTALL_PATH}\bin\tomahawk_crash_reporter.exe"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_breakpad.dll"
|
||||
|
||||
File "${INSTALL_PATH}\bin\libqxtweb-standalone.dll"
|
||||
@@ -287,7 +287,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
;Main executable.
|
||||
File "${BUILD_PATH}\tomahawk.exe"
|
||||
|
||||
File "${BUILD_PATH}\CrashReporter.exe"
|
||||
File "${BUILD_PATH}\tomahawk_crash_reporter.exe"
|
||||
File "${BUILD_PATH}\libtomahawk_breakpad.dll"
|
||||
|
||||
File "${BUILD_PATH}\libtomahawklib.dll"
|
||||
|
42
ChangeLog
42
ChangeLog
@@ -1,3 +1,43 @@
|
||||
Version 0.3.2:
|
||||
* Improved syncing process, it's faster and more reliable now.
|
||||
* Fixed UPnP issues.
|
||||
* Fixed not updating collections and views after a collection changes.
|
||||
* Fixed not showing a source's proper name at all times.
|
||||
* Improved music scanner reliability.
|
||||
* Fixed various labels not being painted in the right color when selected.
|
||||
* Support .oga (ogg mimetype) files.
|
||||
* Fixed stuck Now Playing indicator icon.
|
||||
* Fixed sidebar width of settings dialog on Windows.
|
||||
* Fixed not always showing delete icon on hovered temporary pages.
|
||||
* Fixed inability to select externally mounted drives.
|
||||
* Fixed bug where speaker would be stuck next to a playlist.
|
||||
* Fixed bug where first startup would show a loading spinner in the
|
||||
Dashboard's "Recent Additions" forever.
|
||||
* Automatically upgrade resolvers when an update is found.
|
||||
* Fixed last played track of a friend never expiring.
|
||||
* Fixed parsing of rdio tracks.
|
||||
* Changed steering mechanism in stations to be user-friendlier.
|
||||
* Fixed loading biographies of artist names with special characters.
|
||||
* Fixed behaviour of dropping Spotify playlists on the sidebar.
|
||||
* Fixed hard to read source-name in the audio control area on OS X.
|
||||
* Fixed crashes when playing Grooveshark tracks.
|
||||
* Fixed bug where clicking the latch button would flicker and unlatch.
|
||||
* Fixed Jabber accounts not connecting properly when proxy is in use.
|
||||
|
||||
Version 0.3.1:
|
||||
* Fixed not resolving to local files.
|
||||
* Fixed shutdown crash on Windows.
|
||||
* Support more widget types in Javascript resolver configs.
|
||||
* Fixed bug where red headphone would be visible on My Collection
|
||||
when listened along to source went offline.
|
||||
* Draw author name as well as avatar in recently played playlists.
|
||||
* Fixed Tomahawk integration in Unity.
|
||||
* Fixed incorrect item selected in source tree when deleting temporary
|
||||
pages.
|
||||
* Fixed currently played label disappearing after 10 minutes regardless
|
||||
of length of track.
|
||||
* Fixed crash on Sparkle upgrade on OS X.
|
||||
|
||||
Version 0.3.0:
|
||||
* Make artist names in the album view clickable.
|
||||
* Don't start playing if a tomahawk:// link was clicked while Tomahawk
|
||||
@@ -12,7 +52,7 @@ Version 0.3.0:
|
||||
* Added YouTube resolver.
|
||||
* Fixed bug where going offline then online would not re-connect to many
|
||||
peers.
|
||||
* Added support for auto-updating live XSPF playlists.
|
||||
* Added support for auto-updating live XSPF playlists.
|
||||
* Don't show an age of 41 years for tracks that have no age information.
|
||||
* Show config UI for resolvers that have them as soon as you add them.
|
||||
* Add support for Echo Nest Personal Catalogs and User Radio. Synchronize
|
||||
|
@@ -250,7 +250,7 @@ frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
|
||||
commands.append(['mkdir', '-p', frameworks_dir])
|
||||
resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
|
||||
commands.append(['mkdir', '-p', resources_dir])
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'plugins')
|
||||
binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name)
|
||||
|
||||
fixed_libraries = []
|
||||
@@ -502,9 +502,9 @@ except:
|
||||
print 'Failed to find spotify resolver'
|
||||
|
||||
try:
|
||||
FixPlugin('CrashReporter', '../MacOS')
|
||||
FixPlugin('tomahawk_crash_reporter', '../MacOS')
|
||||
except:
|
||||
print 'Failed to find CrashReporter'
|
||||
print 'Failed to find tomahawk_crash_reporter'
|
||||
|
||||
for plugin in QT_PLUGINS:
|
||||
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
||||
|
BIN
data/images/apply-check.png
Normal file
BIN
data/images/apply-check.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
3028
lang/tomahawk_en.ts
Normal file
3028
lang/tomahawk_en.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/lang">
|
||||
<file>tomahawk_de.qm</file>
|
||||
<file>tomahawk_en.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -98,6 +98,7 @@
|
||||
<file>data/images/track-icon-22x22.png</file>
|
||||
<file>data/images/track-icon-32x32.png</file>
|
||||
<file>data/images/track-icon-16x16.png</file>
|
||||
<file>data/images/apply-check.png</file>
|
||||
<file>data/stylesheets/topbar-radiobuttons.css</file>
|
||||
<file>data/icons/tomahawk-icon-16x16.png</file>
|
||||
<file>data/icons/tomahawk-icon-32x32.png</file>
|
||||
|
@@ -40,6 +40,7 @@ SET( tomahawkSources ${tomahawkSources}
|
||||
musicscanner.cpp
|
||||
shortcuthandler.cpp
|
||||
scanmanager.cpp
|
||||
ubuntuunityhack.cpp
|
||||
tomahawkapp.cpp
|
||||
main.cpp
|
||||
)
|
||||
@@ -85,6 +86,7 @@ SET( tomahawkHeaders ${tomahawkHeaders}
|
||||
|
||||
musicscanner.h
|
||||
scanmanager.h
|
||||
ubuntuunityhack.h
|
||||
shortcuthandler.h
|
||||
)
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
#include "GetNewStuffDelegate.h"
|
||||
#include "GetNewStuffModel.h"
|
||||
|
||||
GetNewStuffDialog::GetNewStuffDialog( QWidget *parent, Qt::WindowFlags f )
|
||||
GetNewStuffDialog::GetNewStuffDialog( QWidget* parent, Qt::WindowFlags f )
|
||||
: QDialog( parent, f )
|
||||
, ui( new Ui::GetNewStuffDialog )
|
||||
, m_model( new GetNewStuffModel( this ) )
|
||||
@@ -37,16 +37,17 @@ GetNewStuffDialog::GetNewStuffDialog( QWidget *parent, Qt::WindowFlags f )
|
||||
|
||||
ui->listView->setMouseTracking( true );
|
||||
|
||||
setMinimumSize( 560, 350 );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
setMinimumSize( 510, 350 );
|
||||
setMaximumSize( 510, 350 );
|
||||
setMaximumSize( 560, 350 );
|
||||
setSizeGripEnabled( false );
|
||||
|
||||
ui->listView->setAttribute( Qt::WA_MacShowFocusRect, false );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
GetNewStuffDialog::~GetNewStuffDialog()
|
||||
{
|
||||
delete ui;
|
||||
|
@@ -34,9 +34,6 @@ LoadXSPFDialog::LoadXSPFDialog( QWidget* parent, Qt::WindowFlags f )
|
||||
m_ui->verticalLayout->setSpacing( 0 );
|
||||
#endif
|
||||
|
||||
connect( m_ui->buttonBox, SIGNAL( accepted() ), SLOT( accept() ) );
|
||||
connect( m_ui->buttonBox, SIGNAL( rejected() ), SLOT( reject() ) );
|
||||
|
||||
connect( m_ui->navigateButton, SIGNAL( clicked( bool ) ), this, SLOT( getLocalFile() ) );
|
||||
}
|
||||
|
||||
@@ -47,7 +44,7 @@ LoadXSPFDialog::~LoadXSPFDialog()
|
||||
void
|
||||
LoadXSPFDialog::getLocalFile()
|
||||
{
|
||||
QString url = QFileDialog::getOpenFileName( this, tr( "Load XSPF File" ), QDir::homePath(), ".xspf" );
|
||||
QString url = QFileDialog::getOpenFileName( this, tr( "Load XSPF File" ), QDir::homePath(), tr( "XSPF Files (*.xspf)" ) );
|
||||
m_ui->lineEdit->setText( url );
|
||||
}
|
||||
|
||||
|
@@ -19,9 +19,9 @@
|
||||
#include "audiocontrols.h"
|
||||
#include "ui_audiocontrols.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QDropEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtGui/QDropEvent>
|
||||
#include <QtGui/QMouseEvent>
|
||||
|
||||
#include "audio/audioengine.h"
|
||||
#include "playlist/playlistview.h"
|
||||
@@ -86,7 +86,11 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
|
||||
ui->loveButton->setCheckable( true );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
ui->ownerLabel->setForegroundRole( QPalette::Text );
|
||||
#else
|
||||
ui->ownerLabel->setForegroundRole( QPalette::Dark );
|
||||
#endif
|
||||
ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
|
||||
|
||||
ui->seekSlider->setEnabled( true );
|
||||
@@ -204,9 +208,11 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
m_sliderTimeLine.setFrameRange( 0, duration );
|
||||
m_sliderTimeLine.setCurrentTime( 0 );
|
||||
m_seekMsecs = -1;
|
||||
|
||||
|
||||
ui->seekSlider->setVisible( true );
|
||||
|
||||
m_noTimeChange = false;
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
trackInfo["artist"] = result->artist()->name();
|
||||
trackInfo["album"] = result->album()->name();
|
||||
@@ -373,9 +379,22 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
|
||||
|
||||
if ( m_sliderTimeLine.currentTime() > msElapsed || m_seekMsecs != -1 )
|
||||
if ( m_noTimeChange )
|
||||
{
|
||||
if ( m_sliderTimeLine.currentTime() != msElapsed )
|
||||
{
|
||||
m_noTimeChange = false;
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
}
|
||||
else if ( m_sliderTimeLine.currentTime() >= msElapsed || m_seekMsecs != -1 )
|
||||
{
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
|
||||
m_noTimeChange = false;
|
||||
if ( m_sliderTimeLine.currentTime() == msElapsed )
|
||||
m_noTimeChange = true;
|
||||
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
m_seekMsecs = -1;
|
||||
if ( AudioEngine::instance()->state() != AudioEngine::Paused )
|
||||
|
@@ -19,8 +19,8 @@
|
||||
#ifndef AUDIOCONTROLS_H
|
||||
#define AUDIOCONTROLS_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimeLine>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtCore/QTimeLine>
|
||||
|
||||
#include "result.h"
|
||||
#include "playlistinterface.h"
|
||||
@@ -95,6 +95,7 @@ private:
|
||||
|
||||
QTimeLine m_sliderTimeLine;
|
||||
qint64 m_seekMsecs;
|
||||
bool m_noTimeChange;
|
||||
};
|
||||
|
||||
#endif // AUDIOCONTROLS_H
|
||||
|
@@ -28,9 +28,6 @@
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
@@ -164,9 +161,6 @@
|
||||
<height>58</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
|
@@ -18,11 +18,17 @@
|
||||
|
||||
#include "BreakPad.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QFileInfo>
|
||||
#include <string.h>
|
||||
|
||||
#define CRASH_REPORTER_BINARY "CrashReporter"
|
||||
#define CRASH_REPORTER_BINARY "tomahawk_crash_reporter"
|
||||
|
||||
bool s_active = true;
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
@@ -38,8 +44,10 @@ LaunchUploader( const char* dump_dir, const char* minidump_id, void* that, bool
|
||||
return false;
|
||||
|
||||
const char* crashReporter = static_cast<BreakPad*>(that)->crashReporter();
|
||||
pid_t pid = fork();
|
||||
if ( !s_active || strlen( crashReporter ) == 0 )
|
||||
return false;
|
||||
|
||||
pid_t pid = fork();
|
||||
if ( pid == -1 ) // fork failed
|
||||
return false;
|
||||
if ( pid == 0 )
|
||||
@@ -63,14 +71,25 @@ LaunchUploader( const char* dump_dir, const char* minidump_id, void* that, bool
|
||||
}
|
||||
|
||||
|
||||
BreakPad::BreakPad( const QString& path )
|
||||
BreakPad::BreakPad( const QString& path, bool active )
|
||||
#ifdef Q_OS_LINUX
|
||||
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true )
|
||||
#else
|
||||
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true, 0 )
|
||||
#endif
|
||||
{
|
||||
QString reporter = QString( "%1/%2" ).arg( qApp->applicationDirPath() ).arg( CRASH_REPORTER_BINARY );
|
||||
s_active = active;
|
||||
|
||||
QString reporter;
|
||||
QString localReporter = QString( "%1/%2" ).arg( qApp->applicationDirPath() ).arg( CRASH_REPORTER_BINARY );
|
||||
QString globalReporter = QString( "%1/%2" ).arg( CMAKE_INSTALL_PREFIX "/" CMAKE_INSTALL_LIBEXECDIR ).arg( CRASH_REPORTER_BINARY );
|
||||
|
||||
if ( QFileInfo( localReporter ).exists() )
|
||||
reporter = localReporter;
|
||||
else if ( QFileInfo( globalReporter ).exists() )
|
||||
reporter = globalReporter;
|
||||
else
|
||||
tLog() << "Could not find \"" CRASH_REPORTER_BINARY "\" in \"" CMAKE_INSTALL_PREFIX "/" CMAKE_INSTALL_LIBEXECDIR "\" or application path";
|
||||
|
||||
char* creporter;
|
||||
std::string sreporter = reporter.toStdString();
|
||||
@@ -126,7 +145,7 @@ LaunchUploader( const wchar_t* dump_dir, const wchar_t* minidump_id, void* that,
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
ZeroMemory( &pi, sizeof(pi) );
|
||||
|
||||
if (CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
|
||||
if ( CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ) )
|
||||
{
|
||||
CloseHandle( pi.hProcess );
|
||||
CloseHandle( pi.hThread );
|
||||
@@ -137,9 +156,24 @@ LaunchUploader( const wchar_t* dump_dir, const wchar_t* minidump_id, void* that,
|
||||
}
|
||||
|
||||
|
||||
BreakPad::BreakPad( const QString& path )
|
||||
BreakPad::BreakPad( const QString& path, bool active )
|
||||
: google_breakpad::ExceptionHandler( path.toStdWString(), 0, LaunchUploader, this, true )
|
||||
{
|
||||
s_active = active;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
|
||||
void
|
||||
BreakPad::setActive( bool enabled )
|
||||
{
|
||||
s_active = enabled;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BreakPad::isActive()
|
||||
{
|
||||
return s_active;
|
||||
}
|
||||
|
@@ -32,11 +32,14 @@ class BreakPad : public google_breakpad::ExceptionHandler
|
||||
const char* m_crashReporter; // again, const char[]
|
||||
|
||||
public:
|
||||
BreakPad( const QString &dump_write_dirpath );
|
||||
BreakPad( const QString& dump_write_dirpath, bool active );
|
||||
|
||||
~BreakPad()
|
||||
{}
|
||||
|
||||
static void setActive( bool enabled );
|
||||
static bool isActive();
|
||||
|
||||
void setProductName( const char* s ) { m_productName = s; };
|
||||
const char* productName() const { return m_productName; }
|
||||
|
||||
|
@@ -1,8 +1,10 @@
|
||||
PROJECT( CrashReporter )
|
||||
|
||||
|
||||
FIND_PACKAGE( Qt4 REQUIRED )
|
||||
SET( QT_USE_QTNETWORK TRUE )
|
||||
|
||||
|
||||
SET( crashreporter_SOURCES main.cpp CrashReporter.cpp )
|
||||
SET( crashreporter_HEADERS CrashReporter.h )
|
||||
SET( crashreporter_UI CrashReporter.ui )
|
||||
@@ -16,5 +18,8 @@ INCLUDE( ${QT_USE_FILE} )
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src ../../libtomahawk )
|
||||
ADD_DEFINITIONS( ${QT_DEFINITIONS} )
|
||||
|
||||
ADD_EXECUTABLE( CrashReporter WIN32 ${crashreporter_SOURCES} ${crashreporter_HEADERS_MOC} ${crashreporter_UI_HEADERS} ${crashreporter_RC_RCC} )
|
||||
TARGET_LINK_LIBRARIES( CrashReporter ${QT_LIBRARIES} tomahawklib )
|
||||
ADD_EXECUTABLE( tomahawk_crash_reporter WIN32 ${crashreporter_SOURCES} ${crashreporter_HEADERS_MOC} ${crashreporter_UI_HEADERS} ${crashreporter_RC_RCC} )
|
||||
TARGET_LINK_LIBRARIES( tomahawk_crash_reporter ${QT_LIBRARIES} tomahawklib )
|
||||
|
||||
INCLUDE(GNUInstallDirs)
|
||||
install(TARGETS tomahawk_crash_reporter RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR})
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#cmakedefine DEBUG_BUILD
|
||||
|
||||
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
#define CMAKE_INSTALL_LIBEXECDIR "${CMAKE_INSTALL_LIBEXECDIR}"
|
||||
#define CMAKE_SYSTEM "${CMAKE_SYSTEM}"
|
||||
|
||||
#cmakedefine LION
|
||||
|
@@ -45,6 +45,8 @@ AtticaManager::AtticaManager( QObject* parent )
|
||||
|
||||
// resolvers
|
||||
m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org:10480/resolvers/providers.xml" ) );
|
||||
|
||||
qRegisterMetaType< Attica::Content >( "Attica::Content" );
|
||||
}
|
||||
|
||||
|
||||
@@ -149,6 +151,7 @@ AtticaManager::pathFromId( const QString& resolverId ) const
|
||||
return m_resolverStates.value( resolverId ).scriptPath;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::uploadRating( const Content& c )
|
||||
{
|
||||
@@ -175,6 +178,7 @@ AtticaManager::uploadRating( const Content& c )
|
||||
emit resolverStateChanged( c.id() );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AtticaManager::userHasRated( const Content& c ) const
|
||||
{
|
||||
@@ -245,6 +249,7 @@ AtticaManager::resolverIconFetched()
|
||||
m_resolverStates[ resolverId ].pixmap = icon;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::syncServerData()
|
||||
{
|
||||
@@ -271,62 +276,16 @@ AtticaManager::syncServerData()
|
||||
if ( ( r.state == Installed || r.state == NeedsUpgrade ) &&
|
||||
!upstream.version().isEmpty() )
|
||||
{
|
||||
if ( newerVersion( r.version, upstream.version() ) )
|
||||
if ( TomahawkUtils::newerVersion( r.version, upstream.version() ) )
|
||||
{
|
||||
m_resolverStates[ id ].state = NeedsUpgrade;
|
||||
QMetaObject::invokeMethod( this, "upgradeResolver", Qt::QueuedConnection, Q_ARG( Attica::Content, upstream ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AtticaManager::newerVersion( const QString& older, const QString& newer ) const
|
||||
{
|
||||
// Dumb version comparison. Expects two strings, X.Y and Z.V. Returns true if Z > v || Z == V && V > Y
|
||||
// DOES NOT support X.Y.Z version strings
|
||||
if ( older.isEmpty() || newer.isEmpty() )
|
||||
return false;
|
||||
|
||||
QPair<int, int> oldVer, newVer;
|
||||
QStringList parts = older.split( "." );
|
||||
|
||||
if ( parts.size() == 1 )
|
||||
{
|
||||
oldVer.first = parts[ 0 ].toInt();
|
||||
oldVer.second = 0;
|
||||
}
|
||||
else if ( parts.size() == 2 )
|
||||
{
|
||||
oldVer.first = parts[ 0 ].toInt();
|
||||
oldVer.second = parts[ 1 ].toInt();;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
parts = newer.split( "." );
|
||||
if ( parts.size() == 1 )
|
||||
{
|
||||
newVer.first = parts[ 0 ].toInt();
|
||||
newVer.second = 0;
|
||||
}
|
||||
else if ( parts.size() == 2 )
|
||||
{
|
||||
newVer.first = parts[ 0 ].toInt();
|
||||
newVer.second = parts[ 1 ].toInt();;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
// Do the comparison
|
||||
if ( newVer.first > oldVer.first )
|
||||
return true;
|
||||
if ( newVer.first == oldVer.first &&
|
||||
newVer.second > oldVer.second )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
AtticaManager::installResolver( const Content& resolver )
|
||||
@@ -347,6 +306,7 @@ AtticaManager::installResolver( const Content& resolver )
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::upgradeResolver( const Content& resolver )
|
||||
{
|
||||
|
@@ -83,8 +83,6 @@ public:
|
||||
ResolverState resolverState( const Attica::Content& resolver ) const;
|
||||
QPixmap iconForResolver( const Attica::Content& id ); // Looks up in icon cache
|
||||
|
||||
void installResolver( const Attica::Content& resolver );
|
||||
void upgradeResolver( const Attica::Content& resolver );
|
||||
void uninstallResolver( const Attica::Content& resolver );
|
||||
void uninstallResolver( const QString& pathToResolver );
|
||||
QString pathFromId( const QString& resolverId ) const;
|
||||
@@ -92,6 +90,9 @@ public:
|
||||
void uploadRating( const Attica::Content& c );
|
||||
bool userHasRated( const Attica::Content& c ) const;
|
||||
|
||||
public slots:
|
||||
void installResolver( const Attica::Content& resolver );
|
||||
void upgradeResolver( const Attica::Content& resolver );
|
||||
|
||||
signals:
|
||||
void resolversReloaded( const Attica::Content::List& resolvers );
|
||||
@@ -111,7 +112,6 @@ private slots:
|
||||
void resolverIconFetched();
|
||||
|
||||
void syncServerData();
|
||||
bool newerVersion( const QString& older, const QString& newer ) const;
|
||||
|
||||
private:
|
||||
QString extractPayload( const QString& filename, const QString& resolverId ) const;
|
||||
@@ -127,4 +127,8 @@ private:
|
||||
static AtticaManager* s_instance;
|
||||
};
|
||||
|
||||
#ifdef LIBATTICA_FOUND
|
||||
Q_DECLARE_METATYPE( Attica::Content );
|
||||
#endif
|
||||
|
||||
#endif // ATTICAMANAGER_H
|
||||
|
@@ -440,6 +440,7 @@ set( libHeaders
|
||||
widgets/playlisttypeselectordlg.h
|
||||
widgets/welcomewidget.h
|
||||
widgets/whatshotwidget.h
|
||||
widgets/whatshotwidget_p.h
|
||||
widgets/RecentlyPlayedPlaylistsModel.h
|
||||
widgets/RecentPlaylistsModel.h
|
||||
widgets/OverlayButton.h
|
||||
@@ -501,7 +502,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
|
||||
${QJSON_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}/..
|
||||
${CLUCENE_INCLUDE_DIR}
|
||||
${CLUCENE_INCLUDE_DIRS}
|
||||
${PHONON_INCLUDES}
|
||||
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src
|
||||
|
||||
|
@@ -42,7 +42,7 @@ ActionCollection::initActions()
|
||||
m_actionCollection[ "latchOff" ] = new QAction( tr( "&Stop Listening Along" ), this );
|
||||
|
||||
bool isPublic = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening;
|
||||
QAction *privacyToggle = new QAction( tr( QString( isPublic ? "&Listen Privately" : "&Listen Publicly" ).toAscii().constData() ), this );
|
||||
QAction *privacyToggle = new QAction( ( isPublic ? tr( "&Listen Privately" ) : tr( "&Listen Publicly" ) ), this );
|
||||
privacyToggle->setIcon( QIcon( RESPATH "images/private-listening.png" ) );
|
||||
privacyToggle->setIconVisibleInMenu( isPublic );
|
||||
m_actionCollection[ "togglePrivacy" ] = privacyToggle;
|
||||
|
@@ -413,7 +413,7 @@ AudioEngine::togglePrivateListeningMode()
|
||||
#ifndef TOMAHAWK_HEADLESS
|
||||
QAction *privacyToggle = ActionCollection::instance()->getAction( "togglePrivacy" );
|
||||
bool isPublic = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening;
|
||||
privacyToggle->setText( tr( QString( isPublic ? "&Listen Privately" : "&Listen Publicly" ).toAscii().constData() ) );
|
||||
privacyToggle->setText( ( isPublic ? tr( "&Listen Privately" ) : tr( "&Listen Publicly" ) ) );
|
||||
privacyToggle->setIconVisibleInMenu( isPublic );
|
||||
#endif
|
||||
}
|
||||
@@ -450,9 +450,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
tLog() << "Starting new song:" << m_currentTrack->url();
|
||||
emit loading( m_currentTrack );
|
||||
|
||||
if ( QNetworkReply* qnr_io = qobject_cast< QNetworkReply* >( io.data() ) )
|
||||
connect( qnr_io, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( ioStreamError( QNetworkReply::NetworkError ) ) );
|
||||
|
||||
if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) )
|
||||
{
|
||||
if ( QNetworkReply* qnr_io = qobject_cast< QNetworkReply* >( io.data() ) )
|
||||
@@ -605,16 +602,6 @@ AudioEngine::playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::re
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::ioStreamError( QNetworkReply::NetworkError error )
|
||||
{
|
||||
if ( error != QNetworkReply::NoError )
|
||||
{
|
||||
if ( canGoNext() )
|
||||
loadNextTrack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::playlistNextTrackReady()
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include <phonon/MediaObject>
|
||||
#include <phonon/AudioOutput>
|
||||
@@ -137,7 +136,6 @@ private slots:
|
||||
|
||||
void setCurrentTrack( const Tomahawk::result_ptr& result );
|
||||
|
||||
void ioStreamError( QNetworkReply::NetworkError );
|
||||
private:
|
||||
void setState( AudioState state );
|
||||
|
||||
|
@@ -33,10 +33,12 @@ Collection::Collection( const source_ptr& source, const QString& name, QObject*
|
||||
: QObject( parent )
|
||||
, m_name( name )
|
||||
, m_lastmodified( 0 )
|
||||
, m_isLoaded( false )
|
||||
, m_changed( false )
|
||||
, m_source( source )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << name << source->friendlyName();
|
||||
|
||||
connect( source.data(), SIGNAL( synced() ), SLOT( onSynced() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -211,8 +213,8 @@ Collection::setTracks( const QList<unsigned int>& ids )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << ids.count() << name();
|
||||
|
||||
m_changed = true;
|
||||
emit tracksAdded( ids );
|
||||
emit changed();
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +223,19 @@ Collection::delTracks( const QList<unsigned int>& ids )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << ids.count() << name();
|
||||
|
||||
m_changed = true;
|
||||
emit tracksRemoved( ids );
|
||||
emit changed();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Collection::onSynced()
|
||||
{
|
||||
if ( m_changed )
|
||||
{
|
||||
m_changed = false;
|
||||
emit changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -49,8 +49,6 @@ public:
|
||||
Collection( const source_ptr& source, const QString& name, QObject* parent = 0 );
|
||||
virtual ~Collection();
|
||||
|
||||
virtual void setLoaded() { m_isLoaded = true; }
|
||||
virtual bool isLoaded() const { return m_isLoaded; }
|
||||
virtual QString name() const;
|
||||
|
||||
virtual void loadPlaylists() { qDebug() << Q_FUNC_INFO; }
|
||||
@@ -107,8 +105,11 @@ protected:
|
||||
QString m_name;
|
||||
unsigned int m_lastmodified; // unix time of last change to collection
|
||||
|
||||
private slots:
|
||||
void onSynced();
|
||||
|
||||
private:
|
||||
bool m_isLoaded;
|
||||
bool m_changed;
|
||||
|
||||
source_ptr m_source;
|
||||
QHash< QString, Tomahawk::playlist_ptr > m_playlists;
|
||||
|
@@ -73,7 +73,15 @@ Database::loadIndex()
|
||||
|
||||
|
||||
void
|
||||
Database::enqueue( QSharedPointer<DatabaseCommand> lc )
|
||||
Database::enqueue( const QList< QSharedPointer<DatabaseCommand> >& lc )
|
||||
{
|
||||
qDebug() << "Enqueueing" << lc.count() << "commands to rw thread";
|
||||
m_workerRW->enqueue( lc );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Database::enqueue( const QSharedPointer<DatabaseCommand>& lc )
|
||||
{
|
||||
if ( lc->doesMutates() )
|
||||
{
|
||||
|
@@ -66,7 +66,8 @@ signals:
|
||||
void newJobRW( QSharedPointer<DatabaseCommand> );
|
||||
|
||||
public slots:
|
||||
void enqueue( QSharedPointer<DatabaseCommand> lc );
|
||||
void enqueue( const QSharedPointer<DatabaseCommand>& lc );
|
||||
void enqueue( const QList< QSharedPointer<DatabaseCommand> >& lc );
|
||||
|
||||
private slots:
|
||||
void setIsReadyTrue() { m_ready = true; }
|
||||
|
@@ -69,22 +69,8 @@ DatabaseCollection::loadStations()
|
||||
connect( cmd, SIGNAL( stationLoaded( Tomahawk::source_ptr, QVariantList ) ),
|
||||
SLOT( stationCreated( const Tomahawk::source_ptr&, const QVariantList& ) ) );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );}
|
||||
|
||||
|
||||
/*void
|
||||
DatabaseCollection::loadTracks()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << source()->userName();
|
||||
|
||||
setLoaded();
|
||||
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( source()->collection() );
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( setTracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
@@ -143,19 +129,8 @@ DatabaseCollection::stations()
|
||||
}
|
||||
|
||||
|
||||
/*QList< Tomahawk::query_ptr >
|
||||
DatabaseCollection::tracks()
|
||||
{
|
||||
if ( !isLoaded() )
|
||||
{
|
||||
loadTracks();
|
||||
}
|
||||
|
||||
return Collection::tracks();
|
||||
}*/
|
||||
|
||||
|
||||
void DatabaseCollection::autoPlaylistCreated( const source_ptr& source, const QVariantList& data )
|
||||
void
|
||||
DatabaseCollection::autoPlaylistCreated( const source_ptr& source, const QVariantList& data )
|
||||
{
|
||||
dynplaylist_ptr p( new DynamicPlaylist( source, //src
|
||||
data[0].toString(), //current rev
|
||||
@@ -172,7 +147,8 @@ void DatabaseCollection::autoPlaylistCreated( const source_ptr& source, const QV
|
||||
}
|
||||
|
||||
|
||||
void DatabaseCollection::stationCreated( const source_ptr& source, const QVariantList& data )
|
||||
void
|
||||
DatabaseCollection::stationCreated( const source_ptr& source, const QVariantList& data )
|
||||
{
|
||||
dynplaylist_ptr p( new DynamicPlaylist( source, //src
|
||||
data[0].toString(), //current rev
|
||||
|
@@ -80,12 +80,14 @@ DatabaseCommand::setSource( const Tomahawk::source_ptr& s )
|
||||
m_source = s;
|
||||
}
|
||||
|
||||
|
||||
const Tomahawk::source_ptr&
|
||||
DatabaseCommand::source() const
|
||||
{
|
||||
return m_source;
|
||||
}
|
||||
|
||||
|
||||
DatabaseCommand*
|
||||
DatabaseCommand::factory( const QVariant& op, const source_ptr& source )
|
||||
{
|
||||
@@ -139,7 +141,8 @@ DatabaseCommand::factory( const QVariant& op, const source_ptr& source )
|
||||
cmd->setSource( source );
|
||||
QJson::QObjectHelper::qvariant2qobject( op.toMap(), cmd );
|
||||
return cmd;
|
||||
} else if( name == "createdynamicplaylist" )
|
||||
}
|
||||
else if( name == "createdynamicplaylist" )
|
||||
{
|
||||
DatabaseCommand_CreateDynamicPlaylist * cmd = new DatabaseCommand_CreateDynamicPlaylist;
|
||||
cmd->setSource( source );
|
||||
@@ -183,7 +186,7 @@ DatabaseCommand::factory( const QVariant& op, const source_ptr& source )
|
||||
return cmd;
|
||||
}
|
||||
|
||||
qDebug() << "ERROR in" << Q_FUNC_INFO << name;
|
||||
qDebug() << "Unknown database command" << name;
|
||||
// Q_ASSERT( false );
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -70,6 +70,7 @@ public:
|
||||
const Tomahawk::source_ptr& source() const;
|
||||
|
||||
virtual bool loggable() const { return false; }
|
||||
virtual bool groupable() const { return false; }
|
||||
virtual bool singletonCmd() const { return false; }
|
||||
virtual bool localOnly() const { return false; }
|
||||
|
||||
|
@@ -24,7 +24,6 @@
|
||||
#include "album.h"
|
||||
#include "collection.h"
|
||||
#include "database/database.h"
|
||||
#include "databasecommand_collectionstats.h"
|
||||
#include "databaseimpl.h"
|
||||
#include "network/dbsyncconnection.h"
|
||||
#include "network/servent.h"
|
||||
@@ -73,15 +72,7 @@ DatabaseCommand_AddFiles::postCommitHook()
|
||||
emit notify( m_ids );
|
||||
|
||||
if ( source()->isLocal() )
|
||||
{
|
||||
Servent::instance()->triggerDBSync();
|
||||
|
||||
// Re-calculate local db stats
|
||||
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( SourceList::instance()->getLocal() );
|
||||
connect( cmd, SIGNAL( done( QVariantMap ) ),
|
||||
SourceList::instance()->getLocal().data(), SLOT( setStats( QVariantMap ) ), Qt::QueuedConnection );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -35,20 +35,21 @@ DatabaseCommand_addSource::DatabaseCommand_addSource( const QString& username, c
|
||||
void
|
||||
DatabaseCommand_addSource::exec( DatabaseImpl* dbi )
|
||||
{
|
||||
Q_ASSERT( !m_fname.isEmpty() );
|
||||
|
||||
TomahawkSqlQuery query = dbi->newquery();
|
||||
query.prepare( "SELECT id, friendlyname FROM source WHERE name = ?" );
|
||||
query.prepare( "SELECT id FROM source WHERE name = ?" );
|
||||
query.addBindValue( m_username );
|
||||
query.exec();
|
||||
|
||||
if ( query.next() )
|
||||
{
|
||||
unsigned int id = query.value( 0 ).toInt();
|
||||
QString fname = query.value( 1 ).toString();
|
||||
query.prepare( "UPDATE source SET isonline = 'true', friendlyname = ? WHERE id = ?" );
|
||||
query.addBindValue( m_fname );
|
||||
query.addBindValue( id );
|
||||
query.exec();
|
||||
emit done( id, fname );
|
||||
emit done( id, m_fname );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -25,7 +25,6 @@
|
||||
#include "collection.h"
|
||||
#include "source.h"
|
||||
#include "database/database.h"
|
||||
#include "databasecommand_collectionstats.h"
|
||||
#include "databaseimpl.h"
|
||||
#include "network/servent.h"
|
||||
#include "utils/logger.h"
|
||||
@@ -54,7 +53,7 @@ DatabaseCommand_DeleteFiles::postCommitHook()
|
||||
ids << id.toUInt();
|
||||
emit notify( ids );
|
||||
|
||||
if( source()->isLocal() )
|
||||
if ( source()->isLocal() )
|
||||
Servent::instance()->triggerDBSync();
|
||||
}
|
||||
|
||||
|
@@ -64,6 +64,7 @@ public:
|
||||
virtual void exec( DatabaseImpl* );
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual bool localOnly() const { return false; }
|
||||
virtual bool groupable() const { return true; }
|
||||
virtual void postCommitHook();
|
||||
|
||||
QVariantList ids() const { return m_ids; }
|
||||
|
@@ -94,23 +94,13 @@ DatabaseCommand_LoadDynamicPlaylistEntries::exec( DatabaseImpl* dbi )
|
||||
}
|
||||
else
|
||||
{
|
||||
// No controls, lets load the info we need directly from the playlist table
|
||||
TomahawkSqlQuery info = dbi->newquery();
|
||||
info.prepare( QString( "SELECT dynamic_playlist.pltype, dynamic_playlist.plmode FROM playlist, dynamic_playlist WHERE playlist.guid = \"%1\" AND playlist.guid = dynamic_playlist.guid" ).arg( playlist_guid ) );
|
||||
if( !info.exec() ) {
|
||||
qWarning() << "Failed to load dynplaylist info..";
|
||||
return;
|
||||
} else if( !info.first() ) {
|
||||
qWarning() << "Noo results for queryL:" << info.lastQuery();
|
||||
return;
|
||||
}
|
||||
type = info.value( 0 ).toString();
|
||||
mode = static_cast<GeneratorMode>( info.value( 1 ).toInt() );
|
||||
// No controls or plguid is null, but that's okay. We'll get a setdynrevision command with a proper revision some point later
|
||||
return;
|
||||
}
|
||||
|
||||
if( mode == OnDemand )
|
||||
{
|
||||
Q_ASSERT( m_entrymap.isEmpty() ); // ondemand should have no entry
|
||||
// Q_ASSERT( m_entrymap.isEmpty() ); // ondemand should have no entry
|
||||
|
||||
emit done( revisionGuid(), m_islatest, type, controls, true );
|
||||
}
|
||||
|
@@ -36,8 +36,8 @@ using namespace Tomahawk;
|
||||
void
|
||||
DatabaseCommand_LogPlayback::postCommitHook()
|
||||
{
|
||||
connect( this, SIGNAL( trackPlaying( Tomahawk::query_ptr ) ),
|
||||
source().data(), SLOT( onPlaybackStarted( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
|
||||
connect( this, SIGNAL( trackPlaying( Tomahawk::query_ptr, unsigned int ) ),
|
||||
source().data(), SLOT( onPlaybackStarted( Tomahawk::query_ptr, unsigned int ) ), Qt::QueuedConnection );
|
||||
connect( this, SIGNAL( trackPlayed( Tomahawk::query_ptr ) ),
|
||||
source().data(), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
|
||||
|
||||
@@ -60,7 +60,7 @@ DatabaseCommand_LogPlayback::postCommitHook()
|
||||
// if the play time is more than 10 minutes in the past, ignore
|
||||
else if ( m_action == Started && QDateTime::fromTime_t( playtime() ).secsTo( QDateTime::currentDateTime() ) < STARTED_THRESHOLD )
|
||||
{
|
||||
emit trackPlaying( q );
|
||||
emit trackPlaying( q, m_trackDuration );
|
||||
}
|
||||
|
||||
if ( source()->isLocal() )
|
||||
|
@@ -37,6 +37,7 @@ Q_PROPERTY( QString artist READ artist WRITE setArtist )
|
||||
Q_PROPERTY( QString track READ track WRITE setTrack )
|
||||
Q_PROPERTY( unsigned int playtime READ playtime WRITE setPlaytime )
|
||||
Q_PROPERTY( unsigned int secsPlayed READ secsPlayed WRITE setSecsPlayed )
|
||||
Q_PROPERTY( unsigned int trackDuration READ trackDuration WRITE setTrackDuration )
|
||||
Q_PROPERTY( int action READ action WRITE setAction )
|
||||
|
||||
public:
|
||||
@@ -47,13 +48,14 @@ public:
|
||||
};
|
||||
|
||||
explicit DatabaseCommand_LogPlayback( QObject* parent = 0 )
|
||||
: DatabaseCommandLoggable( parent )
|
||||
: DatabaseCommandLoggable( parent ), m_playtime( 0 ), m_secsPlayed( 0 ), m_trackDuration( 0 )
|
||||
{}
|
||||
|
||||
explicit DatabaseCommand_LogPlayback( const Tomahawk::result_ptr& result, Action action, unsigned int secsPlayed = 0, QObject* parent = 0 )
|
||||
: DatabaseCommandLoggable( parent ), m_result( result ), m_secsPlayed( secsPlayed ), m_action( action )
|
||||
{
|
||||
m_playtime = QDateTime::currentDateTimeUtc().toTime_t();
|
||||
m_trackDuration = result->duration();
|
||||
setSource( SourceList::instance()->getLocal() );
|
||||
|
||||
setArtist( result->artist()->name() );
|
||||
@@ -68,6 +70,7 @@ public:
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual bool singletonCmd() const { return ( m_action == Started ); }
|
||||
virtual bool localOnly() const;
|
||||
virtual bool groupable() const { return true; }
|
||||
|
||||
QString artist() const { return m_artist; }
|
||||
void setArtist( const QString& s ) { m_artist = s; }
|
||||
@@ -81,11 +84,14 @@ public:
|
||||
unsigned int secsPlayed() const { return m_secsPlayed; }
|
||||
void setSecsPlayed( unsigned int i ) { m_secsPlayed = i; }
|
||||
|
||||
unsigned int trackDuration() const { return m_trackDuration; }
|
||||
void setTrackDuration( unsigned int trackDuration ) { m_trackDuration = trackDuration; }
|
||||
|
||||
int action() const { return m_action; }
|
||||
void setAction( int a ) { m_action = (Action)a; }
|
||||
|
||||
signals:
|
||||
void trackPlaying( const Tomahawk::query_ptr& query );
|
||||
void trackPlaying( const Tomahawk::query_ptr& query, unsigned int duration );
|
||||
void trackPlayed( const Tomahawk::query_ptr& query );
|
||||
|
||||
private:
|
||||
@@ -95,6 +101,7 @@ private:
|
||||
QString m_track;
|
||||
unsigned int m_playtime;
|
||||
unsigned int m_secsPlayed;
|
||||
unsigned int m_trackDuration;
|
||||
Action m_action;
|
||||
};
|
||||
|
||||
|
@@ -157,7 +157,6 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
result->setRID( uuid() );
|
||||
result->setAlbumPos( files_query.value( 14 ).toUInt() );
|
||||
result->setTrackId( files_query.value( 9 ).toUInt() );
|
||||
result->setYear( files_query.value( 17 ).toUInt() );
|
||||
|
||||
TomahawkSqlQuery attrQuery = lib->newquery();
|
||||
QVariantMap attr;
|
||||
|
@@ -249,8 +249,8 @@ DatabaseCommand_SetDynamicPlaylistRevision::exec( DatabaseImpl* lib )
|
||||
|
||||
controlsQuery.exec();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( m_applied )
|
||||
{
|
||||
tLog() << "updating dynamic playlist, optimistic locking okay";
|
||||
|
@@ -60,6 +60,7 @@ public:
|
||||
virtual void exec( DatabaseImpl* lib );
|
||||
virtual void postCommitHook();
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual bool groupable() const { return true; }
|
||||
|
||||
void setControlsV( const QVariantList& vlist )
|
||||
{
|
||||
|
@@ -104,6 +104,7 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << "Playlist:" << m_playlistguid << m_currentRevision << source()->friendlyName() << source()->id();
|
||||
throw "No such playlist, WTF?";
|
||||
return;
|
||||
}
|
||||
@@ -212,6 +213,6 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
|
||||
else if ( !m_oldrev.isEmpty() )
|
||||
{
|
||||
tDebug() << "Not updating current revision, optimistic locking fail";
|
||||
Q_ASSERT( false );
|
||||
// Q_ASSERT( false );
|
||||
}
|
||||
}
|
||||
|
@@ -58,6 +58,7 @@ public:
|
||||
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual bool localOnly() const { return m_localOnly; }
|
||||
virtual bool groupable() const { return true; }
|
||||
|
||||
void setAddedentriesV( const QVariantList& vlist )
|
||||
{
|
||||
|
@@ -170,6 +170,7 @@ public:
|
||||
void setTimestamp( const int ts ) { m_timestamp = ts; }
|
||||
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual bool groupable() const { return true; }
|
||||
|
||||
private:
|
||||
Tomahawk::result_ptr m_result;
|
||||
|
@@ -26,6 +26,7 @@
|
||||
DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex()
|
||||
: DatabaseCommand()
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Updating index.";
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@@ -72,16 +72,21 @@ DatabaseWorker::run()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseWorker::enqueue( const QList< QSharedPointer<DatabaseCommand> >& cmds )
|
||||
{
|
||||
QMutexLocker lock( &m_mut );
|
||||
m_outstanding += cmds.count();
|
||||
m_commands << cmds;
|
||||
|
||||
if ( m_outstanding == cmds.count() )
|
||||
QTimer::singleShot( 0, this, SLOT( doWork() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseWorker::enqueue( const QSharedPointer<DatabaseCommand>& cmd )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << "Reinvoking in correct thread.";
|
||||
QMetaObject::invokeMethod( this, "enqueue", Qt::QueuedConnection, Q_ARG( QSharedPointer<DatabaseCommand>, cmd ) );
|
||||
return;
|
||||
}
|
||||
|
||||
QMutexLocker lock( &m_mut );
|
||||
m_outstanding++;
|
||||
m_commands << cmd;
|
||||
@@ -107,6 +112,7 @@ DatabaseWorker::doWork()
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
QList< QSharedPointer<DatabaseCommand> > cmdGroup;
|
||||
QSharedPointer<DatabaseCommand> cmd;
|
||||
{
|
||||
QMutexLocker lock( &m_mut );
|
||||
@@ -119,47 +125,66 @@ DatabaseWorker::doWork()
|
||||
Q_ASSERT( transok );
|
||||
Q_UNUSED( transok );
|
||||
}
|
||||
|
||||
unsigned int completed = 0;
|
||||
try
|
||||
{
|
||||
bool finished = false;
|
||||
{
|
||||
// tDebug() << "Executing cmd:" << cmd->guid();
|
||||
cmd->_exec( m_dbimpl ); // runs actual SQL stuff
|
||||
|
||||
if ( cmd->loggable() )
|
||||
while ( !finished )
|
||||
{
|
||||
// We only save our own ops to the oplog, since incoming ops from peers
|
||||
// are applied immediately.
|
||||
//
|
||||
// Crazy idea: if peers had keypairs and could sign ops/msgs, in theory it
|
||||
// would be safe to sync ops for friend A from friend B's cache, if he saved them,
|
||||
// which would mean you could get updates even if a peer was offline.
|
||||
if ( cmd->source()->isLocal() && !cmd->localOnly() )
|
||||
completed++;
|
||||
cmd->_exec( m_dbimpl ); // runs actual SQL stuff
|
||||
|
||||
if ( cmd->loggable() )
|
||||
{
|
||||
// save to op-log
|
||||
DatabaseCommandLoggable* command = (DatabaseCommandLoggable*)cmd.data();
|
||||
logOp( command );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make a note of the last guid we applied for this source
|
||||
// so we can always request just the newer ops in future.
|
||||
// We only save our own ops to the oplog, since incoming ops from peers
|
||||
// are applied immediately.
|
||||
//
|
||||
if ( !cmd->singletonCmd() )
|
||||
// Crazy idea: if peers had keypairs and could sign ops/msgs, in theory it
|
||||
// would be safe to sync ops for friend A from friend B's cache, if he saved them,
|
||||
// which would mean you could get updates even if a peer was offline.
|
||||
if ( cmd->source()->isLocal() && !cmd->localOnly() )
|
||||
{
|
||||
// qDebug() << "Setting lastop for source" << cmd->source()->id() << "to" << cmd->guid();
|
||||
|
||||
TomahawkSqlQuery query = m_dbimpl->newquery();
|
||||
query.prepare( "UPDATE source SET lastop = ? WHERE id = ?" );
|
||||
query.addBindValue( cmd->guid() );
|
||||
query.addBindValue( cmd->source()->id() );
|
||||
|
||||
if ( !query.exec() )
|
||||
// save to op-log
|
||||
DatabaseCommandLoggable* command = (DatabaseCommandLoggable*)cmd.data();
|
||||
logOp( command );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make a note of the last guid we applied for this source
|
||||
// so we can always request just the newer ops in future.
|
||||
//
|
||||
if ( !cmd->singletonCmd() )
|
||||
{
|
||||
qDebug() << "Failed to set lastop";
|
||||
throw "Failed to set lastop";
|
||||
TomahawkSqlQuery query = m_dbimpl->newquery();
|
||||
query.prepare( "UPDATE source SET lastop = ? WHERE id = ?" );
|
||||
query.addBindValue( cmd->guid() );
|
||||
query.addBindValue( cmd->source()->id() );
|
||||
|
||||
if ( !query.exec() )
|
||||
{
|
||||
throw "Failed to set lastop";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmdGroup << cmd;
|
||||
if ( cmd->groupable() && !m_commands.isEmpty() )
|
||||
{
|
||||
QMutexLocker lock( &m_mut );
|
||||
if ( m_commands.first()->groupable() )
|
||||
{
|
||||
cmd = m_commands.takeFirst();
|
||||
}
|
||||
else
|
||||
{
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
finished = true;
|
||||
}
|
||||
|
||||
if ( cmd->doesMutates() )
|
||||
@@ -167,8 +192,7 @@ DatabaseWorker::doWork()
|
||||
qDebug() << "Committing" << cmd->commandname() << cmd->guid();
|
||||
if ( !m_dbimpl->database().commit() )
|
||||
{
|
||||
|
||||
qDebug() << "*FAILED TO COMMIT TRANSACTION*";
|
||||
tDebug() << "FAILED TO COMMIT TRANSACTION*";
|
||||
throw "commit failed";
|
||||
}
|
||||
}
|
||||
@@ -178,7 +202,8 @@ DatabaseWorker::doWork()
|
||||
tDebug() << "DBCmd Duration:" << duration << "ms, now running postcommit for" << cmd->commandname();
|
||||
#endif
|
||||
|
||||
cmd->postCommit();
|
||||
foreach ( QSharedPointer<DatabaseCommand> c, cmdGroup )
|
||||
c->postCommit();
|
||||
|
||||
#ifdef DEBUG_TIMING
|
||||
tDebug() << "Post commit finished in" << timer.elapsed() - duration << "ms for" << cmd->commandname();
|
||||
@@ -195,7 +220,7 @@ DatabaseWorker::doWork()
|
||||
<< m_dbimpl->database().lastError().driverText()
|
||||
<< endl;
|
||||
|
||||
if( cmd->doesMutates() )
|
||||
if ( cmd->doesMutates() )
|
||||
m_dbimpl->database().rollback();
|
||||
|
||||
Q_ASSERT( false );
|
||||
@@ -203,17 +228,19 @@ DatabaseWorker::doWork()
|
||||
catch(...)
|
||||
{
|
||||
qDebug() << "Uncaught exception processing dbcmd";
|
||||
if( cmd->doesMutates() )
|
||||
if ( cmd->doesMutates() )
|
||||
m_dbimpl->database().rollback();
|
||||
|
||||
Q_ASSERT( false );
|
||||
throw;
|
||||
}
|
||||
|
||||
cmd->emitFinished();
|
||||
foreach ( QSharedPointer<DatabaseCommand> c, cmdGroup )
|
||||
c->emitFinished();
|
||||
|
||||
QMutexLocker lock( &m_mut );
|
||||
if ( --m_outstanding > 0 )
|
||||
m_outstanding -= completed;
|
||||
if ( m_outstanding > 0 )
|
||||
QTimer::singleShot( 0, this, SLOT( doWork() ) );
|
||||
}
|
||||
|
||||
|
@@ -47,6 +47,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void enqueue( const QSharedPointer<DatabaseCommand>& );
|
||||
void enqueue( const QList< QSharedPointer<DatabaseCommand> >& );
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
@@ -266,6 +266,7 @@ CREATE TABLE IF NOT EXISTS playback_log (
|
||||
playtime INTEGER NOT NULL, -- when playback finished (timestamp)
|
||||
secs_played INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX playback_log_source ON playback_log(source);
|
||||
CREATE INDEX playback_log_track ON playback_log(track);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
This file was automatically generated from schema.sql on Thu Sep 29 17:28:17 EDT 2011.
|
||||
This file was automatically generated from schema.sql on Wed Nov 16 22:47:16 EST 2011.
|
||||
*/
|
||||
|
||||
static const char * tomahawk_schema_sql =
|
||||
|
@@ -34,10 +34,12 @@
|
||||
#include "utils/xspfloader.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
bool DropJob::s_canParseSpotifyPlaylists = false;
|
||||
|
||||
|
||||
DropJob::DropJob( QObject *parent )
|
||||
: QObject( parent )
|
||||
, m_queryCount( 0 )
|
||||
@@ -50,11 +52,13 @@ DropJob::DropJob( QObject *parent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DropJob::~DropJob()
|
||||
{
|
||||
qDebug() << "destryong DropJob";
|
||||
}
|
||||
|
||||
|
||||
/// QMIMEDATA HANDLING
|
||||
|
||||
QStringList
|
||||
@@ -68,15 +72,18 @@ DropJob::mimeTypes()
|
||||
<< "application/tomahawk.metadata.artist"
|
||||
<< "application/tomahawk.metadata.album"
|
||||
<< "application/tomahawk.mixed"
|
||||
<< "text/plain";
|
||||
<< "text/plain"
|
||||
<< "text/uri-list";
|
||||
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType, DropJob::DropAction acceptedAction )
|
||||
{
|
||||
Q_UNUSED( acceptedAction );
|
||||
|
||||
if ( data->hasFormat( "application/tomahawk.query.list" )
|
||||
|| data->hasFormat( "application/tomahawk.plentry.list" )
|
||||
|| data->hasFormat( "application/tomahawk.result.list" )
|
||||
@@ -90,7 +97,8 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
|
||||
// check plain text url types
|
||||
if ( !data->hasFormat( "text/plain" ) )
|
||||
return false;
|
||||
if ( !data->hasFormat( "text/uri-list" ) )
|
||||
return false;
|
||||
|
||||
const QString url = data->data( "text/plain" );
|
||||
|
||||
@@ -99,6 +107,9 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
if( url.contains( "xspf" ) )
|
||||
return true;
|
||||
|
||||
if( data->data( "text/uri-list" ).contains( "xspf" ) )
|
||||
return true;
|
||||
|
||||
// Not the most elegant
|
||||
if ( url.contains( "spotify" ) && url.contains( "playlist" ) && s_canParseSpotifyPlaylists )
|
||||
return true;
|
||||
@@ -137,21 +148,22 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
return true;
|
||||
}
|
||||
|
||||
// We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them,
|
||||
// so we do an extra level of lookup
|
||||
if ( url.contains( "bit.ly" ) || url.contains( "j.mp" ) || url.contains( "t.co" ) || url.contains( "rd.io" ) )
|
||||
// We whitelist certain url-shorteners since they do some link checking. Often playable (e.g. spotify) links hide behind them,
|
||||
// so we do an extra level of lookup
|
||||
if ( ShortenedLinkParser::handlesUrl( url ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DropJob::isDropType( DropJob::DropType desired, const QMimeData* data )
|
||||
{
|
||||
const QString url = data->data( "text/plain" );
|
||||
if ( desired == Playlist )
|
||||
{
|
||||
if( url.contains( "xspf" ) )
|
||||
if( url.contains( "xspf" ) || data->data( "text/uri-list").contains( "xspf" ) )
|
||||
return true;
|
||||
|
||||
// Not the most elegant
|
||||
@@ -161,11 +173,7 @@ DropJob::isDropType( DropJob::DropType desired, const QMimeData* data )
|
||||
if ( url.contains( "rdio.com" ) && url.contains( "people" ) && url.contains( "playlist" ) )
|
||||
return true;
|
||||
|
||||
// we don't know about these.. gotta say yes for now
|
||||
if ( url.contains( "bit.ly" ) ||
|
||||
url.contains( "j.mp" ) ||
|
||||
url.contains( "t.co" ) ||
|
||||
url.contains( "rd.io" ) )
|
||||
if ( ShortenedLinkParser::handlesUrl( url ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -179,6 +187,7 @@ DropJob::setGetWholeArtists( bool getWholeArtists )
|
||||
m_getWholeArtists = getWholeArtists;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::setGetWholeAlbums( bool getWholeAlbums )
|
||||
{
|
||||
@@ -208,6 +217,7 @@ DropJob::tracksFromMimeData( const QMimeData* data, bool allowDuplicates, bool o
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::parseMimeData( const QMimeData *data )
|
||||
{
|
||||
@@ -222,15 +232,21 @@ DropJob::parseMimeData( const QMimeData *data )
|
||||
results = tracksFromArtistMetaData( data );
|
||||
else if ( data->hasFormat( "application/tomahawk.mixed" ) )
|
||||
tracksFromMixedData( data );
|
||||
else if ( data->hasFormat( "text/plain" ) )
|
||||
else if ( data->hasFormat( "text/plain" ) && !data->data( "text/plain" ).isEmpty() )
|
||||
{
|
||||
const QString plainData = QString::fromUtf8( data->data( "text/plain" ) );
|
||||
handleAllUrls( plainData );
|
||||
|
||||
}else if ( data->hasFormat( "text/uri-list" ) )
|
||||
{
|
||||
const QString plainData = QString::fromUtf8( data->data( "text/uri-list" ).trimmed() );
|
||||
handleAllUrls( plainData );
|
||||
}
|
||||
|
||||
m_resultList.append( results );
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromQueryList( const QMimeData* data )
|
||||
{
|
||||
@@ -270,6 +286,7 @@ DropJob::tracksFromQueryList( const QMimeData* data )
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromResultList( const QMimeData* data )
|
||||
{
|
||||
@@ -311,6 +328,7 @@ DropJob::tracksFromResultList( const QMimeData* data )
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromAlbumMetaData( const QMimeData *data )
|
||||
{
|
||||
@@ -335,6 +353,7 @@ DropJob::tracksFromAlbumMetaData( const QMimeData *data )
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromArtistMetaData( const QMimeData *data )
|
||||
{
|
||||
@@ -359,6 +378,7 @@ DropJob::tracksFromArtistMetaData( const QMimeData *data )
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromMixedData( const QMimeData *data )
|
||||
{
|
||||
@@ -407,32 +427,50 @@ DropJob::tracksFromMixedData( const QMimeData *data )
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::handleXspfs( const QString& fileUrls )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "Got xspf playlist!!" << fileUrls;
|
||||
|
||||
QStringList urls = fileUrls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
|
||||
bool error = false;
|
||||
QStringList urls = fileUrls.split( QRegExp( "\n" ), QString::SkipEmptyParts );
|
||||
|
||||
if ( dropAction() == Default )
|
||||
setDropAction( Create );
|
||||
|
||||
foreach ( const QString& url, urls )
|
||||
{
|
||||
XSPFLoader* l = 0;
|
||||
QFile xspfFile( QUrl::fromUserInput( url ).toLocalFile() );
|
||||
|
||||
if ( xspfFile.exists() )
|
||||
{
|
||||
XSPFLoader* l = new XSPFLoader( true, this );
|
||||
l = new XSPFLoader( dropAction() == Create, this );
|
||||
tDebug( LOGINFO ) << "Loading local xspf " << xspfFile.fileName();
|
||||
l->load( xspfFile );
|
||||
}
|
||||
else if ( QUrl( url ).isValid() )
|
||||
{
|
||||
l = new XSPFLoader( dropAction() == Create, this );
|
||||
tDebug( LOGINFO ) << "Loading remote xspf " << url;
|
||||
l->load( QUrl( url ) );
|
||||
}
|
||||
else
|
||||
tLog( LOGINFO ) << "Error Loading local xspf " << xspfFile.fileName();
|
||||
}
|
||||
{
|
||||
error = true;
|
||||
tLog() << "Failed to load or parse dropped XSPF";
|
||||
}
|
||||
|
||||
if ( dropAction() == Append && !error && l )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Trying to append xspf";
|
||||
connect( l, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) );
|
||||
m_queryCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::handleSpotifyUrls( const QString& urlsRaw )
|
||||
{
|
||||
@@ -458,6 +496,7 @@ DropJob::handleSpotifyUrls( const QString& urlsRaw )
|
||||
m_queryCount++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::handleRdioUrls( const QString& urlsRaw )
|
||||
{
|
||||
@@ -470,10 +509,10 @@ DropJob::handleRdioUrls( const QString& urlsRaw )
|
||||
RdioParser* rdio = new RdioParser( this );
|
||||
connect( rdio, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) );
|
||||
|
||||
m_queryCount++;
|
||||
rdio->setCreatePlaylist( dropAction() == Create );
|
||||
rdio->parse( urls );
|
||||
|
||||
m_queryCount++;
|
||||
}
|
||||
|
||||
|
||||
@@ -524,10 +563,8 @@ DropJob::handleTrackUrls( const QString& urls )
|
||||
m_queryCount++;
|
||||
|
||||
rdio->parse( tracks );
|
||||
} else if ( urls.contains( "bit.ly" ) ||
|
||||
urls.contains( "j.mp" ) ||
|
||||
urls.contains( "t.co" ) ||
|
||||
urls.contains( "rd.io" ) )
|
||||
}
|
||||
else if ( ShortenedLinkParser::handlesUrl( urls ) )
|
||||
{
|
||||
QStringList tracks = urls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
|
||||
|
||||
@@ -538,6 +575,7 @@ DropJob::handleTrackUrls( const QString& urls )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::expandedUrls( QStringList urls )
|
||||
{
|
||||
@@ -545,6 +583,7 @@ DropJob::expandedUrls( QStringList urls )
|
||||
handleAllUrls( urls.join( "\n" ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::onTracksAdded( const QList<Tomahawk::query_ptr>& tracksList )
|
||||
{
|
||||
@@ -569,6 +608,7 @@ DropJob::onTracksAdded( const QList<Tomahawk::query_ptr>& tracksList )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::removeDuplicates()
|
||||
{
|
||||
@@ -587,6 +627,7 @@ DropJob::removeDuplicates()
|
||||
m_resultList = list;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::removeRemoteSources()
|
||||
{
|
||||
@@ -605,6 +646,7 @@ DropJob::removeRemoteSources()
|
||||
m_resultList = list;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
|
||||
{
|
||||
@@ -634,6 +676,7 @@ DropJob::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::getArtist( const QString &artist )
|
||||
{
|
||||
@@ -649,6 +692,7 @@ DropJob::getArtist( const QString &artist )
|
||||
return artistPtr->tracks();
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::getAlbum(const QString &artist, const QString &album)
|
||||
{
|
||||
@@ -672,6 +716,7 @@ DropJob::getAlbum(const QString &artist, const QString &album)
|
||||
return albumPtr->tracks();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::getTopTen( const QString &artist )
|
||||
{
|
||||
|
@@ -108,6 +108,7 @@ public:
|
||||
|
||||
static bool canParseSpotifyPlaylists() { return s_canParseSpotifyPlaylists; }
|
||||
static void setCanParseSpotifyPlaylists( bool parseable ) { s_canParseSpotifyPlaylists = parseable; }
|
||||
|
||||
signals:
|
||||
/// QMimeData parsing results
|
||||
void tracks( const QList< Tomahawk::query_ptr >& tracks );
|
||||
|
@@ -297,12 +297,12 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url )
|
||||
tDebug() << "No xspf to load...";
|
||||
return false;
|
||||
}
|
||||
QUrl xspf = QUrl( url.queryItemValue( "xspf" ) );
|
||||
QUrl xspf = QUrl::fromUserInput( url.queryItemValue( "xspf" ) );
|
||||
QString title = url.hasQueryItem( "title" ) ? url.queryItemValue( "title" ) : QString();
|
||||
XSPFLoader* l= new XSPFLoader( true, this );
|
||||
l->setOverrideTitle( title );
|
||||
l->load( xspf );
|
||||
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) );
|
||||
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), this, SLOT( playlistCreatedToShow( Tomahawk::playlist_ptr) ) );
|
||||
|
||||
} else if( parts [ 0 ] == "new" ) {
|
||||
if( !url.hasQueryItem( "title" ) ) {
|
||||
@@ -323,6 +323,22 @@ GlobalActionManager::handlePlaylistCommand( const QUrl& url )
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GlobalActionManager::playlistCreatedToShow( const playlist_ptr& pl )
|
||||
{
|
||||
connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistReadyToShow() ) );
|
||||
pl->setProperty( "sharedptr", QVariant::fromValue<Tomahawk::playlist_ptr>( pl ) );
|
||||
}
|
||||
|
||||
void GlobalActionManager::playlistReadyToShow()
|
||||
{
|
||||
playlist_ptr pl = sender()->property( "sharedptr" ).value<Tomahawk::playlist_ptr>();
|
||||
if ( !pl.isNull() )
|
||||
ViewManager::instance()->show( pl );
|
||||
|
||||
disconnect( sender(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistReadyToShow() ) );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GlobalActionManager::handleCollectionCommand( const QUrl& url )
|
||||
@@ -408,6 +424,7 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
|
||||
|
||||
QString title, artist, album, urlStr;
|
||||
foreach( pair, queryItems ) {
|
||||
pair.second = pair.second.replace( "+", " " ); // QUrl::queryItems doesn't decode + to a space :(
|
||||
if( pair.first == "title" )
|
||||
title = pair.second;
|
||||
else if( pair.first == "artist" )
|
||||
@@ -431,7 +448,7 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
|
||||
foreach( pair, queryItems ) {
|
||||
if( pair.first != "url" )
|
||||
continue;
|
||||
QUrl track = QUrl::fromUserInput( pair.second );
|
||||
QUrl track = QUrl::fromUserInput( pair.second );
|
||||
//FIXME: isLocalFile is Qt 4.8
|
||||
if( track.toString().startsWith( "file://" ) ) { // it's local, so we see if it's in the DB and load it if so
|
||||
// TODO
|
||||
|
@@ -81,6 +81,8 @@ private slots:
|
||||
void playOrQueueNow( const Tomahawk::query_ptr& );
|
||||
void playNow( const Tomahawk::query_ptr& );
|
||||
|
||||
void playlistCreatedToShow( const Tomahawk::playlist_ptr& pl );
|
||||
void playlistReadyToShow();
|
||||
private:
|
||||
explicit GlobalActionManager( QObject* parent = 0 );
|
||||
void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q );
|
||||
|
@@ -39,9 +39,6 @@
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -76,9 +73,6 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
@@ -92,9 +86,6 @@
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
@@ -143,9 +134,6 @@
|
||||
<height>62</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
|
@@ -19,12 +19,10 @@
|
||||
|
||||
#include "chartsplugin.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkReply>
|
||||
#include <QDomElement>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtNetwork/QNetworkConfiguration>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include "album.h"
|
||||
#include "chartsplugin_data_p.h"
|
||||
@@ -34,7 +32,7 @@
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#define CHART_URL "http://charts.tomahawk-player.org:10080/"
|
||||
#define CHART_URL "http://charts.tomahawk-player.org/"
|
||||
//#define CHART_URL "http://localhost:8080/"
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
@@ -50,27 +48,12 @@ ChartsPlugin::ChartsPlugin()
|
||||
m_chartResources << "billboard" << "itunes" << "rdio" << "wearehunted" << "ex.fm";
|
||||
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
|
||||
|
||||
/// Then get each chart from resource
|
||||
/// We want to prepopulate the breadcrumb to fetch them before they are asked for
|
||||
if ( !m_chartResources.isEmpty() && m_allChartsMap.isEmpty() )
|
||||
{
|
||||
tDebug() << "ChartsPlugin: InfoChart fetching possible resources";
|
||||
foreach ( QVariant resource, m_chartResources )
|
||||
{
|
||||
QUrl url = QUrl( QString( CHART_URL "source/%1" ).arg(resource.toString() ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
tDebug() << "fetching:" << url;
|
||||
connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
|
||||
|
||||
m_chartsFetchJobs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ChartsPlugin::~ChartsPlugin()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,27 +68,27 @@ ChartsPlugin::dataError( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
void
|
||||
ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << requestData.caller;
|
||||
qDebug() << Q_FUNC_INFO << requestData.customData;
|
||||
//qDebug() << Q_FUNC_INFO << requestData.caller;
|
||||
//qDebug() << Q_FUNC_INFO << requestData.customData;
|
||||
|
||||
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
bool foundSource = false;
|
||||
|
||||
switch ( requestData.type )
|
||||
{
|
||||
|
||||
case InfoChart:
|
||||
/// We need something to check if the request is actually ment to go to this plugin
|
||||
if ( !hash.contains( "chart_source" ) )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required param!";
|
||||
dataError( requestData );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( QVariant resource, m_chartResources )
|
||||
foreach( QString resource, m_chartResources )
|
||||
{
|
||||
if( resource.toString() == hash["chart_source"] )
|
||||
if( resource == hash["chart_source"] )
|
||||
{
|
||||
foundSource = true;
|
||||
}
|
||||
@@ -130,15 +113,6 @@ ChartsPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ChartsPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
|
||||
{
|
||||
Q_UNUSED( caller )
|
||||
Q_UNUSED( type)
|
||||
Q_UNUSED( input )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
@@ -155,6 +129,7 @@ ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
/// Each request needs to contain both a id and source
|
||||
if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!";
|
||||
dataError( requestData );
|
||||
return;
|
||||
|
||||
@@ -163,7 +138,7 @@ ChartsPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
criteria["chart_id"] = hash["chart_id"];
|
||||
criteria["chart_source"] = hash["chart_source"];
|
||||
|
||||
emit getCachedInfo( criteria, 0, requestData );
|
||||
emit getCachedInfo( criteria, 86400000, requestData );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -171,13 +146,14 @@ ChartsPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requ
|
||||
{
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Could not convert requestData to InfoStringHash!";
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
|
||||
emit getCachedInfo( criteria, 0, requestData );
|
||||
criteria[ "InfoChartCapabilities" ] = "chartsplugin";
|
||||
emit getCachedInfo( criteria, 604800000, requestData );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -187,9 +163,11 @@ ChartsPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
|
||||
{
|
||||
case InfoChart:
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart not in cache! Fetching...";
|
||||
|
||||
/// Fetch the chart, we need source and id
|
||||
QUrl url = QUrl( QString( CHART_URL "source/%1/chart/%2" ).arg( criteria["chart_source"] ).arg( criteria["chart_id"] ) );
|
||||
qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Getting chart url" << url;
|
||||
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
|
||||
@@ -201,9 +179,33 @@ ChartsPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
|
||||
|
||||
case InfoChartCapabilities:
|
||||
{
|
||||
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching...";
|
||||
// we never need to re-fetch
|
||||
if ( !m_allChartsMap.isEmpty() )
|
||||
return;
|
||||
|
||||
/// Then get each chart from resource
|
||||
|
||||
if ( !m_chartResources.isEmpty() && m_allChartsMap.isEmpty() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart fetching possible resources";
|
||||
foreach ( QString resource, m_chartResources )
|
||||
{
|
||||
QUrl url = QUrl( QString( CHART_URL "source/%1" ).arg( resource ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
reply->setProperty( "chart_resource", resource);
|
||||
|
||||
tDebug() << "fetching:" << url;
|
||||
connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
|
||||
|
||||
m_chartsFetchJobs++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_chartsFetchJobs > 0 )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
|
||||
m_cachedRequests.append( requestData );
|
||||
return;
|
||||
}
|
||||
@@ -226,9 +228,10 @@ void
|
||||
ChartsPlugin::chartTypes()
|
||||
{
|
||||
/// Get possible chart type for specificChartsPlugin: InfoChart types returned chart source
|
||||
tDebug() << "Got chart type result";
|
||||
tDebug( LOGVERBOSE ) << "Got chart type result";
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
|
||||
|
||||
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QJson::Parser p;
|
||||
@@ -262,7 +265,8 @@ ChartsPlugin::chartTypes()
|
||||
QHash< QString, QVariantMap > extraType;
|
||||
foreach( const QVariant& chartObj, chartObjs.values() )
|
||||
{
|
||||
if( !chartObj.toMap().isEmpty() ){
|
||||
if( !chartObj.toMap().isEmpty() )
|
||||
{
|
||||
const QVariantMap chart = chartObj.toMap();
|
||||
const QString id = chart.value( "id" ).toString();
|
||||
const QString geo = chart.value( "geo" ).toString();
|
||||
@@ -271,7 +275,8 @@ ChartsPlugin::chartTypes()
|
||||
const bool isDefault = ( chart.contains( "default" ) && chart[ "default" ].toInt() == 1 );
|
||||
|
||||
QString extra;
|
||||
if( !geo.isEmpty() ){
|
||||
if( !geo.isEmpty() )
|
||||
{
|
||||
|
||||
if ( !m_cachedCountries.contains( geo ) )
|
||||
{
|
||||
@@ -289,10 +294,10 @@ ChartsPlugin::chartTypes()
|
||||
m_cachedCountries[ geo ] = extra;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra = m_cachedCountries[ geo ];
|
||||
}
|
||||
}else extra = chart.value( "extra" ).toString();
|
||||
}
|
||||
else
|
||||
extra = chart.value( "extra" ).toString();
|
||||
|
||||
if ( name.isEmpty() ) // not a specific chart, an all chart
|
||||
name = tr( "Top Overall" );
|
||||
@@ -304,10 +309,10 @@ ChartsPlugin::chartTypes()
|
||||
if ( isDefault )
|
||||
c[ "default" ] = "true";
|
||||
|
||||
QList<InfoStringHash> extraTypeData = extraType[ extra ][ type ].value< QList< InfoStringHash > >();
|
||||
QList< Tomahawk::InfoSystem::InfoStringHash > extraTypeData = extraType[ extra ][ type ].value< QList< Tomahawk::InfoSystem::InfoStringHash > >();
|
||||
extraTypeData.append( c );
|
||||
extraType[ extra ][ type ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( extraTypeData );
|
||||
|
||||
extraType[ extra ].insert( type, QVariant::fromValue< QList< InfoStringHash > >( extraTypeData ) );
|
||||
if ( isDefault )
|
||||
{
|
||||
defaultChain.clear();
|
||||
@@ -319,7 +324,7 @@ ChartsPlugin::chartTypes()
|
||||
foreach( const QString& c, extraType.keys() )
|
||||
{
|
||||
charts[ c ] = extraType[ c ];
|
||||
// qDebug() << "extraType has types:" << c;
|
||||
// tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "extraType has types:" << c;
|
||||
}
|
||||
if( source == "itunes" ){
|
||||
chartName = "iTunes";
|
||||
@@ -330,7 +335,8 @@ ChartsPlugin::chartTypes()
|
||||
}
|
||||
}
|
||||
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
// We'll just build:
|
||||
// [Source] - Album - Chart Type
|
||||
@@ -380,11 +386,11 @@ ChartsPlugin::chartTypes()
|
||||
}
|
||||
}
|
||||
if( !artistCharts.isEmpty() )
|
||||
charts.insert( tr( "Artists" ), QVariant::fromValue< QList< InfoStringHash > >( artistCharts ) );
|
||||
charts.insert( tr( "Artists" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( artistCharts ) );
|
||||
if( !albumCharts.isEmpty() )
|
||||
charts.insert( tr( "Albums" ), QVariant::fromValue< QList< InfoStringHash > >( albumCharts ) );
|
||||
charts.insert( tr( "Albums" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( albumCharts ) );
|
||||
if( !trackCharts.isEmpty() )
|
||||
charts.insert( tr( "Tracks" ), QVariant::fromValue< QList< InfoStringHash > >( trackCharts ) );
|
||||
charts.insert( tr( "Tracks" ), QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( trackCharts ) );
|
||||
|
||||
/// @note For displaying purposes, upper the first letter
|
||||
/// @note Remeber to lower it when fetching this!
|
||||
@@ -394,7 +400,7 @@ ChartsPlugin::chartTypes()
|
||||
}
|
||||
|
||||
/// Add the possible charts and its types to breadcrumb
|
||||
// qDebug() << "ADDING CHART TYPE TO CHARTS:" << chartName;
|
||||
// tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "ADDING CHART TYPE TO CHARTS:" << chartName;
|
||||
QVariantMap defaultMap = m_allChartsMap.value( "defaults" ).value< QVariantMap >();
|
||||
defaultMap[ source ] = defaultChain;
|
||||
m_allChartsMap[ "defaults" ] = defaultMap;
|
||||
@@ -413,6 +419,10 @@ ChartsPlugin::chartTypes()
|
||||
foreach ( InfoRequestData request, m_cachedRequests )
|
||||
{
|
||||
emit info( request, m_allChartsMap );
|
||||
// update cache
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
criteria[ "InfoChartCapabilities" ] = "chartsplugin";
|
||||
emit updateCache( criteria, 604800000, request.type, m_allChartsMap );
|
||||
}
|
||||
m_cachedRequests.clear();
|
||||
}
|
||||
@@ -441,8 +451,8 @@ ChartsPlugin::chartReturned()
|
||||
|
||||
/// SO we have a result, parse it!
|
||||
QVariantList chartResponse = res.value( "list" ).toList();
|
||||
QList< InfoStringHash > top_tracks;
|
||||
QList< InfoStringHash > top_albums;
|
||||
QList< Tomahawk::InfoSystem::InfoStringHash > top_tracks;
|
||||
QList< Tomahawk::InfoSystem::InfoStringHash > top_albums;
|
||||
QStringList top_artists;
|
||||
|
||||
/// Deside what type, we need to handle it differently
|
||||
@@ -478,16 +488,16 @@ ChartsPlugin::chartReturned()
|
||||
|
||||
if ( album.isEmpty() && artist.isEmpty() ) // don't have enough...
|
||||
{
|
||||
tLog() << "Didn't get an artist and album name from chart, not enough to build a query on. Aborting" << title << album << artist;
|
||||
tDebug( LOGVERBOSE ) << "Didn't get an artist and album name from chart, not enough to build a query on. Aborting" << title << album << artist;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << album << artist;
|
||||
InfoStringHash pair;
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash pair;
|
||||
pair["artist"] = artist;
|
||||
pair["album"] = album;
|
||||
top_albums << pair;
|
||||
top_albums.append( pair );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -497,28 +507,28 @@ ChartsPlugin::chartReturned()
|
||||
|
||||
if ( title.isEmpty() && artist.isEmpty() ) // don't have enough...
|
||||
{
|
||||
tLog() << "Didn't get an artist and track name from charts, not enough to build a query on. Aborting" << title << artist << album;
|
||||
tDebug( LOGVERBOSE ) << "Didn't get an artist and track name from charts, not enough to build a query on. Aborting" << title << artist << album;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
InfoStringHash pair;
|
||||
Tomahawk::InfoSystem::InfoStringHash pair;
|
||||
pair["artist"] = artist;
|
||||
pair["track"] = title;
|
||||
top_tracks << pair;
|
||||
top_tracks.append( pair );
|
||||
|
||||
}
|
||||
}else if( chartType() == Artist )
|
||||
{
|
||||
if ( artist.isEmpty() ) // don't have enough...
|
||||
{
|
||||
tLog() << "Didn't get an artist from charts, not enough to build a query on. Aborting" << artist;
|
||||
tDebug( LOGVERBOSE ) << "Didn't get an artist from charts, not enough to build a query on. Aborting" << artist;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
top_artists << artist;
|
||||
top_artists.append( artist );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -528,31 +538,35 @@ ChartsPlugin::chartReturned()
|
||||
if( chartType() == Artist )
|
||||
{
|
||||
tDebug() << "ChartsPlugin:" << "\tgot " << top_artists.size() << " artists";
|
||||
returnedData["artists"] = QVariant::fromValue( top_artists );
|
||||
returnedData["type"] = "artists";
|
||||
returnedData[ "artists" ] = QVariant::fromValue< QStringList >( top_artists );
|
||||
returnedData[ "type" ] = "artists";
|
||||
}
|
||||
|
||||
if( chartType() == Track )
|
||||
{
|
||||
tDebug() << "ChartsPlugin:" << "\tgot " << top_tracks.size() << " tracks";
|
||||
returnedData["tracks"] = QVariant::fromValue( top_tracks );
|
||||
returnedData["type"] = "tracks";
|
||||
returnedData[ "tracks" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( top_tracks );
|
||||
returnedData[ "type" ] = "tracks";
|
||||
}
|
||||
|
||||
if( chartType() == Album )
|
||||
{
|
||||
tDebug() << "ChartsPlugin:" << "\tgot " << top_albums.size() << " albums";
|
||||
returnedData["albums"] = QVariant::fromValue( top_albums );
|
||||
returnedData["type"] = "albums";
|
||||
returnedData[ "albums" ] = QVariant::fromValue< QList< Tomahawk::InfoSystem::InfoStringHash > >( top_albums );
|
||||
returnedData[ "type" ] = "albums";
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
|
||||
|
||||
|
||||
emit info( requestData, returnedData );
|
||||
// TODO update cache
|
||||
// update cache
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
criteria[ "chart_id" ] = origData[ "chart_id" ];
|
||||
criteria[ "chart_source" ] = origData[ "chart_source" ];
|
||||
emit updateCache( criteria, 86400000, requestData.type, returnedData );
|
||||
}
|
||||
else
|
||||
qDebug() << "Network error in fetching chart:" << reply->url().toString();
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Network error in fetching chart:" << reply->url().toString();
|
||||
|
||||
}
|
||||
|
@@ -21,8 +21,8 @@
|
||||
|
||||
#include "infosystem/infosystem.h"
|
||||
#include "infosystem/infosystemworker.h"
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
@@ -47,8 +47,9 @@ public:
|
||||
Artist = 0x04
|
||||
|
||||
};
|
||||
void setChartType( ChartType type ) { m_chartType = type; }
|
||||
ChartType chartType() const { return m_chartType; }
|
||||
|
||||
void setChartType( ChartType type ) { m_chartType = type; }
|
||||
ChartType chartType() const { return m_chartType; }
|
||||
|
||||
public slots:
|
||||
void chartReturned();
|
||||
@@ -58,15 +59,20 @@ protected slots:
|
||||
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
|
||||
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
|
||||
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data )
|
||||
{
|
||||
Q_UNUSED( caller )
|
||||
Q_UNUSED( type )
|
||||
Q_UNUSED( data )
|
||||
}
|
||||
|
||||
private:
|
||||
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
void fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
void dataError( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
|
||||
QVariantList m_chartResources;
|
||||
QList<InfoStringHash> m_charts;
|
||||
QStringList m_chartResources;
|
||||
QList< InfoStringHash > m_charts;
|
||||
ChartType m_chartType;
|
||||
|
||||
QVariantMap m_allChartsMap;
|
||||
|
@@ -23,11 +23,9 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkReply>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "album.h"
|
||||
#include "typedefs.h"
|
||||
#include "audio/audioengine.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
@@ -140,16 +138,6 @@ hypemPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hypemPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
|
||||
{
|
||||
Q_UNUSED( caller )
|
||||
Q_UNUSED( type)
|
||||
Q_UNUSED( input )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hypemPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
@@ -173,8 +161,9 @@ hypemPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
/// Set the criterias for current chart
|
||||
criteria["chart_id"] = hash["chart_id"];
|
||||
criteria["chart_source"] = hash["chart_source"];
|
||||
|
||||
emit getCachedInfo( criteria, 0, requestData );
|
||||
/// @todo
|
||||
/// set cache time based on wether requested type is 3day, lastweek or recent.
|
||||
emit getCachedInfo( criteria, 86400000, requestData );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -198,7 +187,7 @@ hypemPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSys
|
||||
case InfoChart:
|
||||
{
|
||||
/// Fetch the chart, we need source and id
|
||||
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart not in cache! Fetching...";
|
||||
QUrl url = QUrl( QString( HYPEM_URL "%1/%2" ).arg( criteria["chart_id"].toLower() ).arg(HYPEM_END_URL) );
|
||||
qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
|
||||
|
||||
@@ -212,6 +201,7 @@ hypemPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSys
|
||||
|
||||
case InfoChartCapabilities:
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching...";
|
||||
if ( m_chartsFetchJobs > 0 )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
|
||||
@@ -390,7 +380,14 @@ hypemPlugin::chartReturned()
|
||||
|
||||
|
||||
emit info( requestData, returnedData );
|
||||
// TODO update cache
|
||||
// update cache
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
criteria[ "chart_id" ] = origData[ "chart_id" ];
|
||||
criteria[ "chart_source" ] = origData[ "chart_source" ];
|
||||
/// @todo
|
||||
/// set cache time based on wether requested type is 3day, lastweek or recent.
|
||||
emit updateCache( criteria, 86400000, requestData.type, returnedData );
|
||||
}
|
||||
else
|
||||
qDebug() << "Network error in fetching chart:" << reply->url().toString();
|
||||
|
@@ -57,8 +57,13 @@ public slots:
|
||||
protected slots:
|
||||
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
|
||||
{
|
||||
Q_UNUSED( caller )
|
||||
Q_UNUSED( type)
|
||||
Q_UNUSED( input )
|
||||
}
|
||||
|
||||
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
|
||||
|
||||
private:
|
||||
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkReply>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "album.h"
|
||||
#include "typedefs.h"
|
||||
@@ -33,7 +32,7 @@
|
||||
#include "utils/logger.h"
|
||||
#include "chartsplugin_data_p.h"
|
||||
|
||||
#define SPOTIFY_API_URL "http://spotikea.tomahawk-player.org:10380/"
|
||||
#define SPOTIFY_API_URL "http://spotikea.tomahawk-player.org/"
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
|
||||
@@ -47,19 +46,6 @@ SpotifyPlugin::SpotifyPlugin()
|
||||
|
||||
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
|
||||
|
||||
// we never need to re-fetch
|
||||
if ( !m_allChartsMap.isEmpty() )
|
||||
return;
|
||||
|
||||
/// We need to fetch possible types before they are asked for
|
||||
tDebug() << "SpotifyPlugin: InfoChart fetching possible resources";
|
||||
|
||||
QUrl url = QUrl( QString( SPOTIFY_API_URL "toplist/charts" ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
tDebug() << Q_FUNC_INFO << "fetching:" << url;
|
||||
connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
|
||||
m_chartsFetchJobs++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -107,14 +93,6 @@ SpotifyPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
|
||||
{
|
||||
Q_UNUSED( caller )
|
||||
Q_UNUSED( type)
|
||||
Q_UNUSED( input )
|
||||
}
|
||||
|
||||
void
|
||||
SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
@@ -123,17 +101,22 @@ SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
if ( !hash.contains( "chart_id" ) )
|
||||
/// Each request needs to contain both a id and source
|
||||
if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!";
|
||||
dataError( requestData );
|
||||
return;
|
||||
} else {
|
||||
criteria["chart_id"] = hash["chart_id"];
|
||||
}
|
||||
|
||||
emit getCachedInfo( criteria, 604800000 /* Expire chart cache in 1 week */, requestData );
|
||||
}
|
||||
/// Set the criterias for current chart
|
||||
criteria["chart_id"] = hash["chart_id"];
|
||||
criteria["chart_source"] = hash["chart_source"];
|
||||
|
||||
emit getCachedInfo( criteria, 86400000 /* Expire chart cache in 1 day */, requestData );
|
||||
}
|
||||
void
|
||||
SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
@@ -145,7 +128,8 @@ SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData req
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
emit getCachedInfo( criteria, 0, requestData );
|
||||
criteria[ "InfoChartCapabilities" ] = "spotifyplugin";
|
||||
emit getCachedInfo( criteria, 604800000, requestData );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -157,6 +141,7 @@ SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, To
|
||||
case InfoChart:
|
||||
{
|
||||
/// Fetch the chart, we need source and id
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChart not in cache! Fetching...";
|
||||
QUrl url = QUrl( QString( SPOTIFY_API_URL "toplist/%1/" ).arg( criteria["chart_id"] ) );
|
||||
qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
|
||||
|
||||
@@ -169,6 +154,21 @@ SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, To
|
||||
}
|
||||
case InfoChartCapabilities:
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "InfoChartCapabilities not in cache! Fetching...";
|
||||
|
||||
// we never need to re-fetch
|
||||
if ( !m_allChartsMap.isEmpty() )
|
||||
return;
|
||||
|
||||
/// We need to fetch possible types before they are asked for
|
||||
tDebug() << "SpotifyPlugin: InfoChart fetching possible resources";
|
||||
|
||||
QUrl url = QUrl( QString( SPOTIFY_API_URL "toplist/charts" ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
tDebug() << Q_FUNC_INFO << "fetching:" << url;
|
||||
connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
|
||||
m_chartsFetchJobs++;
|
||||
|
||||
if ( m_chartsFetchJobs > 0 )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "InfoChartCapabilities still fetching!";
|
||||
@@ -275,6 +275,9 @@ SpotifyPlugin::chartTypes()
|
||||
foreach ( InfoRequestData request, m_cachedRequests )
|
||||
{
|
||||
emit info( request, m_allChartsMap );
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
criteria[ "InfoChartCapabilities" ] = "spotifyplugin";
|
||||
emit updateCache( criteria,604800000, request.type, m_allChartsMap );
|
||||
}
|
||||
m_cachedRequests.clear();
|
||||
}
|
||||
@@ -379,9 +382,14 @@ SpotifyPlugin::chartReturned()
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
|
||||
|
||||
|
||||
emit info( requestData, returnedData );
|
||||
|
||||
// update cache
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
Tomahawk::InfoSystem::InfoStringHash origData = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
criteria[ "chart_id" ] = origData[ "chart_id" ];
|
||||
criteria[ "chart_source" ] = origData[ "chart_source" ];
|
||||
emit updateCache( criteria, 86400000, requestData.type, returnedData );
|
||||
}
|
||||
else
|
||||
qDebug() << "Network error in fetching chart:" << reply->url().toString();
|
||||
|
@@ -57,7 +57,12 @@ public slots:
|
||||
protected slots:
|
||||
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data );
|
||||
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
|
||||
{
|
||||
Q_UNUSED( caller )
|
||||
Q_UNUSED( type)
|
||||
Q_UNUSED( input )
|
||||
}
|
||||
|
||||
private:
|
||||
void fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
|
@@ -51,6 +51,7 @@ InfoSystem::instance()
|
||||
|
||||
InfoSystem::InfoSystem( QObject *parent )
|
||||
: QObject( parent )
|
||||
, m_inited( false )
|
||||
, m_infoSystemCacheThreadController( 0 )
|
||||
, m_infoSystemWorkerThreadController( 0 )
|
||||
{
|
||||
@@ -59,71 +60,94 @@ InfoSystem::InfoSystem( QObject *parent )
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_infoSystemCacheThreadController = new InfoSystemCacheThread( this );
|
||||
m_cache = QWeakPointer< InfoSystemCache >( new InfoSystemCache() );
|
||||
m_cache.data()->moveToThread( m_infoSystemCacheThreadController );
|
||||
m_infoSystemCacheThreadController->setCache( m_cache );
|
||||
m_infoSystemCacheThreadController->start( QThread::IdlePriority );
|
||||
|
||||
m_infoSystemWorkerThreadController = new InfoSystemWorkerThread( this );
|
||||
m_worker = QWeakPointer< InfoSystemWorker >( new InfoSystemWorker() );
|
||||
m_worker.data()->moveToThread( m_infoSystemWorkerThreadController );
|
||||
m_infoSystemWorkerThreadController->setWorker( m_worker );
|
||||
m_infoSystemWorkerThreadController->start();
|
||||
|
||||
QMetaObject::invokeMethod( m_worker.data(), "init", Qt::QueuedConnection, Q_ARG( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache >, m_cache ) );
|
||||
|
||||
connect( m_cache.data(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
m_worker.data(), SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
|
||||
|
||||
connect( m_worker.data(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
this, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
|
||||
|
||||
connect( m_worker.data(), SIGNAL( finished( QString ) ), this, SIGNAL( finished( QString ) ), Qt::UniqueConnection );
|
||||
|
||||
connect( m_worker.data(), SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ),
|
||||
this, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ), Qt::UniqueConnection );
|
||||
QTimer::singleShot( 0, this, SLOT( init() ) );
|
||||
}
|
||||
|
||||
|
||||
InfoSystem::~InfoSystem()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << " beginning";
|
||||
tDebug() << Q_FUNC_INFO << " beginning";
|
||||
|
||||
if ( !m_worker.isNull() )
|
||||
if ( m_infoSystemWorkerThreadController->worker() )
|
||||
{
|
||||
m_infoSystemWorkerThreadController->quit();
|
||||
m_infoSystemWorkerThreadController->wait( 60000 );
|
||||
|
||||
//delete m_worker.data();
|
||||
delete m_infoSystemWorkerThreadController;
|
||||
m_infoSystemWorkerThreadController = 0;
|
||||
}
|
||||
qDebug() << Q_FUNC_INFO << " done deleting worker";
|
||||
tDebug() << Q_FUNC_INFO << " done deleting worker";
|
||||
|
||||
if( m_infoSystemCacheThreadController )
|
||||
if( m_infoSystemCacheThreadController->cache() )
|
||||
{
|
||||
m_infoSystemCacheThreadController->quit();
|
||||
m_infoSystemCacheThreadController->wait( 60000 );
|
||||
|
||||
//delete m_cache.data();
|
||||
delete m_infoSystemCacheThreadController;
|
||||
m_infoSystemCacheThreadController = 0;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << " done deleting cache";
|
||||
tDebug() << Q_FUNC_INFO << " done deleting cache";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InfoSystem::init()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
if ( !m_infoSystemCacheThreadController->cache() || !m_infoSystemWorkerThreadController->worker() )
|
||||
{
|
||||
QTimer::singleShot( 0, this, SLOT( init() ) );
|
||||
return;
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoSystemCache* cache = m_infoSystemCacheThreadController->cache();
|
||||
Tomahawk::InfoSystem::InfoSystemWorker* worker = m_infoSystemWorkerThreadController->worker();
|
||||
|
||||
connect( cache, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
worker, SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
|
||||
|
||||
connect( worker, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
this, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
|
||||
|
||||
connect( worker, SIGNAL( finished( QString ) ), this, SIGNAL( finished( QString ) ), Qt::UniqueConnection );
|
||||
|
||||
connect( worker, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ),
|
||||
this, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ), Qt::UniqueConnection );
|
||||
|
||||
QMetaObject::invokeMethod( worker, "init", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoSystemCache*, cache ) );
|
||||
|
||||
m_inited = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InfoSystem::getInfo( const InfoRequestData &requestData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QMetaObject::invokeMethod( m_worker.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
|
||||
if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
|
||||
{
|
||||
init();
|
||||
return false;
|
||||
}
|
||||
QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
InfoSystem::getInfo( const QString &caller, const QVariantMap &customData, const InfoTypeMap &inputMap, const InfoTimeoutMap &timeoutMap, bool allSources )
|
||||
{
|
||||
if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
|
||||
{
|
||||
init();
|
||||
return false;
|
||||
}
|
||||
InfoRequestData requestData;
|
||||
requestData.caller = caller;
|
||||
requestData.customData = customData;
|
||||
@@ -133,82 +157,102 @@ InfoSystem::getInfo( const QString &caller, const QVariantMap &customData, const
|
||||
requestData.type = type;
|
||||
requestData.input = inputMap[ type ];
|
||||
requestData.timeoutMillis = timeoutMap.contains( type ) ? timeoutMap[ type ] : 10000;
|
||||
QMetaObject::invokeMethod( m_worker.data(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
|
||||
QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
InfoSystem::pushInfo( const QString &caller, const InfoType type, const QVariant& input )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QMetaObject::invokeMethod( m_worker.data(), "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ) );
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
|
||||
{
|
||||
init();
|
||||
return false;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
InfoSystem::pushInfo( const QString &caller, const InfoTypeMap &input )
|
||||
{
|
||||
if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
|
||||
{
|
||||
init();
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_FOREACH( InfoType type, input.keys() )
|
||||
QMetaObject::invokeMethod( m_worker.data(), "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input[ type ] ) );
|
||||
QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input[ type ] ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
InfoSystemCacheThread::InfoSystemCacheThread( QObject *parent )
|
||||
: QThread( parent )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
|
||||
InfoSystemCacheThread::~InfoSystemCacheThread()
|
||||
{
|
||||
delete m_cache.data();
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InfoSystemCacheThread::InfoSystemCacheThread::run()
|
||||
{
|
||||
m_cache = QWeakPointer< InfoSystemCache >( new InfoSystemCache() );
|
||||
exec();
|
||||
if ( !m_cache.isNull() )
|
||||
delete m_cache.data();
|
||||
}
|
||||
|
||||
QWeakPointer< InfoSystemCache >
|
||||
|
||||
InfoSystemCache*
|
||||
InfoSystemCacheThread::cache() const
|
||||
{
|
||||
return m_cache;
|
||||
if ( m_cache.isNull() )
|
||||
return 0;
|
||||
return m_cache.data();
|
||||
}
|
||||
|
||||
void
|
||||
InfoSystemCacheThread::setCache( QWeakPointer< InfoSystemCache > cache )
|
||||
{
|
||||
m_cache = cache;
|
||||
}
|
||||
|
||||
InfoSystemWorkerThread::InfoSystemWorkerThread( QObject *parent )
|
||||
: QThread( parent )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
InfoSystemWorkerThread::~InfoSystemWorkerThread()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void
|
||||
InfoSystemWorkerThread::InfoSystemWorkerThread::run()
|
||||
{
|
||||
m_worker = QWeakPointer< InfoSystemWorker >( new InfoSystemWorker() );
|
||||
exec();
|
||||
if( m_worker )
|
||||
if( !m_worker.isNull() )
|
||||
delete m_worker.data();
|
||||
}
|
||||
|
||||
QWeakPointer< InfoSystemWorker >
|
||||
InfoSystemWorker*
|
||||
InfoSystemWorkerThread::worker() const
|
||||
{
|
||||
return m_worker;
|
||||
}
|
||||
|
||||
void
|
||||
InfoSystemWorkerThread::setWorker( QWeakPointer< InfoSystemWorker > worker )
|
||||
{
|
||||
m_worker = worker;
|
||||
if ( m_worker.isNull() )
|
||||
return 0;
|
||||
return m_worker.data();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -205,8 +205,7 @@ public:
|
||||
virtual ~InfoSystemCacheThread();
|
||||
|
||||
void run();
|
||||
QWeakPointer< InfoSystemCache > cache() const;
|
||||
void setCache( QWeakPointer< InfoSystemCache > cache );
|
||||
InfoSystemCache* cache() const;
|
||||
|
||||
private:
|
||||
QWeakPointer< InfoSystemCache > m_cache;
|
||||
@@ -221,8 +220,7 @@ public:
|
||||
virtual ~InfoSystemWorkerThread();
|
||||
|
||||
void run();
|
||||
QWeakPointer< InfoSystemWorker > worker() const;
|
||||
void setWorker( QWeakPointer< InfoSystemWorker > worker );
|
||||
InfoSystemWorker* worker() const;
|
||||
|
||||
private:
|
||||
QWeakPointer< InfoSystemWorker > m_worker;
|
||||
@@ -238,20 +236,22 @@ public:
|
||||
InfoSystem( QObject *parent );
|
||||
~InfoSystem();
|
||||
|
||||
void getInfo( const InfoRequestData &requestData );
|
||||
bool getInfo( const InfoRequestData &requestData );
|
||||
//WARNING: if changing timeoutMillis above, also change in below function in .cpp file
|
||||
void getInfo( const QString &caller, const QVariantMap &customData, const InfoTypeMap &inputMap, const InfoTimeoutMap &timeoutMap = InfoTimeoutMap(), bool allSources = false );
|
||||
void pushInfo( const QString &caller, const InfoType type, const QVariant &input );
|
||||
void pushInfo( const QString &caller, const InfoTypeMap &input );
|
||||
bool getInfo( const QString &caller, const QVariantMap &customData, const InfoTypeMap &inputMap, const InfoTimeoutMap &timeoutMap = InfoTimeoutMap(), bool allSources = false );
|
||||
bool pushInfo( const QString &caller, const InfoType type, const QVariant &input );
|
||||
bool pushInfo( const QString &caller, const InfoTypeMap &input );
|
||||
|
||||
signals:
|
||||
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
void finished( QString target );
|
||||
void finished( QString target, Tomahawk::InfoSystem::InfoType type );
|
||||
|
||||
private slots:
|
||||
void init();
|
||||
|
||||
private:
|
||||
QWeakPointer< InfoSystemCache > m_cache;
|
||||
QWeakPointer< InfoSystemWorker > m_worker;
|
||||
bool m_inited;
|
||||
InfoSystemCacheThread* m_infoSystemCacheThreadController;
|
||||
InfoSystemWorkerThread* m_infoSystemWorkerThreadController;
|
||||
|
||||
@@ -287,7 +287,7 @@ inline uint qHash( Tomahawk::InfoSystem::InfoStringHash hash )
|
||||
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoRequestData );
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoStringHash );
|
||||
Q_DECLARE_METATYPE( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache > );
|
||||
Q_DECLARE_METATYPE( QList<Tomahawk::InfoSystem::InfoStringHash> );
|
||||
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoSystemCache* );
|
||||
Q_DECLARE_METATYPE( QList< Tomahawk::InfoSystem::InfoStringHash > );
|
||||
|
||||
#endif // TOMAHAWK_INFOSYSTEM_H
|
||||
|
@@ -39,6 +39,7 @@ InfoSystemCache::InfoSystemCache( QObject* parent )
|
||||
, m_cacheBaseDir( QDesktopServices::storageLocation( QDesktopServices::CacheLocation ) + "/InfoSystemCache/" )
|
||||
, m_cacheVersion( 2 )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
TomahawkSettings *s = TomahawkSettings::instance();
|
||||
if ( s->infoSystemCacheVersion() != m_cacheVersion )
|
||||
{
|
||||
@@ -64,6 +65,7 @@ InfoSystemCache::InfoSystemCache( QObject* parent )
|
||||
|
||||
InfoSystemCache::~InfoSystemCache()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -53,7 +53,7 @@ namespace InfoSystem
|
||||
InfoSystemWorker::InfoSystemWorker()
|
||||
: QObject()
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_checkTimeoutsTimer.setInterval( 1000 );
|
||||
m_checkTimeoutsTimer.setSingleShot( false );
|
||||
@@ -64,20 +64,20 @@ InfoSystemWorker::InfoSystemWorker()
|
||||
|
||||
InfoSystemWorker::~InfoSystemWorker()
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << " beginning";
|
||||
tDebug() << Q_FUNC_INFO << " beginning";
|
||||
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
|
||||
{
|
||||
if( plugin )
|
||||
delete plugin.data();
|
||||
}
|
||||
// qDebug() << Q_FUNC_INFO << " finished";
|
||||
tDebug() << Q_FUNC_INFO << " finished";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cache )
|
||||
InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << "and cache is" << cache.data();
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
InfoPluginPtr enptr( new EchoNestPlugin() );
|
||||
m_plugins.append( enptr );
|
||||
@@ -132,13 +132,13 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
|
||||
connect(
|
||||
plugin.data(),
|
||||
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
|
||||
cache.data(),
|
||||
cache,
|
||||
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) )
|
||||
);
|
||||
connect(
|
||||
plugin.data(),
|
||||
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
|
||||
cache.data(),
|
||||
cache,
|
||||
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
|
||||
);
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ signals:
|
||||
void finished( QString target, Tomahawk::InfoSystem::InfoType type );
|
||||
|
||||
public slots:
|
||||
void init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache > cache );
|
||||
void init( Tomahawk::InfoSystem::InfoSystemCache* cache );
|
||||
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input );
|
||||
|
||||
|
@@ -81,6 +81,7 @@ JobStatusModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
case Qt::DecorationRole:
|
||||
return item->icon();
|
||||
case Qt::ToolTipRole:
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
if ( m_collapseCount.contains( item->type() ) )
|
||||
@@ -114,7 +115,7 @@ JobStatusModel::itemFinished()
|
||||
JobStatusItem* item = qobject_cast< JobStatusItem* >( sender() );
|
||||
Q_ASSERT( item );
|
||||
|
||||
tDebug() << "Got item finished:" << item->type() << item->mainText() << item;
|
||||
// tDebug() << "Got item finished:" << item->type() << item->mainText() << item;
|
||||
if ( !m_items.contains( item ) && !m_collapseCount.contains( item->type() ) )
|
||||
return;
|
||||
|
||||
@@ -140,7 +141,7 @@ JobStatusModel::itemFinished()
|
||||
// qDebug() << "Replaced" << m_collapseCount[ item->type() ].first() << "with:" << m_collapseCount[ item->type() ][ 1 ] << m_items;
|
||||
}
|
||||
m_collapseCount[ item->type() ].removeAll( item );
|
||||
tDebug() << "New collapse count list:" << m_collapseCount[ item->type() ];
|
||||
// tDebug() << "New collapse count list:" << m_collapseCount[ item->type() ];
|
||||
if ( m_collapseCount[ item->type() ].isEmpty() )
|
||||
m_collapseCount.remove( item->type() );
|
||||
else
|
||||
|
@@ -18,8 +18,8 @@
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
#include <QTime>
|
||||
#include <QThread>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include "network/servent.h"
|
||||
#include "utils/logger.h"
|
||||
@@ -63,7 +63,7 @@ Connection::Connection( Servent* parent )
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
qDebug() << "DTOR connection (super)" << id() << thread() << m_sock.isNull();
|
||||
tDebug() << "DTOR connection (super)" << id() << thread() << m_sock.isNull();
|
||||
if( !m_sock.isNull() )
|
||||
{
|
||||
// qDebug() << "deleteLatering sock" << m_sock;
|
||||
@@ -82,7 +82,7 @@ Connection::handleIncomingQueueEmpty()
|
||||
// << "m_peer_disconnected" << m_peer_disconnected
|
||||
// << "bytes rx" << bytesReceived();
|
||||
|
||||
if( m_sock->bytesAvailable() == 0 && m_peer_disconnected )
|
||||
if( !m_sock.isNull() && m_sock->bytesAvailable() == 0 && m_peer_disconnected )
|
||||
{
|
||||
qDebug() << "No more data to read, peer disconnected. shutting down connection."
|
||||
<< "bytesavail" << m_sock->bytesAvailable()
|
||||
@@ -144,13 +144,13 @@ void
|
||||
Connection::actualShutdown()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << m_actually_shutting_down << id();
|
||||
if( m_actually_shutting_down )
|
||||
if ( m_actually_shutting_down )
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_actually_shutting_down = true;
|
||||
|
||||
if( !m_sock.isNull() && m_sock->isOpen() )
|
||||
if ( !m_sock.isNull() && m_sock->isOpen() )
|
||||
{
|
||||
m_sock->disconnectFromHost();
|
||||
}
|
||||
@@ -261,7 +261,7 @@ Connection::doSetup()
|
||||
void
|
||||
Connection::socketDisconnected()
|
||||
{
|
||||
qDebug() << "SOCKET DISCONNECTED" << this->name() << id()
|
||||
tDebug() << "SOCKET DISCONNECTED" << this->name() << id()
|
||||
<< "shutdown will happen after incoming queue empties."
|
||||
<< "bytesavail:" << m_sock->bytesAvailable()
|
||||
<< "bytesRecvd" << bytesReceived();
|
||||
@@ -276,14 +276,15 @@ Connection::socketDisconnected()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Connection::socketDisconnectedError(QAbstractSocket::SocketError e)
|
||||
Connection::socketDisconnectedError( QAbstractSocket::SocketError e )
|
||||
{
|
||||
qDebug() << "SOCKET ERROR CODE" << e << this->name() << "CALLING Connection::shutdown(false)";
|
||||
|
||||
if ( e == QAbstractSocket::RemoteHostClosedError )
|
||||
return;
|
||||
|
||||
qDebug() << "SOCKET ERROR CODE" << e << this->name() << "CALLING Connection::shutdown(false)";
|
||||
|
||||
m_peer_disconnected = true;
|
||||
|
||||
emit socketErrored(e);
|
||||
@@ -423,16 +424,16 @@ Connection::sendMsg_now( msg_ptr msg )
|
||||
{
|
||||
//qDebug() << Q_FUNC_INFO << thread() << QThread::currentThread();
|
||||
Q_ASSERT( QThread::currentThread() == thread() );
|
||||
Q_ASSERT( this->isRunning() );
|
||||
// Q_ASSERT( this->isRunning() );
|
||||
|
||||
if( m_sock.isNull() || !m_sock->isOpen() || !m_sock->isWritable() )
|
||||
if ( m_sock.isNull() || !m_sock->isOpen() || !m_sock->isWritable() )
|
||||
{
|
||||
qDebug() << "***** Socket problem, whilst in sendMsg(). Cleaning up. *****";
|
||||
shutdown( false );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! msg->write( m_sock.data() ) )
|
||||
if ( !msg->write( m_sock.data() ) )
|
||||
{
|
||||
//qDebug() << "Error writing to socket in sendMsg() *************";
|
||||
shutdown( false );
|
||||
|
@@ -19,17 +19,17 @@
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <QTcpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QVariant>
|
||||
#include <QVariantMap>
|
||||
#include <QString>
|
||||
#include <QDataStream>
|
||||
#include <QtEndian>
|
||||
#include <QTimer>
|
||||
#include <QTime>
|
||||
#include <QPointer>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QVariantMap>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QtEndian>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
@@ -87,6 +87,8 @@ public:
|
||||
void setMsgProcessorModeOut( quint32 m ) { m_msgprocessor_out.setMode( m ); }
|
||||
void setMsgProcessorModeIn( quint32 m ) { m_msgprocessor_in.setMode( m ); }
|
||||
|
||||
const QHostAddress peerIpAddress() const { return m_peerIpAddress; }
|
||||
|
||||
signals:
|
||||
void ready();
|
||||
void failed();
|
||||
@@ -128,6 +130,7 @@ protected:
|
||||
bool m_outbound, m_ready, m_onceonly;
|
||||
msg_ptr m_firstmsg;
|
||||
QString m_name;
|
||||
QHostAddress m_peerIpAddress;
|
||||
|
||||
private:
|
||||
void handleReadMsg();
|
||||
|
@@ -33,7 +33,7 @@
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
ControlConnection::ControlConnection( Servent* parent )
|
||||
ControlConnection::ControlConnection( Servent* parent, const QHostAddress &ha )
|
||||
: Connection( parent )
|
||||
, m_dbsyncconn( 0 )
|
||||
, m_registered( false )
|
||||
@@ -47,6 +47,38 @@ ControlConnection::ControlConnection( Servent* parent )
|
||||
|
||||
this->setMsgProcessorModeIn( MsgProcessor::UNCOMPRESS_ALL | MsgProcessor::PARSE_JSON );
|
||||
this->setMsgProcessorModeOut( MsgProcessor::COMPRESS_IF_LARGE );
|
||||
|
||||
m_peerIpAddress = ha;
|
||||
}
|
||||
|
||||
|
||||
ControlConnection::ControlConnection( Servent* parent, const QString &ha )
|
||||
: Connection( parent )
|
||||
, m_dbsyncconn( 0 )
|
||||
, m_registered( false )
|
||||
, m_pingtimer( 0 )
|
||||
{
|
||||
qDebug() << "CTOR controlconnection";
|
||||
setId("ControlConnection()");
|
||||
|
||||
// auto delete when connection closes:
|
||||
connect( this, SIGNAL( finished() ), SLOT( deleteLater() ) );
|
||||
|
||||
this->setMsgProcessorModeIn( MsgProcessor::UNCOMPRESS_ALL | MsgProcessor::PARSE_JSON );
|
||||
this->setMsgProcessorModeOut( MsgProcessor::COMPRESS_IF_LARGE );
|
||||
|
||||
if ( !ha.isEmpty() )
|
||||
{
|
||||
QHostAddress qha( ha );
|
||||
if ( !qha.isNull() )
|
||||
m_peerIpAddress = qha;
|
||||
else
|
||||
{
|
||||
QHostInfo qhi = QHostInfo::fromName( ha );
|
||||
if ( !qhi.addresses().isEmpty() )
|
||||
m_peerIpAddress = qhi.addresses().first();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +104,7 @@ ControlConnection::source() const
|
||||
Connection*
|
||||
ControlConnection::clone()
|
||||
{
|
||||
ControlConnection* clone = new ControlConnection( servent() );
|
||||
ControlConnection* clone = new ControlConnection( servent(), m_peerIpAddress.toString() );
|
||||
clone->setOnceOnly( onceOnly() );
|
||||
clone->setName( name() );
|
||||
return clone;
|
||||
@@ -102,6 +134,8 @@ ControlConnection::setup()
|
||||
else
|
||||
friendlyName = name();
|
||||
|
||||
tDebug() << "Detected name:" << name() << friendlyName << m_sock->peerAddress();
|
||||
|
||||
// setup source and remote collection for this peer
|
||||
m_source = SourceList::instance()->get( id(), friendlyName );
|
||||
m_source->setControlConnection( this );
|
||||
|
@@ -39,7 +39,8 @@ class DLLEXPORT ControlConnection : public Connection
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ControlConnection( Servent* parent = 0 );
|
||||
explicit ControlConnection( Servent* parent = 0, const QHostAddress &ha = QHostAddress() );
|
||||
explicit ControlConnection( Servent* parent = 0, const QString &ha = QString() );
|
||||
~ControlConnection();
|
||||
Connection* clone();
|
||||
|
||||
|
@@ -39,10 +39,6 @@
|
||||
#include "sourcelist.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
// close the dbsync connection after this much inactivity.
|
||||
// it's automatically reestablished as needed.
|
||||
#define IDLE_TIMEOUT 300000
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
@@ -52,11 +48,11 @@ DBSyncConnection::DBSyncConnection( Servent* s, const source_ptr& src )
|
||||
, m_state( UNKNOWN )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << src->id() << thread();
|
||||
|
||||
connect( this, SIGNAL( stateChanged( DBSyncConnection::State, DBSyncConnection::State, QString ) ),
|
||||
m_source.data(), SLOT( onStateChanged( DBSyncConnection::State, DBSyncConnection::State, QString ) ) );
|
||||
|
||||
m_timer.setInterval( IDLE_TIMEOUT );
|
||||
connect( &m_timer, SIGNAL( timeout() ), SLOT( idleTimeout() ) );
|
||||
connect( m_source.data(), SIGNAL( commandsFinished() ),
|
||||
this, SLOT( lastOpApplied() ) );
|
||||
|
||||
this->setMsgProcessorModeIn( MsgProcessor::PARSE_JSON | MsgProcessor::UNCOMPRESS_ALL );
|
||||
|
||||
@@ -67,19 +63,11 @@ DBSyncConnection::DBSyncConnection( Servent* s, const source_ptr& src )
|
||||
|
||||
DBSyncConnection::~DBSyncConnection()
|
||||
{
|
||||
qDebug() << "DTOR" << Q_FUNC_INFO;
|
||||
tDebug() << "DTOR" << Q_FUNC_INFO << m_source->id() << m_source->friendlyName();
|
||||
m_state = SHUTDOWN;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DBSyncConnection::idleTimeout()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
shutdown( true );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DBSyncConnection::changeState( State newstate )
|
||||
{
|
||||
@@ -96,7 +84,6 @@ DBSyncConnection::changeState( State newstate )
|
||||
void
|
||||
DBSyncConnection::setup()
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
setId( QString( "DBSyncConnection/%1" ).arg( socket()->peerAddress().toString() ) );
|
||||
check();
|
||||
}
|
||||
@@ -105,23 +92,19 @@ DBSyncConnection::setup()
|
||||
void
|
||||
DBSyncConnection::trigger()
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
|
||||
// if we're still setting up the connection, do nothing - we sync on first connect anyway:
|
||||
if ( !isRunning() )
|
||||
return;
|
||||
|
||||
QMetaObject::invokeMethod( this, "sendMsg", Qt::QueuedConnection,
|
||||
Q_ARG( msg_ptr,
|
||||
Msg::factory( "{\"method\":\"trigger\"}", Msg::JSON ) )
|
||||
);
|
||||
Q_ARG( msg_ptr, Msg::factory( "{\"method\":\"trigger\"}", Msg::JSON ) ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DBSyncConnection::check()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << m_source->id();
|
||||
qDebug() << Q_FUNC_INFO << this << m_source->id();
|
||||
if ( m_state != UNKNOWN && m_state != SYNCED )
|
||||
{
|
||||
qDebug() << "Syncing in progress already.";
|
||||
@@ -133,10 +116,7 @@ DBSyncConnection::check()
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT( m_cmds.isEmpty() );
|
||||
m_uscache.clear();
|
||||
m_us.clear();
|
||||
|
||||
changeState( CHECKING );
|
||||
|
||||
// load last-modified etc data for our collection and theirs from our DB:
|
||||
@@ -154,9 +134,6 @@ DBSyncConnection::check()
|
||||
{
|
||||
fetchOpsData( m_source->lastCmdGuid() );
|
||||
}
|
||||
|
||||
// restarts idle countdown
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +142,7 @@ DBSyncConnection::check()
|
||||
void
|
||||
DBSyncConnection::gotUs( const QVariantMap& m )
|
||||
{
|
||||
m_us = m;
|
||||
Q_UNUSED( m )
|
||||
if ( !m_uscache.empty() )
|
||||
sendOps();
|
||||
}
|
||||
@@ -231,19 +208,16 @@ DBSyncConnection::handleMsg( msg_ptr msg )
|
||||
if ( msg->is( Msg::DBOP ) )
|
||||
{
|
||||
DatabaseCommand* cmd = DatabaseCommand::factory( m, m_source );
|
||||
if ( !cmd )
|
||||
if ( cmd )
|
||||
{
|
||||
qDebug() << "UNKNOWN DBOP CMD";
|
||||
return;
|
||||
QSharedPointer<DatabaseCommand> cmdsp = QSharedPointer<DatabaseCommand>(cmd);
|
||||
m_source->addCommand( cmdsp );
|
||||
}
|
||||
|
||||
QSharedPointer<DatabaseCommand> cmdsp = QSharedPointer<DatabaseCommand>(cmd);
|
||||
m_cmds << cmdsp;
|
||||
|
||||
if ( !msg->is( Msg::FRAGMENT ) ) // last msg in this batch
|
||||
{
|
||||
changeState( SAVING ); // just DB work left to complete
|
||||
executeCommands();
|
||||
m_source->executeCommands();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -251,8 +225,7 @@ DBSyncConnection::handleMsg( msg_ptr msg )
|
||||
if ( m.value( "method" ).toString() == "fetchops" )
|
||||
{
|
||||
m_uscache = m;
|
||||
if ( !m_us.empty() )
|
||||
sendOps();
|
||||
sendOps();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -269,23 +242,11 @@ DBSyncConnection::handleMsg( msg_ptr msg )
|
||||
|
||||
|
||||
void
|
||||
DBSyncConnection::executeCommands()
|
||||
DBSyncConnection::lastOpApplied()
|
||||
{
|
||||
if ( !m_cmds.isEmpty() )
|
||||
{
|
||||
QSharedPointer<DatabaseCommand> cmd = m_cmds.takeFirst();
|
||||
if ( !cmd->singletonCmd() )
|
||||
m_source->setLastCmdGuid( cmd->guid() );
|
||||
|
||||
connect( cmd.data(), SIGNAL( finished() ), SLOT( executeCommands() ) );
|
||||
Database::instance()->enqueue( cmd );
|
||||
}
|
||||
else
|
||||
{
|
||||
changeState( SYNCED );
|
||||
// check again, until peer responds we have no new ops to process
|
||||
check();
|
||||
}
|
||||
changeState( SYNCED );
|
||||
// check again, until peer responds we have no new ops to process
|
||||
check();
|
||||
}
|
||||
|
||||
|
||||
@@ -298,8 +259,8 @@ DBSyncConnection::sendOps()
|
||||
source_ptr src = SourceList::instance()->getLocal();
|
||||
|
||||
DatabaseCommand_loadOps* cmd = new DatabaseCommand_loadOps( src, m_uscache.value( "lastop" ).toString() );
|
||||
connect( cmd, SIGNAL( done( QString, QString, QList< dbop_ptr > ) ),
|
||||
SLOT( sendOpsData( QString, QString, QList< dbop_ptr > ) ) );
|
||||
connect( cmd, SIGNAL( done( QString, QString, QList< dbop_ptr > ) ),
|
||||
SLOT( sendOpsData( QString, QString, QList< dbop_ptr > ) ) );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
@@ -314,6 +275,7 @@ DBSyncConnection::sendOpsData( QString sinceguid, QString lastguid, QList< dbop_
|
||||
m_lastSentOp = lastguid;
|
||||
if ( ops.length() == 0 )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << "Sending ok" << m_source->id() << m_source->friendlyName();
|
||||
sendMsg( Msg::factory( "ok", Msg::DBOP ) );
|
||||
return;
|
||||
}
|
||||
|
@@ -70,23 +70,20 @@ private slots:
|
||||
|
||||
void fetchOpsData( const QString& sinceguid );
|
||||
void sendOpsData( QString sinceguid, QString lastguid, QList< dbop_ptr > ops );
|
||||
void executeCommands();
|
||||
void lastOpApplied();
|
||||
|
||||
void check();
|
||||
void idleTimeout();
|
||||
|
||||
private:
|
||||
void synced();
|
||||
void changeState( State newstate );
|
||||
|
||||
Tomahawk::source_ptr m_source;
|
||||
QVariantMap m_us, m_uscache;
|
||||
QVariantMap m_uscache;
|
||||
|
||||
QList< QSharedPointer<DatabaseCommand> > m_cmds;
|
||||
QString m_lastSentOp;
|
||||
|
||||
State m_state;
|
||||
QTimer m_timer;
|
||||
};
|
||||
|
||||
#endif // DBSYNCCONNECTION_H
|
||||
|
@@ -161,7 +161,7 @@ Servent::createConnectionKey( const QString& name, const QString &nodeid, const
|
||||
Q_ASSERT( this->thread() == QThread::currentThread() );
|
||||
|
||||
QString _key = ( key.isEmpty() ? uuid() : key );
|
||||
ControlConnection* cc = new ControlConnection( this );
|
||||
ControlConnection* cc = new ControlConnection( this, name );
|
||||
cc->setName( name.isEmpty() ? QString( "KEY(%1)" ).arg( key ) : name );
|
||||
if ( !nodeid.isEmpty() )
|
||||
cc->setId( nodeid );
|
||||
@@ -260,6 +260,7 @@ Servent::unregisterControlConnection( ControlConnection* conn )
|
||||
if( c!=conn )
|
||||
n.append( c );
|
||||
|
||||
m_connectedNodes.removeAll( conn->id() );
|
||||
m_controlconnections = n;
|
||||
}
|
||||
|
||||
@@ -327,7 +328,6 @@ Servent::readyRead()
|
||||
|
||||
ControlConnection* cc = 0;
|
||||
bool ok;
|
||||
// int pport; //FIXME?
|
||||
QString key, conntype, nodeid, controlid;
|
||||
QVariantMap m = parser.parse( sock->_msg->payload(), &ok ).toMap();
|
||||
if( !ok )
|
||||
@@ -335,9 +335,9 @@ Servent::readyRead()
|
||||
tDebug() << "Invalid JSON on new connection, aborting";
|
||||
goto closeconnection;
|
||||
}
|
||||
|
||||
conntype = m.value( "conntype" ).toString();
|
||||
key = m.value( "key" ).toString();
|
||||
// pport = m.value( "port" ).toInt();
|
||||
nodeid = m.value( "nodeid" ).toString();
|
||||
controlid = m.value( "controlid" ).toString();
|
||||
|
||||
@@ -345,14 +345,25 @@ Servent::readyRead()
|
||||
|
||||
if( !nodeid.isEmpty() ) // only control connections send nodeid
|
||||
{
|
||||
bool dupe = false;
|
||||
if ( m_connectedNodes.contains( nodeid ) )
|
||||
dupe = true;
|
||||
|
||||
foreach( ControlConnection* con, m_controlconnections )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << "known connection:" << con->id() << con->source()->friendlyName();
|
||||
if( con->id() == nodeid )
|
||||
{
|
||||
tLog() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
|
||||
goto closeconnection;
|
||||
dupe = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( dupe )
|
||||
{
|
||||
tLog() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
|
||||
goto closeconnection;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( ControlConnection* con, m_controlconnections )
|
||||
@@ -368,14 +379,16 @@ Servent::readyRead()
|
||||
if( conntype == "accept-offer" || "push-offer" )
|
||||
{
|
||||
sock->_msg.clear();
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << key << nodeid << "socket peer address = " << sock->peerAddress() << "socket peer name = " << sock->peerName();
|
||||
Connection* conn = claimOffer( cc, nodeid, key, sock->peerAddress() );
|
||||
if( !conn )
|
||||
{
|
||||
tLog() << "claimOffer FAILED, key:" << key;
|
||||
tLog() << "claimOffer FAILED, key:" << key << nodeid;
|
||||
goto closeconnection;
|
||||
}
|
||||
tDebug( LOGVERBOSE ) << "claimOffer OK:" << key;
|
||||
tDebug( LOGVERBOSE ) << "claimOffer OK:" << key << nodeid;
|
||||
|
||||
m_connectedNodes << nodeid;
|
||||
if( !nodeid.isEmpty() )
|
||||
conn->setId( nodeid );
|
||||
|
||||
@@ -400,7 +413,7 @@ closeconnection:
|
||||
void
|
||||
Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn, const QString& key )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << "Servent::createParallelConnection, key:" << key << thread() << orig_conn;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << ", key:" << key << thread() << orig_conn;
|
||||
// if we can connect to them directly:
|
||||
if( orig_conn && orig_conn->outbound() )
|
||||
{
|
||||
@@ -433,7 +446,7 @@ Servent::socketConnected()
|
||||
{
|
||||
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
|
||||
|
||||
tDebug( LOGVERBOSE ) << "Servent::SocketConnected" << thread() << "socket:" << sock;
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << thread() << "socket: " << sock << ", hostaddr: " << sock->peerAddress() << ", hostname: " << sock->peerName();
|
||||
|
||||
Connection* conn = sock->_conn.data();
|
||||
handoverSocket( conn, sock );
|
||||
@@ -497,7 +510,7 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, const Q
|
||||
{
|
||||
Q_ASSERT( this->thread() == QThread::currentThread() );
|
||||
|
||||
ControlConnection* conn = new ControlConnection( this );
|
||||
ControlConnection* conn = new ControlConnection( this, ha );
|
||||
QVariantMap m;
|
||||
m["conntype"] = "accept-offer";
|
||||
m["key"] = key;
|
||||
@@ -549,7 +562,10 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, Connect
|
||||
connect( sock, SIGNAL( error( QAbstractSocket::SocketError ) ),
|
||||
SLOT( socketError( QAbstractSocket::SocketError ) ) );
|
||||
|
||||
sock->connectToHost( ha, port, QTcpSocket::ReadWrite );
|
||||
if ( !conn->peerIpAddress().isNull() )
|
||||
sock->connectToHost( conn->peerIpAddress(), port, QTcpSocket::ReadWrite );
|
||||
else
|
||||
sock->connectToHost( ha, port, QTcpSocket::ReadWrite );
|
||||
sock->moveToThread( thread() );
|
||||
}
|
||||
|
||||
@@ -616,7 +632,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
if( isIPWhitelisted( peer ) )
|
||||
{
|
||||
tDebug() << "Connection is from whitelisted IP range (LAN)";
|
||||
Connection* conn = new ControlConnection( this );
|
||||
Connection* conn = new ControlConnection( this, peer.toString() );
|
||||
conn->setName( peer.toString() );
|
||||
return conn;
|
||||
}
|
||||
@@ -662,7 +678,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
else if ( noauth )
|
||||
{
|
||||
Connection* conn;
|
||||
conn = new ControlConnection( this );
|
||||
conn = new ControlConnection( this, peer );
|
||||
conn->setName( key );
|
||||
return conn;
|
||||
}
|
||||
@@ -799,11 +815,11 @@ Servent::isIPWhitelisted( QHostAddress ip )
|
||||
static QList<range> whitelist;
|
||||
if( whitelist.isEmpty() )
|
||||
{
|
||||
whitelist << range( QHostAddress( "10.0.0.0" ), 8 )
|
||||
<< range( QHostAddress( "172.16.0.0" ), 12 )
|
||||
<< range( QHostAddress( "192.168.0.0" ), 16 )
|
||||
<< range( QHostAddress( "169.254.0.0" ), 16 )
|
||||
<< range( QHostAddress( "127.0.0.0" ), 24 );
|
||||
whitelist << range( QHostAddress( "10.0.0.0" ), 8 )
|
||||
<< range( QHostAddress( "172.16.0.0" ), 12 )
|
||||
<< range( QHostAddress( "192.168.0.0" ), 16 )
|
||||
<< range( QHostAddress( "169.254.0.0" ), 16 )
|
||||
<< range( QHostAddress( "127.0.0.0" ), 24 );
|
||||
|
||||
// tDebug( LOGVERBOSE ) << "Loaded whitelist IP range:" << whitelist;
|
||||
}
|
||||
|
@@ -22,15 +22,15 @@
|
||||
// time before new connection terminates if no auth received
|
||||
#define AUTH_TIMEOUT 180000
|
||||
|
||||
#include <QObject>
|
||||
#include <QTcpServer>
|
||||
#include <QHostInfo>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QSharedPointer>
|
||||
#include <QTcpSocket>
|
||||
#include <QTimer>
|
||||
#include <QPointer>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtNetwork/QTcpServer>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
#include <QtNetwork/QHostInfo>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
@@ -159,6 +159,8 @@ private:
|
||||
QJson::Parser parser;
|
||||
QList< ControlConnection* > m_controlconnections; // canonical list of authed peers
|
||||
QMap< QString, QWeakPointer<Connection> > m_offers;
|
||||
QStringList m_connectedNodes;
|
||||
|
||||
int m_port, m_externalPort;
|
||||
QHostAddress m_externalAddress;
|
||||
QString m_externalHostname;
|
||||
|
@@ -293,7 +293,8 @@ Playlist::loadRevision( const QString& rev )
|
||||
void
|
||||
Playlist::createNewRevision( const QString& newrev, const QString& oldrev, const QList< plentry_ptr >& entries )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << newrev << oldrev << entries.count();
|
||||
tDebug() << Q_FUNC_INFO << newrev << oldrev << entries.count();
|
||||
Q_ASSERT( m_source->isLocal() || newrev == oldrev );
|
||||
|
||||
if ( busy() )
|
||||
{
|
||||
@@ -387,34 +388,32 @@ Playlist::setNewRevision( const QString& rev,
|
||||
bool is_newest_rev,
|
||||
const QMap< QString, Tomahawk::plentry_ptr >& addedmap )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << rev << is_newest_rev << m_title << addedmap.count() << neworderedguids.count() << oldorderedguids.count();
|
||||
|
||||
// build up correctly ordered new list of plentry_ptrs from
|
||||
// existing ones, and the ones that have been added
|
||||
QMap<QString, plentry_ptr> entriesmap;
|
||||
foreach( const plentry_ptr& p, m_entries )
|
||||
foreach ( const plentry_ptr& p, m_entries )
|
||||
entriesmap.insert( p->guid(), p );
|
||||
|
||||
QList<plentry_ptr> entries;
|
||||
foreach( const QString& id, neworderedguids )
|
||||
foreach ( const QString& id, neworderedguids )
|
||||
{
|
||||
if( entriesmap.contains( id ) )
|
||||
if ( entriesmap.contains( id ) )
|
||||
{
|
||||
entries.append( entriesmap.value( id ) );
|
||||
}
|
||||
else if( addedmap.contains( id ) )
|
||||
else if ( addedmap.contains( id ) )
|
||||
{
|
||||
entries.append( addedmap.value( id ) );
|
||||
if( is_newest_rev )
|
||||
if ( is_newest_rev )
|
||||
m_entries.append( addedmap.value( id ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* qDebug() << "id:" << id;
|
||||
* qDebug() << "newordered:" << neworderedguids.count() << neworderedguids;
|
||||
* qDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
|
||||
* qDebug() << "addedmap:" << addedmap.count() << addedmap;
|
||||
* qDebug() << "m_entries" << m_entries; */
|
||||
tDebug() << "id:" << id;
|
||||
tDebug() << "newordered:" << neworderedguids.count() << neworderedguids;
|
||||
tDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
|
||||
tDebug() << "addedmap:" << addedmap.count() << addedmap;
|
||||
tDebug() << "m_entries" << m_entries;
|
||||
|
||||
tLog() << "Playlist error for playlist with guid" << guid() << "from source" << author()->friendlyName();
|
||||
Q_ASSERT( false ); // XXX
|
||||
@@ -428,19 +427,19 @@ Playlist::setNewRevision( const QString& rev,
|
||||
// entries that have been removed:
|
||||
QSet<QString> removedguids = oldorderedguids.toSet().subtract( neworderedguids.toSet() );
|
||||
//qDebug() << "Removedguids:" << removedguids << "oldorederedguids" << oldorderedguids << "newog" << neworderedguids;
|
||||
foreach( QString remid, removedguids )
|
||||
foreach ( QString remid, removedguids )
|
||||
{
|
||||
// NB: entriesmap will contain old/removed entries only if the removal was done
|
||||
// in the same session - after a restart, history is not in memory.
|
||||
if( entriesmap.contains( remid ) )
|
||||
if ( entriesmap.contains( remid ) )
|
||||
{
|
||||
pr.removed << entriesmap.value( remid );
|
||||
if( is_newest_rev )
|
||||
if ( is_newest_rev )
|
||||
{
|
||||
//qDebug() << "Removing from m_entries" << remid;
|
||||
for( int k = 0 ; k < m_entries.length(); ++k )
|
||||
for ( int k = 0 ; k < m_entries.length(); ++k )
|
||||
{
|
||||
if( m_entries.at( k )->guid() == remid )
|
||||
if ( m_entries.at( k )->guid() == remid )
|
||||
{
|
||||
//qDebug() << "removed at" << k;
|
||||
m_entries.removeAt( k );
|
||||
@@ -452,8 +451,8 @@ Playlist::setNewRevision( const QString& rev,
|
||||
}
|
||||
|
||||
pr.added = addedmap.values();
|
||||
|
||||
pr.newlist = entries;
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
|
@@ -159,13 +159,19 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
r.setTop( r.bottom() - painter->fontMetrics().height() );
|
||||
r.adjust( 4, 0, -4, -1 );
|
||||
if ( m_hoveringOver == index )
|
||||
{
|
||||
TomahawkUtils::drawQueryBackground( painter, opt.palette, r, 1.5 );
|
||||
|
||||
painter->setPen( opt.palette.color( QPalette::HighlightedText ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
painter->setPen( opt.palette.color( QPalette::Dark ).darker( 200 ) );
|
||||
painter->setPen( opt.palette.color( QPalette::Dark ).darker( 200 ) );
|
||||
#else
|
||||
painter->setPen( opt.palette.color( QPalette::Dark ) );
|
||||
painter->setPen( opt.palette.color( QPalette::Dark ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
to.setAlignment( Qt::AlignHCenter | Qt::AlignBottom );
|
||||
text = painter->fontMetrics().elidedText( item->album()->artist()->name(), Qt::ElideRight, textRect.width() - 3 );
|
||||
painter->drawText( textRect, text, to );
|
||||
@@ -177,9 +183,11 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
Q_UNUSED( model );
|
||||
Q_UNUSED( option );
|
||||
|
||||
if ( event->type() != QEvent::MouseButtonRelease &&
|
||||
@@ -217,7 +225,8 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const
|
||||
|
||||
event->accept();
|
||||
return true;
|
||||
} else if ( event->type() == QEvent::MouseButtonPress )
|
||||
}
|
||||
else if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
// Stop the whole album from having a down click action as we just want the artist name to be clicked
|
||||
event->accept();
|
||||
@@ -231,6 +240,7 @@ AlbumItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumItemDelegate::whitespaceMouseEvent()
|
||||
{
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "artist.h"
|
||||
#include "albumitem.h"
|
||||
#include "source.h"
|
||||
#include "sourcelist.h"
|
||||
#include "database/database.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
@@ -247,6 +248,7 @@ AlbumModel::addCollection( const collection_ptr& collection, bool overwrite )
|
||||
|
||||
DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( collection );
|
||||
m_overwriteOnAdd = overwrite;
|
||||
m_collection = collection;
|
||||
|
||||
connect( cmd, SIGNAL( albums( QList<Tomahawk::album_ptr>, QVariant ) ),
|
||||
SLOT( addAlbums( QList<Tomahawk::album_ptr> ) ) );
|
||||
@@ -255,6 +257,21 @@ AlbumModel::addCollection( const collection_ptr& collection, bool overwrite )
|
||||
|
||||
m_title = tr( "All albums from %1" ).arg( collection->source()->friendlyName() );
|
||||
|
||||
if ( collection.isNull() )
|
||||
{
|
||||
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
|
||||
|
||||
QList<Tomahawk::source_ptr> sources = SourceList::instance()->sources();
|
||||
foreach ( const source_ptr& source, sources )
|
||||
{
|
||||
connect( source->collection().data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ), Qt::UniqueConnection );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
connect( collection.data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ), Qt::UniqueConnection );
|
||||
}
|
||||
|
||||
emit loadingStarted();
|
||||
}
|
||||
|
||||
@@ -290,14 +307,14 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in
|
||||
void
|
||||
AlbumModel::addAlbums( const QList<Tomahawk::album_ptr>& albums )
|
||||
{
|
||||
emit loadingFinished();
|
||||
|
||||
if ( !albums.count() )
|
||||
return;
|
||||
|
||||
if ( m_overwriteOnAdd )
|
||||
clear();
|
||||
|
||||
emit loadingFinished();
|
||||
|
||||
int c = rowCount( QModelIndex() );
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
@@ -318,6 +335,23 @@ AlbumModel::addAlbums( const QList<Tomahawk::album_ptr>& albums )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumModel::onSourceAdded( const Tomahawk::source_ptr& source )
|
||||
{
|
||||
connect( source->collection().data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ), Qt::UniqueConnection );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumModel::onCollectionChanged()
|
||||
{
|
||||
if ( m_collection )
|
||||
addCollection( m_collection, true );
|
||||
else
|
||||
addCollection( m_collection, true );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumModel::clear()
|
||||
{
|
||||
|
@@ -96,9 +96,13 @@ signals:
|
||||
|
||||
void loadingStarted();
|
||||
void loadingFinished();
|
||||
|
||||
private slots:
|
||||
void onDataChanged();
|
||||
|
||||
void onSourceAdded( const Tomahawk::source_ptr& source );
|
||||
void onCollectionChanged();
|
||||
|
||||
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
void infoSystemFinished( QString target );
|
||||
|
||||
@@ -110,6 +114,8 @@ private:
|
||||
QString m_description;
|
||||
bool m_overwriteOnAdd;
|
||||
|
||||
Tomahawk::collection_ptr m_collection;
|
||||
|
||||
QHash<qlonglong, QPersistentModelIndex> m_coverHash;
|
||||
};
|
||||
|
||||
|
@@ -369,6 +369,9 @@ ArtistView::onMenuTriggered( int action )
|
||||
bool
|
||||
ArtistView::jumpToCurrentTrack()
|
||||
{
|
||||
if ( !m_proxyModel )
|
||||
return false;
|
||||
|
||||
scrollTo( m_proxyModel->currentIndex(), QAbstractItemView::PositionAtCenter );
|
||||
return true;
|
||||
}
|
||||
|
@@ -18,9 +18,6 @@
|
||||
|
||||
#include "collectionflatmodel.h"
|
||||
|
||||
#include <QMimeData>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "database/database.h"
|
||||
#include "sourcelist.h"
|
||||
#include "utils/logger.h"
|
||||
@@ -31,9 +28,6 @@ using namespace Tomahawk;
|
||||
CollectionFlatModel::CollectionFlatModel( QObject* parent )
|
||||
: TrackModel( parent )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
connect( SourceList::instance(), SIGNAL( sourceRemoved( Tomahawk::source_ptr ) ), SLOT( onSourceOffline( Tomahawk::source_ptr ) ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +39,6 @@ CollectionFlatModel::~CollectionFlatModel()
|
||||
void
|
||||
CollectionFlatModel::addCollections( const QList< collection_ptr >& collections )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Adding collections!";
|
||||
foreach( const collection_ptr& col, collections )
|
||||
{
|
||||
addCollection( col );
|
||||
@@ -64,12 +57,7 @@ CollectionFlatModel::addCollection( const collection_ptr& collection, bool sendN
|
||||
<< collection->source()->id()
|
||||
<< collection->source()->userName();
|
||||
|
||||
connect( collection.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
connect( collection.data(), SIGNAL( tracksRemoved( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksRemoved( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
if( sendNotifications )
|
||||
if ( sendNotifications )
|
||||
emit loadingStarted();
|
||||
|
||||
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( collection );
|
||||
@@ -107,143 +95,32 @@ CollectionFlatModel::addFilteredCollection( const collection_ptr& collection, un
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::removeCollection( const collection_ptr& collection )
|
||||
{
|
||||
return; // FIXME
|
||||
|
||||
disconnect( collection.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr> ) ),
|
||||
this, SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
QTime timer;
|
||||
timer.start();
|
||||
|
||||
// QList<TrackModelItem*> plitems = m_collectionIndex.values( collection );
|
||||
QList< QPair< int, int > > rows;
|
||||
QList< QPair< int, int > > sortrows;
|
||||
QPair< int, int > row;
|
||||
QPair< int, int > rowf;
|
||||
rows = m_collectionRows.values( collection );
|
||||
|
||||
while ( rows.count() )
|
||||
{
|
||||
int x = -1;
|
||||
int j = 0;
|
||||
foreach( row, rows )
|
||||
{
|
||||
if ( x < 0 || row.first > rows.at( x ).first )
|
||||
x = j;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
sortrows.append( rows.at( x ) );
|
||||
rows.removeAt( x );
|
||||
}
|
||||
|
||||
foreach( row, sortrows )
|
||||
{
|
||||
QMap< Tomahawk::collection_ptr, QPair< int, int > > newrows;
|
||||
foreach ( const collection_ptr& col, m_collectionRows.uniqueKeys() )
|
||||
{
|
||||
if ( col.data() == collection.data() )
|
||||
continue;
|
||||
|
||||
foreach ( rowf, m_collectionRows.values( col ) )
|
||||
{
|
||||
if ( rowf.first > row.first )
|
||||
{
|
||||
rowf.first -= ( row.second - row.first ) + 1;
|
||||
rowf.second -= ( row.second - row.first ) + 1;
|
||||
}
|
||||
newrows.insertMulti( col, rowf );
|
||||
}
|
||||
}
|
||||
m_collectionRows = newrows;
|
||||
|
||||
qDebug() << "Removing rows:" << row.first << row.second;
|
||||
emit beginRemoveRows( QModelIndex(), row.first, row.second );
|
||||
for ( int i = row.second; i >= row.first; i-- )
|
||||
{
|
||||
TrackModelItem* item = itemFromIndex( index( i, 0, QModelIndex() ) );
|
||||
delete item;
|
||||
}
|
||||
emit endRemoveRows();
|
||||
}
|
||||
|
||||
qDebug() << "Collection removed, time elapsed:" << timer.elapsed();
|
||||
|
||||
// emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << tracks.count() << rowCount( QModelIndex() );
|
||||
|
||||
if( !m_loadingCollections.isEmpty() && sender() && qobject_cast< Collection* >( sender() ) )
|
||||
if ( !m_loadingCollections.isEmpty() && sender() && qobject_cast< Collection* >( sender() ) )
|
||||
{
|
||||
// we are keeping track and are called as a slot
|
||||
m_loadingCollections.removeAll( qobject_cast< Collection* >( sender() ) );
|
||||
}
|
||||
|
||||
bool kickOff = m_tracksToAdd.isEmpty();
|
||||
m_tracksToAdd << tracks;
|
||||
append( tracks );
|
||||
|
||||
emit trackCountChanged( trackCount() );
|
||||
|
||||
if ( m_tracksToAdd.count() && kickOff )
|
||||
processTracksToAdd();
|
||||
else if ( m_tracksToAdd.isEmpty() && m_loadingCollections.isEmpty() )
|
||||
if ( m_loadingCollections.isEmpty() )
|
||||
emit loadingFinished();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::processTracksToAdd()
|
||||
{
|
||||
int chunkSize = 5000;
|
||||
int maxc = qMin( chunkSize, m_tracksToAdd.count() );
|
||||
int c = rowCount( QModelIndex() );
|
||||
|
||||
emit beginInsertRows( QModelIndex(), c, c + maxc - 1 );
|
||||
//beginResetModel();
|
||||
|
||||
TrackModelItem* plitem;
|
||||
QList< Tomahawk::query_ptr >::iterator iter = m_tracksToAdd.begin();
|
||||
|
||||
for( int i = 0; i < maxc; ++i )
|
||||
{
|
||||
plitem = new TrackModelItem( *iter, m_rootItem );
|
||||
plitem->index = createIndex( m_rootItem->children.count() - 1, 0, plitem );
|
||||
|
||||
connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
m_tracksToAdd.erase( m_tracksToAdd.begin(), iter );
|
||||
|
||||
if ( m_tracksToAdd.isEmpty() && m_loadingCollections.isEmpty() )
|
||||
emit loadingFinished();
|
||||
|
||||
//endResetModel();
|
||||
emit endInsertRows();
|
||||
qDebug() << Q_FUNC_INFO << rowCount( QModelIndex() );
|
||||
|
||||
if ( m_tracksToAdd.count() )
|
||||
QTimer::singleShot( 250, this, SLOT( processTracksToAdd() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::onTracksRemoved( const QList<Tomahawk::query_ptr>& tracks )
|
||||
{
|
||||
QList<Tomahawk::query_ptr> t = tracks;
|
||||
for ( int i = rowCount( QModelIndex() ); i >= 0 && t.count(); i-- )
|
||||
{
|
||||
TrackModelItem* item = itemFromIndex( index( i, 0, QModelIndex() ) );
|
||||
QModelIndex idx = index( i, 0, QModelIndex() );
|
||||
TrackModelItem* item = itemFromIndex( idx );
|
||||
if ( !item )
|
||||
continue;
|
||||
|
||||
@@ -252,11 +129,7 @@ CollectionFlatModel::onTracksRemoved( const QList<Tomahawk::query_ptr>& tracks )
|
||||
{
|
||||
if ( item->query().data() == query.data() )
|
||||
{
|
||||
qDebug() << "Removing row:" << i << query->toString();
|
||||
emit beginRemoveRows( QModelIndex(), i, i );
|
||||
delete item;
|
||||
emit endRemoveRows();
|
||||
|
||||
remove( idx );
|
||||
t.removeAt( j );
|
||||
break;
|
||||
}
|
||||
@@ -264,9 +137,6 @@ CollectionFlatModel::onTracksRemoved( const QList<Tomahawk::query_ptr>& tracks )
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
// emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
qDebug() << Q_FUNC_INFO << rowCount( QModelIndex() );
|
||||
}
|
||||
|
||||
|
||||
@@ -274,20 +144,7 @@ void
|
||||
CollectionFlatModel::onDataChanged()
|
||||
{
|
||||
TrackModelItem* p = (TrackModelItem*)sender();
|
||||
// emit itemSizeChanged( p->index );
|
||||
|
||||
if ( p )
|
||||
emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionFlatModel::onSourceOffline( const Tomahawk::source_ptr& src )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( m_collectionRows.contains( src->collection() ) )
|
||||
{
|
||||
removeCollection( src->collection() );
|
||||
}
|
||||
}
|
||||
|
@@ -46,16 +46,9 @@ public:
|
||||
virtual int trackCount() const { return rowCount( QModelIndex() ) + m_tracksToAdd.count(); }
|
||||
|
||||
void addCollections( const QList< Tomahawk::collection_ptr >& collections );
|
||||
|
||||
void addCollection( const Tomahawk::collection_ptr& collection, bool sendNotifications = true );
|
||||
void removeCollection( const Tomahawk::collection_ptr& collection );
|
||||
|
||||
void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllTracks::SortOrder order );
|
||||
|
||||
virtual void append( const Tomahawk::query_ptr& /*query*/ ) {}
|
||||
virtual void append( const Tomahawk::artist_ptr& /*artist*/ ) {}
|
||||
virtual void append( const Tomahawk::album_ptr& /*album*/ ) {}
|
||||
|
||||
signals:
|
||||
void repeatModeChanged( Tomahawk::PlaylistInterface::RepeatMode mode );
|
||||
void shuffleModeChanged( bool enabled );
|
||||
@@ -70,10 +63,6 @@ private slots:
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks );
|
||||
void onTracksRemoved( const QList<Tomahawk::query_ptr>& tracks );
|
||||
|
||||
void onSourceOffline( const Tomahawk::source_ptr& src );
|
||||
|
||||
void processTracksToAdd();
|
||||
|
||||
private:
|
||||
QMap< Tomahawk::collection_ptr, QPair< int, int > > m_collectionRows;
|
||||
QList<Tomahawk::query_ptr> m_tracksToAdd;
|
||||
|
@@ -313,9 +313,9 @@ DynamicModel::removeIndex(const QModelIndex& idx, bool moreToCome)
|
||||
if( !moreToCome && idx == index( rowCount( QModelIndex() ) - 1, 0, QModelIndex() ) ) { // if the user is manually removing the last one, re-add as we're a station
|
||||
newTrackLoading();
|
||||
}
|
||||
TrackModel::removeIndex( idx );
|
||||
TrackModel::remove( idx );
|
||||
} else
|
||||
PlaylistModel::removeIndex( idx, moreToCome );
|
||||
PlaylistModel::remove( idx, moreToCome );
|
||||
// don't call onPlaylistChanged.
|
||||
|
||||
if( !moreToCome )
|
||||
|
@@ -172,7 +172,7 @@ DynamicPlaylist::createNewRevision( const QString& newUuid )
|
||||
}
|
||||
else if( mode() == OnDemand )
|
||||
{
|
||||
createNewRevision( newUuid.isEmpty() ? uuid() : newUuid, currentrevision(), type(), generator()->controls());
|
||||
createNewRevision( newUuid.isEmpty() ? uuid() : newUuid, currentrevision(), type(), generator()->controls() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,8 @@ DynamicPlaylist::createNewRevision( const QString& newrev,
|
||||
const QList< dyncontrol_ptr>& controls,
|
||||
const QList< plentry_ptr >& entries )
|
||||
{
|
||||
Q_ASSERT( m_source->isLocal() || newrev == oldrev );
|
||||
|
||||
if ( busy() )
|
||||
{
|
||||
m_revisionQueue.enqueue( DynQueueItem( newrev, oldrev, type, controls, (int)Static, entries, oldrev == currentrevision() ) );
|
||||
@@ -230,6 +232,8 @@ DynamicPlaylist::createNewRevision( const QString& newrev,
|
||||
const QString& type,
|
||||
const QList< dyncontrol_ptr>& controls )
|
||||
{
|
||||
Q_ASSERT( m_source->isLocal() || newrev == oldrev );
|
||||
|
||||
if ( busy() )
|
||||
{
|
||||
m_revisionQueue.enqueue( DynQueueItem( newrev, oldrev, type, controls, (int)OnDemand, QList< plentry_ptr >(), oldrev == currentrevision() ) );
|
||||
@@ -533,8 +537,15 @@ DynamicPlaylist::checkRevisionQueue()
|
||||
if ( item.oldRev != currentrevision() && item.applyToTip )
|
||||
{
|
||||
// this was applied to the then-latest, but the already-running operation changed it so it's out of date now. fix it
|
||||
if ( item.oldRev == item.newRev )
|
||||
{
|
||||
checkRevisionQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
item.oldRev = currentrevision();
|
||||
}
|
||||
|
||||
if( item.mode == Static )
|
||||
createNewRevision( item.newRev, item.oldRev, item.type, item.controls, item.entries );
|
||||
else
|
||||
|
@@ -264,7 +264,7 @@ DynamicView::collapseEntries( int startRow, int num, int numToKeep )
|
||||
todel << proxyModel()->index( startRow + i, k );
|
||||
}
|
||||
}
|
||||
proxyModel()->removeIndexes( todel );
|
||||
proxyModel()->remove( todel );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -102,6 +102,10 @@ public:
|
||||
* If this generator doesn't support this (and returns false for
|
||||
* \c onDemandSteerable) this will be null. The generator is responsible
|
||||
* for reacting to changes in the widget.
|
||||
*
|
||||
* Steering widgets may emit a \c steeringChanged() signal, which will cause the model to toss any
|
||||
* upcoming tracks and re-fetch them.
|
||||
*
|
||||
*/
|
||||
virtual QWidget* steeringWidget() { return 0; }
|
||||
|
||||
|
@@ -389,9 +389,6 @@ EchonestGenerator::dynamicFetched()
|
||||
|
||||
resetSteering();
|
||||
|
||||
if( !m_steerer.isNull() )
|
||||
m_steerer.data()->resetSteering( true );
|
||||
|
||||
try
|
||||
{
|
||||
Echonest::Song song = m_dynPlaylist->parseNextSong( reply );
|
||||
|
@@ -60,10 +60,10 @@ EchonestSteerer::EchonestSteerer( QWidget* parent )
|
||||
f.setBold( true );
|
||||
m_steerTop->setFont( f );
|
||||
m_textL->addWidget( m_steerTop );
|
||||
m_steerBottom = new QLabel( tr( "Takes effect on track change" ), this );
|
||||
f.setPointSize( f.pointSize() - 3 );
|
||||
m_steerBottom->setFont( f );
|
||||
m_textL->addWidget( m_steerBottom );
|
||||
// m_steerBottom = new QLabel( tr( "Takes effect on track change" ), this );
|
||||
// f.setPointSize( f.pointSize() - 3 );
|
||||
// m_steerBottom->setFont( f );
|
||||
// m_textL->addWidget( m_steerBottom );
|
||||
|
||||
m_layout->addLayout( m_textL, 1 );
|
||||
|
||||
@@ -97,6 +97,12 @@ EchonestSteerer::EchonestSteerer( QWidget* parent )
|
||||
|
||||
connect( m_description, SIGNAL( textChanged( QString ) ), this, SLOT( changed() ) );
|
||||
|
||||
m_apply = initButton( this );
|
||||
m_apply->setIcon( QIcon( RESPATH "images/apply-check.png" ) );
|
||||
m_apply->setToolTip( tr( "Apply steering command" ) );
|
||||
m_layout->addWidget( m_apply );
|
||||
connect( m_apply, SIGNAL( clicked( bool ) ), this, SLOT( applySteering() ) );
|
||||
|
||||
m_reset = initButton( this );
|
||||
m_reset->setIcon( QIcon( RESPATH "images/view-refresh.png" ) );
|
||||
m_reset->setToolTip( tr( "Reset all steering commands" ) );
|
||||
@@ -165,19 +171,7 @@ EchonestSteerer::fadeOut()
|
||||
void
|
||||
EchonestSteerer::changed()
|
||||
{
|
||||
bool keep = false;
|
||||
if( m_amplifier->itemData( m_amplifier->currentIndex() ).toString().isEmpty() ) { // Keep Current
|
||||
keep = true;
|
||||
|
||||
emit reset();
|
||||
}
|
||||
|
||||
if( m_field->itemData( m_field->currentIndex() ).toString() != "desc" ) {
|
||||
if( !keep ) {
|
||||
QString steer = m_field->itemData( m_field->currentIndex() ).toString() + m_amplifier->itemData( m_amplifier->currentIndex() ).toString();
|
||||
emit steerField( steer );
|
||||
}
|
||||
|
||||
// if description was shown, animate to shrink
|
||||
if( m_layout->indexOf( m_description ) > 0 ) {
|
||||
m_expanding = false;
|
||||
@@ -190,15 +184,8 @@ EchonestSteerer::changed()
|
||||
|
||||
m_resizeAnim.setFrameRange( start, end );
|
||||
m_resizeAnim.start();
|
||||
|
||||
qDebug() << "COLLAPSING FROM" << start << "TO" << end;
|
||||
}
|
||||
} else { // description, so put in the description field
|
||||
if( !m_description->text().isEmpty() && !keep ) {
|
||||
QString steer = m_description->text() + m_amplifier->itemData( m_amplifier->currentIndex() ).toString();
|
||||
emit steerDescription( steer );
|
||||
}
|
||||
|
||||
if( m_layout->indexOf( m_description ) == -1 ) {
|
||||
// animate to expand
|
||||
m_layout->insertWidget( m_layout->count() - 1, m_description, 1 );
|
||||
@@ -210,12 +197,32 @@ EchonestSteerer::changed()
|
||||
int end = start + m_layout->spacing() + m_description->sizeHint().width();
|
||||
m_resizeAnim.setFrameRange( start, end );
|
||||
m_resizeAnim.start();
|
||||
|
||||
qDebug() << "EXPANDING FROM" << start << "TO" << end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EchonestSteerer::applySteering()
|
||||
{
|
||||
if ( m_field->itemData( m_field->currentIndex() ).toString() != "desc" )
|
||||
{
|
||||
QString steer = m_field->itemData( m_field->currentIndex() ).toString() + m_amplifier->itemData( m_amplifier->currentIndex() ).toString();
|
||||
emit steerField( steer );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !m_description->text().isEmpty() )
|
||||
{
|
||||
QString steer = m_description->text() + m_amplifier->itemData( m_amplifier->currentIndex() ).toString();
|
||||
emit steerDescription( steer );
|
||||
}
|
||||
}
|
||||
|
||||
emit steeringChanged();
|
||||
|
||||
resetSteering( true );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EchonestSteerer::resizeFrame( int width )
|
||||
|
@@ -44,6 +44,7 @@ public:
|
||||
virtual void paintEvent(QPaintEvent* );
|
||||
|
||||
public slots:
|
||||
void applySteering();
|
||||
void resetSteering( bool automatic = false );
|
||||
|
||||
void fadeIn();
|
||||
@@ -56,6 +57,9 @@ signals:
|
||||
void reset();
|
||||
|
||||
void resized();
|
||||
|
||||
// interface to DynamicWidget
|
||||
void steeringChanged();
|
||||
private slots:
|
||||
void changed();
|
||||
|
||||
@@ -77,6 +81,7 @@ private:
|
||||
QLabel* m_steerBottom;
|
||||
|
||||
// icons on the right
|
||||
QToolButton* m_apply;
|
||||
QToolButton* m_reset;
|
||||
|
||||
// animations
|
||||
|
@@ -324,6 +324,8 @@ DynamicWidget::startStation()
|
||||
m_steering = m_playlist->generator()->steeringWidget();
|
||||
Q_ASSERT( m_steering );
|
||||
|
||||
connect( m_steering, SIGNAL( steeringChanged() ), this, SLOT( steeringChanged() ) );
|
||||
|
||||
int x = ( width() / 2 ) - ( m_steering->size().width() / 2 );
|
||||
int y = height() - m_steering->size().height() - 40; // padding
|
||||
|
||||
@@ -394,6 +396,25 @@ DynamicWidget::controlChanged( const Tomahawk::dyncontrol_ptr& control )
|
||||
emit descriptionChanged( m_playlist->generator()->sentenceSummary() );
|
||||
}
|
||||
|
||||
void
|
||||
DynamicWidget::steeringChanged()
|
||||
{
|
||||
// When steering changes, toss all the tracks that are upcoming, and re-fetch.
|
||||
QModelIndex cur = m_view->currentIndex();
|
||||
const int upcoming = m_view->proxyModel()->rowCount( QModelIndex() ) - 1 - cur.row();
|
||||
tDebug() << "Removing tracks after current in station, found" << upcoming;
|
||||
|
||||
QModelIndexList toRemove;
|
||||
for ( int i = cur.row() + 1; i < m_view->proxyModel()->rowCount( QModelIndex() ); i++ )
|
||||
{
|
||||
toRemove << m_view->proxyModel()->index( i, 0, QModelIndex() );
|
||||
}
|
||||
|
||||
m_view->proxyModel()->remove( toRemove );
|
||||
|
||||
m_playlist->generator()->fetchNext();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DynamicWidget::showPreview()
|
||||
|
@@ -103,6 +103,7 @@ private slots:
|
||||
|
||||
void controlsChanged( bool added );
|
||||
void controlChanged( const Tomahawk::dyncontrol_ptr& control );
|
||||
void steeringChanged();
|
||||
void showPreview();
|
||||
|
||||
void layoutFloatingWidgets();
|
||||
|
@@ -182,12 +182,12 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem&
|
||||
else
|
||||
{
|
||||
upperText = QString( "%1 - %2" ).arg( artist ).arg( track );
|
||||
QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->playedBy().second ) );
|
||||
QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->playedBy().second ), true );
|
||||
|
||||
if ( source == SourceList::instance()->getLocal() )
|
||||
lowerText = QString( "played %1 ago by you" ).arg( playtime );
|
||||
lowerText = QString( tr( "played %1 by you" ) ).arg( playtime );
|
||||
else
|
||||
lowerText = QString( "played %1 ago by %2" ).arg( playtime ).arg( source->friendlyName() );
|
||||
lowerText = QString( tr( "played %1 by %2" ) ).arg( playtime ).arg( source->friendlyName() );
|
||||
|
||||
if ( useAvatars )
|
||||
pixmap = source->avatar( Source::FancyStyle );
|
||||
|
@@ -39,9 +39,8 @@ using namespace Tomahawk;
|
||||
PlaylistModel::PlaylistModel( QObject* parent )
|
||||
: TrackModel( parent )
|
||||
, m_isTemporary( false )
|
||||
, m_changesOngoing( false )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_dropStorage.parent = QPersistentModelIndex();
|
||||
m_dropStorage.row = -10;
|
||||
|
||||
@@ -54,34 +53,9 @@ PlaylistModel::~PlaylistModel()
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PlaylistModel::columnCount( const QModelIndex& parent ) const
|
||||
{
|
||||
return TrackModel::columnCount( parent );
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
PlaylistModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
return TrackModel::data( index, role );
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
PlaylistModel::headerData( int section, Qt::Orientation orientation, int role ) const
|
||||
{
|
||||
return TrackModel::headerData( section, orientation, role );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEntries )
|
||||
{
|
||||
QString currentuuid;
|
||||
if ( currentItem().isValid() )
|
||||
currentuuid = itemFromIndex( currentItem() )->query()->id();
|
||||
|
||||
if ( !m_playlist.isNull() )
|
||||
{
|
||||
disconnect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::PlaylistRevision ) ) );
|
||||
@@ -89,10 +63,8 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
|
||||
disconnect( m_playlist.data(), SIGNAL( changed() ), this, SIGNAL( playlistChanged() ) );
|
||||
}
|
||||
|
||||
if ( rowCount( QModelIndex() ) && loadEntries )
|
||||
{
|
||||
if ( loadEntries )
|
||||
clear();
|
||||
}
|
||||
|
||||
m_playlist = playlist;
|
||||
connect( playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), SLOT( onRevisionLoaded( Tomahawk::PlaylistRevision ) ) );
|
||||
@@ -101,53 +73,16 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
|
||||
|
||||
setReadOnly( !m_playlist->author()->isLocal() );
|
||||
setTitle( playlist->title() );
|
||||
setDescription( tr( "A playlist by %1, created %2 ago" )
|
||||
setDescription( tr( "A playlist by %1, created %2" )
|
||||
.arg( playlist->author()->isLocal() ? tr( "you" ) : playlist->author()->friendlyName() )
|
||||
.arg( TomahawkUtils::ageToString( QDateTime::fromTime_t( playlist->createdOn() ) ) ) );
|
||||
.arg( TomahawkUtils::ageToString( QDateTime::fromTime_t( playlist->createdOn() ), true ) ) );
|
||||
|
||||
m_isTemporary = false;
|
||||
if ( !loadEntries )
|
||||
return;
|
||||
|
||||
TrackModelItem* plitem;
|
||||
QList<plentry_ptr> entries = playlist->entries();
|
||||
if ( entries.count() )
|
||||
{
|
||||
int c = rowCount( QModelIndex() );
|
||||
|
||||
qDebug() << "Starting loading" << playlist->title();
|
||||
emit beginInsertRows( QModelIndex(), c, c + entries.count() - 1 );
|
||||
|
||||
m_waitingForResolved.clear();
|
||||
foreach( const plentry_ptr& entry, entries )
|
||||
{
|
||||
// qDebug() << entry->query()->toString();
|
||||
plitem = new TrackModelItem( entry, m_rootItem );
|
||||
plitem->index = createIndex( m_rootItem->children.count() - 1, 0, plitem );
|
||||
|
||||
connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
|
||||
if ( entry->query()->id() == currentuuid )
|
||||
setCurrentItem( plitem->index );
|
||||
|
||||
if ( !entry->query()->resolvingFinished() && !entry->query()->playable() )
|
||||
{
|
||||
m_waitingForResolved.append( entry->query().data() );
|
||||
connect( entry->query().data(), SIGNAL( resolvingFinished( bool ) ), SLOT( trackResolved( bool ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
emit endInsertRows();
|
||||
}
|
||||
else
|
||||
qDebug() << "Playlist seems empty:" << playlist->title();
|
||||
|
||||
if ( !m_waitingForResolved.isEmpty() )
|
||||
{
|
||||
emit loadingStarted();
|
||||
}
|
||||
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
append( entries );
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +100,7 @@ PlaylistModel::loadHistory( const Tomahawk::source_ptr& source, unsigned int amo
|
||||
cmd->setLimit( amount );
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ), Qt::QueuedConnection );
|
||||
SLOT( append( QList<Tomahawk::query_ptr> ) ), Qt::QueuedConnection );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
@@ -174,22 +109,23 @@ PlaylistModel::loadHistory( const Tomahawk::source_ptr& source, unsigned int amo
|
||||
void
|
||||
PlaylistModel::clear()
|
||||
{
|
||||
if ( rowCount( QModelIndex() ) )
|
||||
{
|
||||
emit loadingFinished();
|
||||
TrackModel::clear();
|
||||
|
||||
emit beginResetModel();
|
||||
delete m_rootItem;
|
||||
m_rootItem = 0;
|
||||
m_rootItem = new TrackModelItem( 0, this );
|
||||
emit endResetModel();
|
||||
}
|
||||
m_waitingForResolved.clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const QList< plentry_ptr >& entries )
|
||||
{
|
||||
insert( entries, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const QList< query_ptr >& queries )
|
||||
{
|
||||
onTracksAdded( queries );
|
||||
insert( queries, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -199,13 +135,10 @@ PlaylistModel::append( const Tomahawk::query_ptr& query )
|
||||
if ( query.isNull() )
|
||||
return;
|
||||
|
||||
QList< Tomahawk::query_ptr > ql;
|
||||
ql << query;
|
||||
|
||||
if ( !query->resolvingFinished() )
|
||||
Pipeline::instance()->resolve( query );
|
||||
|
||||
onTracksAdded( ql );
|
||||
TrackModel::append( query );
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +158,7 @@ PlaylistModel::append( const Tomahawk::album_ptr& album )
|
||||
m_isTemporary = true;
|
||||
}
|
||||
|
||||
onTracksAdded( album->tracks() );
|
||||
append( album->tracks() );
|
||||
}
|
||||
|
||||
|
||||
@@ -245,20 +178,83 @@ PlaylistModel::append( const Tomahawk::artist_ptr& artist )
|
||||
m_isTemporary = true;
|
||||
}
|
||||
|
||||
onTracksAdded( artist->tracks() );
|
||||
append( artist->tracks() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::insert( unsigned int row, const Tomahawk::query_ptr& query )
|
||||
PlaylistModel::insert( const Tomahawk::query_ptr& query, int row )
|
||||
{
|
||||
if ( query.isNull() )
|
||||
TrackModel::insert( query, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::insert( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
{
|
||||
if ( !queries.count() )
|
||||
return;
|
||||
|
||||
QList< Tomahawk::query_ptr > ql;
|
||||
ql << query;
|
||||
QList< Tomahawk::plentry_ptr > entries;
|
||||
foreach( const query_ptr& query, queries )
|
||||
{
|
||||
plentry_ptr entry = plentry_ptr( new PlaylistEntry() );
|
||||
|
||||
onTracksInserted( row, ql );
|
||||
if ( query->results().count() )
|
||||
entry->setDuration( query->results().at( 0 )->duration() );
|
||||
else
|
||||
entry->setDuration( 0 );
|
||||
|
||||
entry->setLastmodified( 0 );
|
||||
entry->setAnnotation( "" ); // FIXME
|
||||
entry->setQuery( query );
|
||||
entry->setGuid( uuid() );
|
||||
|
||||
entries << entry;
|
||||
}
|
||||
|
||||
insert( entries, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row )
|
||||
{
|
||||
if ( !entries.count() )
|
||||
return;
|
||||
|
||||
int c = row;
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
crows.second = c + entries.count() - 1;
|
||||
|
||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||
|
||||
int i = 0;
|
||||
TrackModelItem* plitem;
|
||||
foreach( const plentry_ptr& entry, entries )
|
||||
{
|
||||
plitem = new TrackModelItem( entry, m_rootItem, row + i );
|
||||
plitem->index = createIndex( row + i, 0, plitem );
|
||||
i++;
|
||||
|
||||
if ( entry->query()->id() == currentItemUuid() )
|
||||
setCurrentItem( plitem->index );
|
||||
|
||||
if ( !entry->query()->resolvingFinished() && !entry->query()->playable() )
|
||||
{
|
||||
m_waitingForResolved.append( entry->query().data() );
|
||||
connect( entry->query().data(), SIGNAL( resolvingFinished( bool ) ), SLOT( trackResolved( bool ) ) );
|
||||
}
|
||||
|
||||
connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
}
|
||||
|
||||
if ( !m_waitingForResolved.isEmpty() )
|
||||
emit loadingStarted();
|
||||
|
||||
emit endInsertRows();
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -282,53 +278,9 @@ PlaylistModel::trackResolved( bool )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks )
|
||||
{
|
||||
onTracksInserted( rowCount( QModelIndex() ), tracks );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::onTracksInserted( unsigned int row, const QList<Tomahawk::query_ptr>& tracks )
|
||||
{
|
||||
if ( !tracks.count() )
|
||||
{
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
return;
|
||||
}
|
||||
|
||||
int c = row;
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
crows.second = c + tracks.count() - 1;
|
||||
|
||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||
|
||||
int i = 0;
|
||||
TrackModelItem* plitem;
|
||||
foreach( const query_ptr& query, tracks )
|
||||
{
|
||||
plentry_ptr entry = plentry_ptr( new PlaylistEntry() );
|
||||
entry->setQuery( query );
|
||||
|
||||
plitem = new TrackModelItem( entry, m_rootItem, row + i );
|
||||
plitem->index = createIndex( row + i, 0, plitem );
|
||||
|
||||
i++;
|
||||
|
||||
connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
}
|
||||
|
||||
emit endInsertRows();
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::onDataChanged()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
TrackModelItem* p = (TrackModelItem*)sender();
|
||||
if ( p && p->index.isValid() )
|
||||
emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount() - 1 ) );
|
||||
@@ -384,14 +336,16 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
|
||||
// so check if the drag originated in this playlist to determine whether or not to copy
|
||||
#ifdef Q_WS_MAC
|
||||
if ( !data->hasFormat( "application/tomahawk.playlist.id" ) ||
|
||||
( !m_playlist.isNull() && data->data( "application/tomahawk.playlist.id" ) != m_playlist->guid() ) )
|
||||
( !m_playlist.isNull() && data->data( "application/tomahawk.playlist.id" ) != m_playlist->guid() ) )
|
||||
{
|
||||
dj->setDropAction( DropJob::Append );
|
||||
}
|
||||
#else
|
||||
if ( action & Qt::CopyAction )
|
||||
dj->setDropAction( DropJob::Append );
|
||||
#endif
|
||||
|
||||
connect( dj, SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
connect( dj, SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
dj->tracksFromMimeData( data );
|
||||
|
||||
return true;
|
||||
@@ -412,44 +366,13 @@ PlaylistModel::parsedDroppedTracks( QList< query_ptr > tracks )
|
||||
else
|
||||
beginRow = rowCount( QModelIndex() );
|
||||
|
||||
// qDebug() << data->formats();
|
||||
QString currentuuid;
|
||||
if ( currentItem().isValid() )
|
||||
currentuuid = itemFromIndex( currentItem() )->query()->id();
|
||||
|
||||
if ( tracks.count() )
|
||||
{
|
||||
emit beginInsertRows( QModelIndex(), beginRow, beginRow + tracks.count() - 1 );
|
||||
foreach( const Tomahawk::query_ptr& query, tracks )
|
||||
{
|
||||
plentry_ptr e( new PlaylistEntry() );
|
||||
e->setGuid( uuid() );
|
||||
|
||||
if ( query->results().count() )
|
||||
e->setDuration( query->results().at( 0 )->duration() );
|
||||
else
|
||||
e->setDuration( 0 );
|
||||
|
||||
e->setLastmodified( 0 );
|
||||
e->setAnnotation( "" ); // FIXME
|
||||
e->setQuery( query );
|
||||
|
||||
TrackModelItem* plitem = new TrackModelItem( e, m_rootItem, beginRow );
|
||||
plitem->index = createIndex( beginRow++, 0, plitem );
|
||||
|
||||
if ( query->id() == currentuuid )
|
||||
setCurrentItem( plitem->index );
|
||||
|
||||
connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
}
|
||||
emit endInsertRows();
|
||||
|
||||
if ( m_dropStorage.action & Qt::CopyAction || m_dropStorage.action & Qt::MoveAction )
|
||||
{
|
||||
onPlaylistChanged();
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
bool update = ( m_dropStorage.action & Qt::CopyAction || m_dropStorage.action & Qt::MoveAction );
|
||||
if ( update )
|
||||
beginPlaylistChanges();
|
||||
|
||||
insert( tracks, beginRow );
|
||||
}
|
||||
|
||||
m_dropStorage.parent = QPersistentModelIndex();
|
||||
@@ -458,11 +381,32 @@ PlaylistModel::parsedDroppedTracks( QList< query_ptr > tracks )
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::onPlaylistChanged()
|
||||
PlaylistModel::beginPlaylistChanges()
|
||||
{
|
||||
if ( m_playlist.isNull() )
|
||||
if ( m_playlist.isNull() || !m_playlist->author()->isLocal() )
|
||||
return;
|
||||
|
||||
Q_ASSERT( !m_changesOngoing );
|
||||
m_changesOngoing = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::endPlaylistChanges()
|
||||
{
|
||||
if ( m_playlist.isNull() || !m_playlist->author()->isLocal() )
|
||||
return;
|
||||
|
||||
if ( m_changesOngoing )
|
||||
{
|
||||
m_changesOngoing = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << "Called" << Q_FUNC_INFO << "unexpectedly!";
|
||||
Q_ASSERT( false );
|
||||
}
|
||||
|
||||
QList<plentry_ptr> l = playlistEntries();
|
||||
QString newrev = uuid();
|
||||
m_waitForRevision << newrev;
|
||||
@@ -505,16 +449,17 @@ PlaylistModel::playlistEntries() const
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( unsigned int row, bool moreToCome )
|
||||
PlaylistModel::remove( int row, bool moreToCome )
|
||||
{
|
||||
removeIndex( index( row, 0, QModelIndex() ), moreToCome );
|
||||
TrackModel::remove( row, moreToCome );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
PlaylistModel::remove( const QModelIndex& index, bool moreToCome )
|
||||
{
|
||||
TrackModelItem* item = itemFromIndex( index );
|
||||
|
||||
if ( item && m_waitingForResolved.contains( item->query().data() ) )
|
||||
{
|
||||
m_waitingForResolved.removeAll( item->query().data() );
|
||||
@@ -522,12 +467,27 @@ PlaylistModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
emit loadingFinished();
|
||||
}
|
||||
|
||||
TrackModel::removeIndex( index );
|
||||
if ( !m_changesOngoing )
|
||||
beginPlaylistChanges();
|
||||
|
||||
if ( !moreToCome && !m_playlist.isNull() )
|
||||
{
|
||||
onPlaylistChanged();
|
||||
}
|
||||
TrackModel::remove( index, moreToCome );
|
||||
|
||||
if ( !moreToCome )
|
||||
endPlaylistChanges();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( const QList<QModelIndex>& indexes )
|
||||
{
|
||||
TrackModel::remove( indexes );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( const QList<QPersistentModelIndex>& indexes )
|
||||
{
|
||||
TrackModel::remove( indexes );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -47,11 +47,6 @@ public:
|
||||
explicit PlaylistModel( QObject* parent = 0 );
|
||||
~PlaylistModel();
|
||||
|
||||
int columnCount( const QModelIndex& parent = QModelIndex() ) const;
|
||||
|
||||
QVariant data( const QModelIndex& index, int role ) const;
|
||||
QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
|
||||
|
||||
virtual QMimeData* mimeData ( const QModelIndexList& indexes ) const;
|
||||
virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent );
|
||||
|
||||
@@ -60,44 +55,47 @@ public:
|
||||
virtual void loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEntries = true );
|
||||
void loadHistory( const Tomahawk::source_ptr& source, unsigned int amount = 50 );
|
||||
|
||||
void clear();
|
||||
|
||||
void append( const Tomahawk::query_ptr& query );
|
||||
void append( const Tomahawk::album_ptr& album );
|
||||
void append( const Tomahawk::artist_ptr& artist );
|
||||
|
||||
void append( const QList< Tomahawk::query_ptr >& queries );
|
||||
|
||||
void insert( unsigned int row, const Tomahawk::query_ptr& query );
|
||||
|
||||
void remove( unsigned int row, bool moreToCome = false );
|
||||
virtual void removeIndex( const QModelIndex& index, bool moreToCome = false );
|
||||
bool isTemporary() const;
|
||||
|
||||
public slots:
|
||||
virtual void clear();
|
||||
|
||||
virtual void append( const Tomahawk::query_ptr& query );
|
||||
virtual void append( const Tomahawk::album_ptr& album );
|
||||
virtual void append( const Tomahawk::artist_ptr& artist );
|
||||
virtual void append( const QList< Tomahawk::query_ptr >& queries );
|
||||
virtual void append( const QList< Tomahawk::plentry_ptr >& entries );
|
||||
|
||||
virtual void insert( const Tomahawk::query_ptr& query, int row = 0 );
|
||||
virtual void insert( const QList< Tomahawk::query_ptr >& queries, int row = 0 );
|
||||
virtual void insert( const QList< Tomahawk::plentry_ptr >& entries, int row = 0 );
|
||||
|
||||
virtual void remove( int row, bool moreToCome = false );
|
||||
virtual void remove( const QModelIndex& index, bool moreToCome = false );
|
||||
virtual void remove( const QList<QModelIndex>& indexes );
|
||||
virtual void remove( const QList<QPersistentModelIndex>& indexes );
|
||||
|
||||
signals:
|
||||
void repeatModeChanged( Tomahawk::PlaylistInterface::RepeatMode mode );
|
||||
void shuffleModeChanged( bool enabled );
|
||||
void itemSizeChanged( const QModelIndex& index );
|
||||
void playlistDeleted();
|
||||
void playlistChanged();
|
||||
|
||||
private slots:
|
||||
void onDataChanged();
|
||||
|
||||
void onRevisionLoaded( Tomahawk::PlaylistRevision revision );
|
||||
void onPlaylistChanged();
|
||||
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks );
|
||||
void onTracksInserted( unsigned int row, const QList<Tomahawk::query_ptr>& tracks );
|
||||
void parsedDroppedTracks( QList<Tomahawk::query_ptr> );
|
||||
|
||||
void trackResolved( bool );
|
||||
|
||||
private:
|
||||
void beginPlaylistChanges();
|
||||
void endPlaylistChanges();
|
||||
|
||||
QList<Tomahawk::plentry_ptr> playlistEntries() const;
|
||||
|
||||
Tomahawk::playlist_ptr m_playlist;
|
||||
bool m_isTemporary;
|
||||
bool m_changesOngoing;
|
||||
QList< Tomahawk::Query* > m_waitingForResolved;
|
||||
QStringList m_waitForRevision;
|
||||
|
||||
|
@@ -94,7 +94,7 @@ PlaylistView::keyPressEvent( QKeyEvent* event )
|
||||
if ( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !model()->isReadOnly() )
|
||||
{
|
||||
qDebug() << "Removing selected items";
|
||||
proxyModel()->removeIndexes( selectedIndexes() );
|
||||
proxyModel()->remove( selectedIndexes() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +102,10 @@ PlaylistView::keyPressEvent( QKeyEvent* event )
|
||||
void
|
||||
PlaylistView::deleteItems()
|
||||
{
|
||||
proxyModel()->removeIndexes( selectedIndexes() );
|
||||
proxyModel()->remove( selectedIndexes() );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PlaylistView::canAutoUpdate() const
|
||||
{
|
||||
@@ -114,6 +115,7 @@ PlaylistView::canAutoUpdate() const
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PlaylistView::autoUpdate() const
|
||||
{
|
||||
|
@@ -44,7 +44,7 @@ void
|
||||
QueueProxyModel::onIndexActivated( const QModelIndex& index )
|
||||
{
|
||||
setCurrentIndex( QModelIndex() );
|
||||
removeIndex( index );
|
||||
remove( index );
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ QueueProxyModel::siblingItem( int itemsAway )
|
||||
setCurrentIndex( QModelIndex() );
|
||||
Tomahawk::result_ptr res = PlaylistProxyModel::siblingItem( itemsAway );
|
||||
|
||||
removeIndex( currentIndex() );
|
||||
remove( currentIndex() );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@@ -39,16 +39,13 @@ TrackModel::TrackModel( QObject* parent )
|
||||
, m_readOnly( true )
|
||||
, m_style( Detailed )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
connect( AudioEngine::instance(), SIGNAL( finished( Tomahawk::result_ptr ) ), SLOT( onPlaybackFinished( Tomahawk::result_ptr ) ), Qt::DirectConnection );
|
||||
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
|
||||
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
|
||||
}
|
||||
|
||||
|
||||
TrackModel::~TrackModel()
|
||||
{
|
||||
// delete m_rootItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -230,6 +227,7 @@ QVariant
|
||||
TrackModel::headerData( int section, Qt::Orientation orientation, int role ) const
|
||||
{
|
||||
Q_UNUSED( orientation );
|
||||
|
||||
QStringList headers;
|
||||
headers << tr( "Artist" ) << tr( "Title" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" );
|
||||
if ( role == Qt::DisplayRole && section >= 0 )
|
||||
@@ -244,7 +242,6 @@ TrackModel::headerData( int section, Qt::Orientation orientation, int role ) con
|
||||
void
|
||||
TrackModel::setCurrentItem( const QModelIndex& index )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
TrackModelItem* oldEntry = itemFromIndex( m_currentIndex );
|
||||
if ( oldEntry )
|
||||
{
|
||||
@@ -252,14 +249,16 @@ TrackModel::setCurrentItem( const QModelIndex& index )
|
||||
}
|
||||
|
||||
TrackModelItem* entry = itemFromIndex( index );
|
||||
if ( entry )
|
||||
if ( index.isValid() && entry && !entry->query().isNull() )
|
||||
{
|
||||
m_currentIndex = index;
|
||||
m_currentUuid = entry->query()->id();
|
||||
entry->setIsPlaying( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentIndex = QModelIndex();
|
||||
m_currentUuid = QString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,16 +321,96 @@ TrackModel::mimeData( const QModelIndexList &indexes ) const
|
||||
|
||||
|
||||
void
|
||||
TrackModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
TrackModel::clear()
|
||||
{
|
||||
if ( rowCount( QModelIndex() ) )
|
||||
{
|
||||
emit loadingFinished();
|
||||
|
||||
emit beginResetModel();
|
||||
delete m_rootItem;
|
||||
m_rootItem = 0;
|
||||
m_rootItem = new TrackModelItem( 0, this );
|
||||
emit endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::append( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
insert( query, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::append( const QList< Tomahawk::query_ptr >& queries )
|
||||
{
|
||||
insert( queries, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::insert( const Tomahawk::query_ptr& query, int row )
|
||||
{
|
||||
if ( query.isNull() )
|
||||
return;
|
||||
|
||||
QList< Tomahawk::query_ptr > ql;
|
||||
ql << query;
|
||||
|
||||
insert( ql, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::insert( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
{
|
||||
if ( !queries.count() )
|
||||
return;
|
||||
|
||||
int c = row;
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
crows.second = c + queries.count() - 1;
|
||||
|
||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||
|
||||
int i = 0;
|
||||
TrackModelItem* plitem;
|
||||
foreach( const query_ptr& query, queries )
|
||||
{
|
||||
plitem = new TrackModelItem( query, m_rootItem, row + i );
|
||||
plitem->index = createIndex( row + i, 0, plitem );
|
||||
i++;
|
||||
|
||||
if ( query->id() == currentItemUuid() )
|
||||
setCurrentItem( plitem->index );
|
||||
|
||||
connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
}
|
||||
|
||||
emit endInsertRows();
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::remove( int row, bool moreToCome )
|
||||
{
|
||||
remove( index( row, 0, QModelIndex() ), moreToCome );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::remove( const QModelIndex& index, bool moreToCome )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
// qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
|
||||
QMetaObject::invokeMethod( this, "removeIndex",
|
||||
QMetaObject::invokeMethod( this, "remove",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(const QModelIndex, index),
|
||||
Q_ARG(bool, moreToCome)
|
||||
);
|
||||
Q_ARG(bool, moreToCome) );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -346,24 +425,49 @@ TrackModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
emit endRemoveRows();
|
||||
}
|
||||
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
if ( !moreToCome )
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::removeIndexes( const QList<QModelIndex>& indexes )
|
||||
TrackModel::remove( const QList<QModelIndex>& indexes )
|
||||
{
|
||||
foreach( const QModelIndex& idx, indexes )
|
||||
QList<QPersistentModelIndex> pil;
|
||||
foreach ( const QModelIndex& idx, indexes )
|
||||
{
|
||||
removeIndex( idx );
|
||||
pil << idx;
|
||||
}
|
||||
|
||||
remove( pil );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackModel::remove( const QList<QPersistentModelIndex>& indexes )
|
||||
{
|
||||
QList<QPersistentModelIndex> finalIndexes;
|
||||
foreach ( const QPersistentModelIndex index, indexes )
|
||||
{
|
||||
if ( index.column() > 0 )
|
||||
continue;
|
||||
finalIndexes << index;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < finalIndexes.count(); i++ )
|
||||
{
|
||||
remove( finalIndexes.at( i ), i + 1 != finalIndexes.count() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TrackModelItem*
|
||||
TrackModel::itemFromIndex( const QModelIndex& index ) const
|
||||
{
|
||||
if ( index.isValid() )
|
||||
{
|
||||
return static_cast<TrackModelItem*>( index.internalPointer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_rootItem;
|
||||
@@ -372,10 +476,10 @@ TrackModel::itemFromIndex( const QModelIndex& index ) const
|
||||
|
||||
|
||||
void
|
||||
TrackModel::onPlaybackFinished( const Tomahawk::result_ptr& result )
|
||||
TrackModel::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
TrackModelItem* oldEntry = itemFromIndex( m_currentIndex );
|
||||
if ( oldEntry && !oldEntry->query().isNull() && oldEntry->query()->results().contains( result ) )
|
||||
if ( oldEntry && ( oldEntry->query().isNull() || !oldEntry->query()->numResults() || oldEntry->query()->results().first().data() != result.data() ) )
|
||||
{
|
||||
oldEntry->setIsPlaying( false );
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "playlistinterface.h"
|
||||
#include "trackmodelitem.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
@@ -84,16 +85,13 @@ public:
|
||||
virtual Qt::ItemFlags flags( const QModelIndex& index ) const;
|
||||
|
||||
virtual QPersistentModelIndex currentItem() { return m_currentIndex; }
|
||||
virtual Tomahawk::QID currentItemUuid() { return m_currentUuid; }
|
||||
|
||||
virtual Tomahawk::PlaylistInterface::RepeatMode repeatMode() const { return Tomahawk::PlaylistInterface::NoRepeat; }
|
||||
virtual bool shuffled() const { return false; }
|
||||
|
||||
virtual void ensureResolved();
|
||||
|
||||
virtual void append( const Tomahawk::query_ptr& query ) = 0;
|
||||
virtual void append( const Tomahawk::artist_ptr& artist ) = 0;
|
||||
virtual void append( const Tomahawk::album_ptr& album ) = 0;
|
||||
|
||||
TrackModelItem* itemFromIndex( const QModelIndex& index ) const;
|
||||
TrackModelItem* m_rootItem;
|
||||
|
||||
@@ -109,18 +107,32 @@ signals:
|
||||
public slots:
|
||||
virtual void setCurrentItem( const QModelIndex& index );
|
||||
|
||||
virtual void removeIndex( const QModelIndex& index, bool moreToCome = false );
|
||||
virtual void removeIndexes( const QList<QModelIndex>& indexes );
|
||||
virtual void clear();
|
||||
|
||||
virtual void append( const QList< Tomahawk::query_ptr >& queries );
|
||||
virtual void append( const Tomahawk::query_ptr& query );
|
||||
virtual void append( const Tomahawk::artist_ptr& artist ) { Q_UNUSED( artist ); }
|
||||
virtual void append( const Tomahawk::album_ptr& album ) { Q_UNUSED( album ); }
|
||||
|
||||
virtual void insert( const QList< Tomahawk::query_ptr >& queries, int row = 0 );
|
||||
virtual void insert( const Tomahawk::query_ptr& query, int row = 0 );
|
||||
|
||||
virtual void remove( int row, bool moreToCome = false );
|
||||
virtual void remove( const QModelIndex& index, bool moreToCome = false );
|
||||
virtual void remove( const QList<QModelIndex>& indexes );
|
||||
virtual void remove( const QList<QPersistentModelIndex>& indexes );
|
||||
|
||||
virtual void setRepeatMode( Tomahawk::PlaylistInterface::RepeatMode /*mode*/ ) {}
|
||||
virtual void setShuffled( bool /*shuffled*/ ) {}
|
||||
|
||||
private slots:
|
||||
void onPlaybackFinished( const Tomahawk::result_ptr& result );
|
||||
void onPlaybackStarted( const Tomahawk::result_ptr& result );
|
||||
void onPlaybackStopped();
|
||||
|
||||
private:
|
||||
QPersistentModelIndex m_currentIndex;
|
||||
Tomahawk::QID m_currentUuid;
|
||||
|
||||
bool m_readOnly;
|
||||
|
||||
QString m_title;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user