diff --git a/CMakeLists.txt b/CMakeLists.txt index 9314f2392a..f2a2f08373 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,277 +1,281 @@ cmake_minimum_required(VERSION 3.4) project(Amarok) # Remove all warnings, ease the porting to cmake 3.x if (POLICY CMP0028) cmake_policy(SET CMP0028 NEW) endif() ############### find_package(PkgConfig REQUIRED) find_package(ECM 1.7.0 REQUIRED CONFIG) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(FeatureSummary) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMAddTests) include(ECMAddAppIcon) include(FindPkgConfig) -find_package( Qt5 5.8.0 REQUIRED COMPONENTS Core DBus Gui QuickWidgets Qml Script ScriptTools Sql Svg Test Widgets Xml ) -find_package( Qt5 5.8.0 COMPONENTS QuickControls2 ) +find_package( Qt5 5.8.0 COMPONENTS QuickControls2 WebEngine ) set_package_properties( Qt5QuickControls2 PROPERTIES TYPE RUNTIME PURPOSE "Needed by the player's context area" ) + +find_package( Qt5 5.8.0 REQUIRED COMPONENTS Core DBus Gui QuickWidgets Qml Script ScriptTools Sql Svg Test Widgets Xml ) +set_package_properties( Qt5WebEngine PROPERTIES TYPE OPTIONAL PURPOSE "Needed by the wikipedia applet" ) + find_package( KF5 REQUIRED COMPONENTS Archive Codecs CoreAddons DBusAddons Declarative DNSSD GlobalAccel GuiAddons I18n IconThemes KCMUtils KIO NewStuff Notifications NotifyConfig Package Solid TextEditor ThreadWeaver WindowSystem ) + find_package( KF5 COMPONENTS Kirigami2 ) set_package_properties( KF5Kirigami2 PROPERTIES TYPE RUNTIME PURPOSE "Needed by the player's context area" ) ############### option(WITH_UTILITIES "Enable building of utilities" ON) option(WITH_PLAYER "Enable building of main Amarok player" ON) option(WITH_MP3Tunes "Enable mp3tunes in the Amarok player, requires multiple extra dependencies" ON) option(WITH_IPOD "Enable iPod support in Amarok" ON) option(WITH_MYSQL_EMBEDDED "Build the embedded database library -- highly recommended" ON) option(WITH_PLAYGROUND "Enable building of playground scripts and applets (WARNING: some of them might have legal issues!)" OFF) ############### Taglib set(TAGLIB_MIN_VERSION "1.7") find_package(Taglib REQUIRED) set_package_properties( Taglib PROPERTIES DESCRIPTION "Support for Audio metadata." URL "http://developer.kde.org/~wheeler/taglib.html" TYPE REQUIRED PURPOSE "Required for tag reading" ) # Check if TagLib is built with ASF and MP4 support include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES "${TAGLIB_INCLUDES}") set(CMAKE_REQUIRED_LIBRARIES "${TAGLIB_LIBRARIES}") check_cxx_source_compiles("#include int main() { TagLib::ASF::Tag tag; return 0;}" TAGLIB_ASF_FOUND) if( NOT TAGLIB_ASF_FOUND ) message(FATAL_ERROR "TagLib does not have ASF support compiled in.") endif() check_cxx_source_compiles("#include int main() { TagLib::MP4::Tag tag(0, 0); return 0;}" TAGLIB_MP4_FOUND) if( NOT TAGLIB_MP4_FOUND ) message(FATAL_ERROR "TagLib does not have MP4 support compiled in.") endif() check_cxx_source_compiles("#include #include #include #include #include using namespace TagLib; int main() { char *s; Mod::Tag tag; Mod::File modfile(s); S3M::File s3mfile(s); IT::File itfile(s); XM::File xmfile(s); return 0; }" TAGLIB_MOD_FOUND) check_cxx_source_compiles("#include int main() { char *s; TagLib::Ogg::Opus::File opusfile(s); return 0;}" TAGLIB_OPUS_FOUND) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) set(TAGLIB-EXTRAS_MIN_VERSION "1.0") find_package(Taglib-Extras) set(TAGLIB_EXTRAS_FOUND ${TAGLIB-EXTRAS_FOUND}) # we need a c-compatible name for the include file include(CheckTagLibFileName) check_taglib_filename(COMPLEX_TAGLIB_FILENAME) ############### #Needed to conditionally build tests and gui if(BUILD_TESTING) add_definitions(-DDEBUG) endif() if(WITH_DESKTOP_UI) add_definitions(-DDESKTOP_UI) endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmessage-length=0") if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmessage-length=0") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--as-needed") endif() endif () include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/shared ${CMAKE_CURRENT_BINARY_DIR}/shared ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # Require C++11 # WORKAROUND for Clang bug: http://llvm.org/bugs/show_bug.cgi?id=15651 if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-delayed-template-parsing") endif () add_definitions(-DQT_NO_URL_CAST_FROM_STRING) find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE) find_package( LibLastFm ) set( LIBLASTFM_MIN_VERSION "1.0.0" ) if( LIBLASTFM_FOUND ) if ( ${LIBLASTFM_MIN_VERSION} VERSION_LESS ${LIBLASTFM_VERSION} ) set( LIBLASTFM_FOUND TRUE ) endif() endif() string( TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER ) if( CMAKE_BUILD_TYPE_TOLOWER MATCHES debug ) set( DEBUG_BUILD_TYPE ON ) add_definitions(-Wall -Wextra) endif() # this needs to be here because also code in shared/ needs config.h. This is also the # reason why various checks are above why they belong under if( WITH_PLAYER ) configure_file( shared/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/shared/config.h ) add_subdirectory( data ) add_subdirectory( images ) add_subdirectory( shared ) if( WITH_PLAYER ) find_package(X11) find_package(Threads REQUIRED) find_package(MySQL REQUIRED) if( WITH_MYSQL_EMBEDDED ) set( BUILD_MYSQLE_COLLECTION TRUE ) set_package_properties( MYSQLD PROPERTIES DESCRIPTION "Embedded MySQL Libraries" URL "http://www.mysql.com" TYPE REQUIRED ) else() add_definitions( "-DNO_MYSQL_EMBEDDED" ) endif() set_package_properties( MYSQL PROPERTIES DESCRIPTION "MySQL Server Libraries" URL "http://www.mysql.com" TYPE REQUIRED ) # zlib is required for mysql embedded find_package(ZLIB REQUIRED) set_package_properties( ZLIB PROPERTIES DESCRIPTION "zlib" TYPE REQUIRED ) # We tell users that we need 1.0.3, but we really check just >= 1.0.0. This is because # upstream forgot to update version in lastfm/global.h, so it looks like 1.0.2. :-( # will be fixed in liblastfm-1.0.4 set( LIBLASTFM_MIN_VERSION "1.0.3" ) set_package_properties( LibLastFm PROPERTIES DESCRIPTION "Enable Last.Fm service, including scrobbling, song submissions, and suggested song dynamic playlists" URL "http://cdn.last.fm/client/liblastfm-${LIBLASTFM_MIN_VERSION}.tar.gz" TYPE OPTIONAL ) find_package(FFmpeg) set_package_properties(FFmpeg PROPERTIES DESCRIPTION "Libraries and tools for handling multimedia data" URL "https://www.ffmpeg.org/" TYPE OPTIONAL PURPOSE "Enable MusicDNS service" ) find_package(LibOFA) set_package_properties(LibOFA PROPERTIES DESCRIPTION "Open-source audio fingerprint by MusicIP" URL "http://code.google.com/p/musicip-libofa/" TYPE OPTIONAL PURPOSE "Enable MusicDNS service" ) ## gpodder Service # Actually it needs the to-be-released 1.10. Or you use 1.0.9 and add the # patches from the following pull requests: # https://github.com/gpodder/libmygpo-qt/pull/12 # -https://github.com/gpodder/libmygpo-qt/pull/13 find_package(Mygpo-qt5 1.0.9 CONFIG) set_package_properties(Mygpo-qt5 PROPERTIES DESCRIPTION "A Qt/C++ library wrapping the gpodder.net Webservice." URL "http://wiki.gpodder.org/wiki/Libmygpo-qt" TYPE OPTIONAL PURPOSE "Synchronize podcast subscriptions with gpodder.net" ) if( WITH_IPOD ) find_package(Ipod) set(IPOD_MIN_VERSION "0.8.2") if( IPOD_FOUND AND NOT WIN32 ) if ( ${IPOD_MIN_VERSION} VERSION_LESS ${IPOD_VERSION} ) set( IPOD_FOUND TRUE ) endif() endif() set_package_properties( Ipod PROPERTIES DESCRIPTION "Support Apple iPod/iPad/iPhone audio devices" URL "http://sourceforge.net/projects/gtkpod/" TYPE OPTIONAL ) find_package(GDKPixBuf) set_package_properties( GDKPixBuf PROPERTIES DESCRIPTION "Support for artwork on iPod audio devices via GDK-PixBuf" URL "http://developer.gnome.org/arch/imaging/gdkpixbuf.html" TYPE OPTIONAL ) endif() find_package(Mtp 1.0.0) set_package_properties(Mtp PROPERTIES TYPE OPTIONAL PURPOSE "Enable Support for portable media devices that use the media transfer protocol" ) if( WITH_MP3Tunes ) find_package(CURL) set_package_properties( CURL PROPERTIES DESCRIPTION "Used to transfer data with URLs" URL "https://curl.haxx.se/" TYPE OPTIONAL ) find_package(LibXml2) set_package_properties( LibXml2 PROPERTIES DESCRIPTION "LibXML2 is an XML parser required by mp3tunes." URL "http://www.xmlsoft.org" TYPE OPTIONAL ) find_package(OpenSSL) find_package(Libgcrypt) if ( OPENSSL_FOUND OR LIBGCRYPT_FOUND ) set (_mp3tunes_crypto TRUE ) else () message( SEND_ERROR "Building with mp3tunes support REQUIRES either OpenSSL or GNU Libgcrypt" ) endif () set_package_properties( OpenSSL PROPERTIES DESCRIPTION "OpenSSL or GNU Libgcrypt provides cryptographic functions required by mp3tunes." URL "http://www.openssl.org/ or http://www.gnupg.org/download/#libgcrypt" TYPE OPTIONAL ) set_package_properties( Libgcrypt PROPERTIES DESCRIPTION "OpenSSL or GNU Libgcrypt provides cryptographic functions required by mp3tunes." URL "http://www.openssl.org/ or http://www.gnupg.org/download/#libgcrypt" TYPE OPTIONAL ) find_package(Loudmouth) set_package_properties( Loudmouth PROPERTIES DESCRIPTION "Loudmouth is the communication backend needed by mp3tunes for syncing." URL "http://www.loudmouth-project.org" TYPE OPTIONAL ) include(CheckQtGlib) set_package_properties( QT5_GLIB PROPERTIES DESCRIPTION "Qt5 must be compiled with glib support for mp3tunes" URL "http://www.trolltech.com" TYPE OPTIONAL ) endif() if( WITH_IPOD OR WITH_MP3Tunes ) pkg_search_module( GOBJECT REQUIRED gobject-2.0 ) set_package_properties( GOBJECT PROPERTIES DESCRIPTION "Required by libgpod and mp3tunes." URL "http://www.gtk.org" TYPE OPTIONAL ) pkg_search_module( GLIB2 glib-2.0 ) set_package_properties( GLIB2 PROPERTIES DESCRIPTION "Required by libgpod and mp3tunes" URL "http://www.gtk.org" TYPE OPTIONAL ) endif() find_program( CLAMZ_FOUND clamz PATH ) set_package_properties( CLAMZ PROPERTIES DESCRIPTION "Optional requirement to download songs from the Amazon MP3 store. Highly recommended on Linux, as the official downloader from Amazon is quite broken on many systems." URL "https://code.google.com/p/clamz/" TYPE OPTIONAL ) find_package(PythonInterp) set_package_properties( PYTHON PROPERTIES DESCRIPTION "Required for generating the autocompletion file for the script console" URL "https://www.python.org" TYPE OPTIONAL ) find_package(FFTW3 REQUIRED) if( BUILD_TESTING AND NOT WIN32 ) enable_testing() add_subdirectory( tests ) endif() add_subdirectory( src ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) #Do not remove or modify these. The release script substitutes in for these #comments with appropriate doc and translation directories. #PO_SUBDIR #DOC_SUBDIR endif() if( WITH_UTILITIES ) add_subdirectory( utilities ) endif() if( WITH_PLAYGROUND ) add_subdirectory( playground ) message(STATUS "Included playground subdirectory in configuration") endif() include(CTest) diff --git a/images/icons/CMakeLists.txt b/images/icons/CMakeLists.txt index 34d58200f9..3f8028f24d 100644 --- a/images/icons/CMakeLists.txt +++ b/images/icons/CMakeLists.txt @@ -1,278 +1,273 @@ ########### install files ############### ecm_install_icons(ICONS 128-status-audio-volume-high-amarok.png 128-status-audio-volume-low-amarok.png 128-status-audio-volume-medium-amarok.png 128-status-audio-volume-muted-amarok.png 16-actions-amarok_artist.png 16-actions-amarok_cart_add.png 16-actions-amarok_cart_remove.png 16-actions-amarok_cart_view.png 16-actions-amarok_change_language.png 16-actions-amarok_clock.png 16-actions-amarok_lyrics.png 16-actions-amarok_playcount.png 16-actions-amarok_playlist.png 16-actions-amarok_playlist_refresh.png 16-actions-amarok_scripts.png 16-actions-amarok_track.png 16-actions-collection-rescan-amarok.png 16-actions-download-amarok.png 16-actions-dynamic-amarok.png 16-actions-favorite-genres-amarok.png 16-actions-filename-album-amarok.png 16-actions-filename-artist-amarok.png 16-actions-filename-bpm-amarok.png 16-actions-filename-comment-amarok.png 16-actions-filename-composer-amarok.png 16-actions-filename-dash-amarok.png 16-actions-filename-discnumber-amarok.png 16-actions-filename-dot-amarok.png 16-actions-filename-filetype-amarok.png 16-actions-filename-genre-amarok.png 16-actions-filename-ignore-amarok.png 16-actions-filename-initial-amarok.png 16-actions-filename-last-played.png 16-actions-filename-slash-amarok.png 16-actions-filename-space-amarok.png 16-actions-filename-title-amarok.png 16-actions-filename-track-amarok.png 16-actions-filename-underscore-amarok.png 16-actions-filename-year-amarok.png 16-actions-label-amarok.png 16-actions-lastfm-mix-radio-amarok.png 16-actions-lastfm-neighbour-radio-amarok.png 16-actions-lastfm-personal-radio-amarok.png 16-actions-lastfm-recommended-radio-amarok.png 16-actions-lastfm-tag-amarok.png 16-actions-love-amarok.png 16-actions-media-album-cover-manager-amarok.png 16-actions-media-album-repeat-amarok.png 16-actions-media-playlist-repeat-amarok.png 16-actions-media-random-albums-amarok.png 16-actions-media-random-tracks-amarok.png 16-actions-media-repeat-album-amarok.png 16-actions-media-repeat-playlist-amarok.png 16-actions-media-repeat-track-amarok.png 16-actions-media-show-active-track-amarok.png 16-actions-media-standard-track-progression-amarok.png 16-actions-media-track-add-amarok.png 16-actions-media-track-edit-amarok.png 16-actions-media-track-queue-amarok.png 16-actions-media-track-remove-amarok.png 16-actions-music-amarok.png 16-actions-playlist-generator.png 16-actions-podcast-amarok.png 16-actions-preferences-indicator-amarok.png 16-actions-preferences-media-playback-amarok.png 16-actions-preferences-multimedia-player-amarok.png 16-actions-preferences-view-amarok.png 16-actions-remove-amarok.png 16-actions-view-importers-banshee-amarok.png 16-actions-view-importers-clementine-amarok.png 16-actions-view-importers-rhythmbox-amarok.png 16-actions-view-services-amazon-amarok.png 16-actions-view-services-ampache-amarok.png 16-actions-view-services-gpodder-amarok.png 16-actions-view-services-jamendo-amarok.png 16-actions-view-services-lastfm-amarok.png 16-actions-view-services-librivox-amarok.png 16-actions-view-services-magnatune-amarok.png 16-actions-view-services-mp3tunes-amarok.png 16-actions-view-services-opml-amarok.png 16-actions-view-services-scripted-amarok.png 22-actions-amarok_artist.png 22-actions-amarok_cart_add.png 22-actions-amarok_cart_remove.png 22-actions-amarok_cart_view.png 22-actions-amarok_change_language.png 22-actions-amarok_clock.png 22-actions-amarok_lyrics.png 22-actions-amarok_playcount.png 22-actions-amarok_playlist.png 22-actions-amarok_playlist_refresh.png 22-actions-amarok_scripts.png 22-actions-amarok_track.png 22-actions-collection-rescan-amarok.png 22-actions-download-amarok.png 22-actions-dynamic-amarok.png 22-actions-filename-bpm-amarok.png 22-actions-internet-amarok.png 22-actions-love-amarok.png 22-actions-media-album-cover-manager-amarok.png 22-actions-media-album-repeat-amarok.png 22-actions-media-playlist-repeat-amarok.png 22-actions-media-random-albums-amarok.png 22-actions-media-random-tracks-amarok.png 22-actions-media-repeat-album-amarok.png 22-actions-media-repeat-playlist-amarok.png 22-actions-media-repeat-track-amarok.png 22-actions-media-show-active-track-amarok.png 22-actions-media-standard-track-progression-amarok.png 22-actions-media-track-add-amarok.png 22-actions-media-track-edit-amarok.png 22-actions-media-track-queue-amarok.png 22-actions-media-track-remove-amarok.png 22-actions-music-amarok.png 22-actions-playlist-generator.png 22-actions-podcast-amarok.png 22-actions-preferences-indicator-amarok.png 22-actions-preferences-media-playback-amarok.png 22-actions-preferences-multimedia-player-amarok.png 22-actions-preferences-view-amarok.png 22-actions-remove-amarok.png 22-actions-view-importers-banshee-amarok.png 22-actions-view-importers-clementine-amarok.png 22-actions-view-importers-rhythmbox-amarok.png 22-actions-view-services-amazon-amarok.png 22-actions-view-services-gpodder-amarok.png 22-actions-view-services-jamendo-amarok.png 22-actions-view-services-lastfm-amarok.png 22-actions-view-services-librivox-amarok.png 22-actions-view-services-magnatune-amarok.png 22-actions-view-services-mp3tunes-amarok.png 22-actions-view-services-opml-amarok.png 22-actions-view-services-scripted-amarok.png 24-actions-lastfm-my-friends-amarok.png 24-actions-lastfm-my-neighbours-amarok.png 24-actions-lastfm-my-tags-amarok.png 32-actions-amarok_artist.png 32-actions-amarok_cart_add.png 32-actions-amarok_cart_remove.png 32-actions-amarok_cart_view.png 32-actions-amarok_change_language.png 32-actions-amarok_clock.png 32-actions-amarok_lyrics.png 32-actions-amarok_playcount.png 32-actions-amarok_playlist.png 32-actions-amarok_playlist_refresh.png 32-actions-amarok_scripts.png 32-actions-amarok_track.png 32-actions-audioscrobbler.png 32-actions-collection-rescan-amarok.png 32-actions-download-amarok.png 32-actions-dynamic-amarok.png 32-actions-filename-bpm-amarok.png 32-actions-love-amarok.png 32-actions-media-album-cover-manager-amarok.png 32-actions-media-album-cover.png 32-actions-media-album-repeat-amarok.png 32-actions-media-album-track.png 32-actions-media-playlist-repeat-amarok.png 32-actions-media-random-albums-amarok.png 32-actions-media-random-tracks-amarok.png 32-actions-media-repeat-album-amarok.png 32-actions-media-repeat-playlist-amarok.png 32-actions-media-repeat-track-amarok.png 32-actions-media-show-active-track-amarok.png 32-actions-media-standard-track-progression-amarok.png 32-actions-media-track-add-amarok.png 32-actions-media-track-edit-amarok.png 32-actions-media-track-queue-amarok.png 32-actions-media-track-remove-amarok.png 32-actions-music-amarok.png 32-actions-playlist-generator.png 32-actions-podcast-amarok.png 32-actions-preferences-indicator-amarok.png 32-actions-preferences-media-playback-amarok.png 32-actions-preferences-multimedia-player-amarok.png 32-actions-preferences-view-amarok.png 32-actions-remove-amarok.png 32-actions-view-importers-banshee-amarok.png 32-actions-view-importers-clementine-amarok.png 32-actions-view-importers-rhythmbox-amarok.png 32-actions-view-services-amazon-amarok.png 32-actions-view-services-ampache-amarok.png 32-actions-view-services-gpodder-amarok.png 32-actions-view-services-jamendo-amarok.png 32-actions-view-services-lastfm-amarok.png 32-actions-view-services-magnatune-amarok.png 32-actions-view-services-mp3tunes-amarok.png 32-actions-view-services-opml-amarok.png 32-actions-view-services-scripted-amarok.png 48-actions-amarok_artist.png 48-actions-amarok_cart_add.png 48-actions-amarok_cart_remove.png 48-actions-amarok_cart_view.png 48-actions-amarok_change_language.png 48-actions-amarok_clock.png - 48-actions-amarok_lyrics.png 48-actions-amarok_playcount.png 48-actions-amarok_playlist.png 48-actions-amarok_playlist_refresh.png 48-actions-amarok_scripts.png 48-actions-amarok_track.png 48-actions-collection-rescan-amarok.png - 48-actions-current-track-amarok.png 48-actions-download-amarok.png 48-actions-dynamic-amarok.png 48-actions-filename-album-amarok.png 48-actions-filename-and-amarok.png 48-actions-filename-artist-amarok.png 48-actions-filename-bpm-amarok.png 48-actions-filename-comment-amarok.png 48-actions-filename-composer-amarok.png 48-actions-filename-dash-amarok.png 48-actions-filename-discnumber-amarok.png 48-actions-filename-divider.png 48-actions-filename-dot-amarok.png 48-actions-filename-filetype-amarok.png 48-actions-filename-genre-amarok.png 48-actions-filename-group-length.png 48-actions-filename-group-tracks.png 48-actions-filename-ignore-amarok.png 48-actions-filename-initial-amarok.png 48-actions-filename-last-played.png 48-actions-filename-moodbar.png 48-actions-filename-sample-rate.png 48-actions-filename-slash-amarok.png 48-actions-filename-space-amarok.png 48-actions-filename-title-amarok.png 48-actions-filename-track-amarok.png 48-actions-filename-underscore-amarok.png 48-actions-filename-year-amarok.png 48-actions-info-amarok.png 48-actions-label-amarok.png 48-actions-love-amarok.png - 48-actions-media-album-cover-manager-amarok.png 48-actions-media-album-repeat-amarok.png 48-actions-media-playlist-repeat-amarok.png 48-actions-media-random-albums-amarok.png 48-actions-media-random-tracks-amarok.png 48-actions-media-repeat-album-amarok.png 48-actions-media-repeat-playlist-amarok.png 48-actions-media-repeat-track-amarok.png 48-actions-media-show-active-track-amarok.png 48-actions-media-standard-track-progression-amarok.png 48-actions-media-track-add-amarok.png 48-actions-media-track-edit-amarok.png 48-actions-media-track-queue-amarok.png 48-actions-media-track-remove-amarok.png 48-actions-music-amarok.png - 48-actions-photos-amarok.png 48-actions-playlist-generator.png 48-actions-podcast-amarok.png 48-actions-preferences-indicator-amarok.png 48-actions-preferences-media-playback-amarok.png 48-actions-preferences-multimedia-player-amarok.png 48-actions-preferences-view-amarok.png 48-actions-remove-amarok.png 48-actions-similarartists-amarok.png 48-actions-upcomingevents-amarok.png 48-actions-videoclip-amarok.png 48-actions-view-importers-banshee-amarok.png 48-actions-view-importers-clementine-amarok.png 48-actions-view-importers-rhythmbox-amarok.png - 48-actions-view-media-analyzer-amarok.png 48-actions-view-services-amazon-amarok.png 48-actions-view-services-ampache-amarok.png 48-actions-view-services-gpodder-amarok.png 48-actions-view-services-jamendo-amarok.png 48-actions-view-services-lastfm-amarok.png 48-actions-view-services-magnatune-amarok.png 48-actions-view-services-mp3tunes-amarok.png DESTINATION ${KDE_INSTALL_DATADIR}/amarok/icons THEME hicolor ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1583d04327..e2f5135874 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,973 +1,978 @@ # Improves speed of string concatenation add_definitions(-DQT_USE_FAST_CONCATENATION) add_definitions(-DQT_USE_FAST_OPERATOR_PLUS) if(NOT MSVC) add_definitions(-DQT_STRICT_ITERATORS) endif() if(APPLE) set(mac_SRCS app_mac.cpp mac/GrowlInterface.cpp ) # Notification Center Appeared in 10.8, or Darwin 12 if( CMAKE_SYSTEM_VERSION VERSION_GREATER "11.9.9") list(APPEND mac_SRCS mac/MacSystemNotify.mm) add_definitions(-DHAVE_NOTIFICATION_CENTER) endif() include_directories ( services/lastfm/ ) set( MAC_FILES_DIR ${CMAKE_SOURCE_DIR}/src/mac ) endif() include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) add_subdirectory( core ) add_subdirectory( core-impl/collections ) add_subdirectory( core-impl/storage/sql ) add_subdirectory( context ) add_subdirectory( services ) add_subdirectory( scripting/scripts ) add_subdirectory( aboutdialog/libattica-ocsclient ) add_subdirectory( transcoding ) add_subdirectory( kconf_update ) add_subdirectory( importers ) ##################################################################### # PROXYCOLLECTION ##################################################################### set(aggregatecollection_SRCS core-impl/collections/aggregate/AggregateCollection.cpp core-impl/collections/aggregate/AggregateMeta.cpp core-impl/collections/aggregate/AggregateQueryMaker.cpp ) ##################################################################### # MEDIADEVICEFRAMEWORK ##################################################################### set(libmediadeviceframework_SRCS core-impl/collections/mediadevicecollection/MediaDeviceCollection.cpp core-impl/collections/mediadevicecollection/MediaDeviceCollectionLocation.cpp core-impl/collections/mediadevicecollection/MediaDeviceMeta.cpp core-impl/collections/mediadevicecollection/MediaDeviceTrackEditor.cpp core-impl/collections/mediadevicecollection/handler/MediaDeviceHandler.cpp core-impl/collections/mediadevicecollection/handler/MediaDeviceHandlerCapability.cpp core-impl/collections/mediadevicecollection/handler/capabilities/ArtworkCapability.cpp core-impl/collections/mediadevicecollection/handler/capabilities/PlaylistCapability.cpp core-impl/collections/mediadevicecollection/handler/capabilities/PodcastCapability.cpp core-impl/collections/mediadevicecollection/handler/capabilities/ReadCapability.cpp core-impl/collections/mediadevicecollection/handler/capabilities/WriteCapability.cpp core-impl/collections/mediadevicecollection/playlist/MediaDevicePlaylist.cpp core-impl/collections/mediadevicecollection/playlist/MediaDeviceUserPlaylistProvider.cpp core-impl/collections/mediadevicecollection/podcast/MediaDevicePodcastProvider.cpp core-impl/collections/mediadevicecollection/support/ConnectionAssistant.cpp core-impl/collections/mediadevicecollection/support/MediaDeviceInfo.cpp ) ##################################################################### # SERVICEFRAMEWORK ##################################################################### set(libserviceframework_SRCS services/DynamicServiceQueryMaker.cpp services/InfoParserBase.cpp services/ServiceAlbumCoverDownloader.cpp services/ServiceBase.cpp services/ServiceCapabilities.cpp services/ServiceCollection.cpp services/ServiceCollectionLocation.cpp services/ServiceCollectionTreeView.cpp services/ServiceMetaBase.cpp services/ServicePluginManager.cpp services/ServiceSqlCollection.cpp services/ServiceSqlQueryMaker.cpp services/ServiceSqlRegistry.cpp ) ##################################################################### # SERVICEBROWSER ##################################################################### set(libservicebrowser_SRCS browsers/servicebrowser/ServiceBrowser.cpp ) ##################################################################### # AMAROKURL ##################################################################### set(libamarokurl_SRCS amarokurls/AmarokUrl.cpp amarokurls/AmarokUrlAction.cpp amarokurls/AmarokUrlHandler.cpp amarokurls/BookmarkCurrentButton.cpp amarokurls/ContextUrlGenerator.cpp amarokurls/ContextUrlRunner.cpp amarokurls/NavigationUrlRunner.cpp amarokurls/NavigationUrlGenerator.cpp amarokurls/PlayUrlRunner.cpp amarokurls/PlayUrlGenerator.cpp amarokurls/BookmarkManager.cpp amarokurls/BookmarkManagerWidget.cpp amarokurls/BookmarkGroup.cpp amarokurls/BookmarkModel.cpp amarokurls/BookmarkTreeView.cpp amarokurls/BookmarkMetaActions.cpp ) ##################################################################### # SCRIPTABLESERVICE ##################################################################### set(libscriptableservice_SRCS services/scriptable/ScriptableService.cpp services/scriptable/ScriptableServiceCollection.cpp services/scriptable/ScriptableServiceCollectionTreeModel.cpp services/scriptable/ScriptableServiceInfoParser.cpp services/scriptable/ScriptableServiceManager.cpp services/scriptable/ScriptableServiceMeta.cpp services/scriptable/ScriptableServiceQueryMaker.cpp ) ##################################################################### # CONFIGDIALOG ##################################################################### set(libconfigdialog_SRCS configdialog/ConfigDialog.cpp configdialog/ConfigDialogBase.cpp configdialog/dialogs/CollectionConfig.cpp configdialog/dialogs/ExcludedLabelsDialog.cpp configdialog/dialogs/GeneralConfig.cpp configdialog/dialogs/MetadataConfig.cpp configdialog/dialogs/NotificationsConfig.cpp configdialog/dialogs/PlaybackConfig.cpp configdialog/dialogs/PluginsConfig.cpp configdialog/dialogs/ScriptsConfig.cpp configdialog/dialogs/ScriptSelector.cpp configdialog/dialogs/DatabaseConfig.cpp ) ki18n_wrap_ui(libconfigdialog_SRCS configdialog/dialogs/CollectionConfig.ui configdialog/dialogs/GeneralConfig.ui configdialog/dialogs/MetadataConfig.ui configdialog/dialogs/ExcludedLabelsDialog.ui configdialog/dialogs/NotificationsConfig.ui configdialog/dialogs/PlaybackConfig.ui configdialog/dialogs/DatabaseConfig.ui configdialog/dialogs/ScriptsConfig.ui ) set(libbrowserframework_SRCS browsers/BrowserBreadcrumbItem.cpp browsers/BrowserBreadcrumbWidget.cpp browsers/BrowserCategory.cpp browsers/BrowserCategoryList.cpp browsers/BrowserCategoryListModel.cpp browsers/BrowserCategoryListSortFilterProxyModel.cpp browsers/BrowserDock.cpp browsers/BrowserMessageArea.cpp browsers/CollectionSortFilterProxyModel.cpp browsers/CollectionTreeItem.cpp browsers/CollectionTreeItemModel.cpp browsers/CollectionTreeItemModelBase.cpp browsers/CollectionTreeView.cpp browsers/InfoProxy.cpp browsers/SingleCollectionTreeItemModel.cpp ) ##################################################################### # COLLECTIONBROWSER ##################################################################### set(libcollectionbrowser_SRCS browsers/collectionbrowser/CollectionBrowserTreeView.cpp browsers/collectionbrowser/CollectionWidget.cpp ) ##################################################################### # SYNCHRONIZATION ##################################################################### set(libsynchronization_SRCS synchronization/MasterSlaveSynchronizationJob.cpp synchronization/OneWaySynchronizationJob.cpp synchronization/SynchronizationBaseJob.cpp synchronization/UnionJob.cpp ) ##################################################################### # STATUSBAR ##################################################################### set(libstatusbar_SRCS statusbar/ProgressBar.cpp statusbar/KJobProgressBar.cpp statusbar/NetworkProgressBar.cpp statusbar/CompoundProgressBar.cpp statusbar/PopupWidget.cpp statusbar/LongMessageWidget.cpp ) ##################################################################### # META ##################################################################### set(libmetaimpl_SRCS core-impl/playlists/providers/user/UserPlaylistProvider.cpp core-impl/playlists/types/file/asx/ASXPlaylist.cpp core-impl/playlists/types/file/m3u/M3UPlaylist.cpp core-impl/playlists/types/file/pls/PLSPlaylist.cpp core-impl/playlists/types/file/PlaylistFileLoaderJob.cpp core-impl/playlists/types/file/PlaylistFileSupport.cpp core-impl/playlists/types/file/xspf/XSPFPlaylist.cpp core-impl/capabilities/AlbumActionsCapability.cpp core-impl/capabilities/timecode/TimecodeBoundedPlaybackCapability.cpp core-impl/capabilities/timecode/TimecodeLoadCapability.cpp core-impl/capabilities/timecode/TimecodeWriteCapability.cpp core-impl/capabilities/multisource/MultiSourceCapabilityImpl.cpp core-impl/meta/file/File.cpp core-impl/meta/file/FileTrackProvider.cpp core-impl/meta/multi/MultiTrack.cpp core-impl/meta/cue/CueFileSupport.cpp core-impl/meta/proxy/MetaProxy.cpp core-impl/meta/proxy/MetaProxyWorker.cpp core-impl/meta/stream/Stream.cpp core-impl/playlists/types/file/PlaylistFile.cpp core-impl/support/PersistentStatisticsStore.cpp core-impl/support/TagStatisticsStore.cpp core-impl/support/UrlStatisticsStore.cpp ) ##################################################################### # COLLECTION ##################################################################### set(collection_SRCS core-impl/collections/support/jobs/WriteTagsJob.cpp core-impl/collections/support/ArtistHelper.cpp core-impl/collections/support/CollectionManager.cpp core-impl/collections/support/CollectionLocationDelegateImpl.cpp core-impl/collections/support/MemoryCustomValue.cpp core-impl/collections/support/MemoryFilter.cpp core-impl/collections/support/MemoryMatcher.cpp core-impl/collections/support/MemoryMeta.cpp core-impl/collections/support/MemoryQueryMaker.cpp core-impl/collections/support/MemoryQueryMakerInternal.cpp core-impl/collections/support/MemoryQueryMakerHelper.cpp core-impl/collections/support/TrashCollectionLocation.cpp core-impl/collections/support/XmlQueryReader.cpp core-impl/collections/support/FileCollectionLocation.cpp core-impl/collections/support/Expression.cpp core-impl/collections/support/TextualQueryFilter.cpp ) ##################################################################### # STORAGE ##################################################################### set(storage_SRCS core-impl/storage/StorageManager.cpp ) ##################################################################### # SCANNER ##################################################################### set( scanner_SRCS scanner/GenericScanManager.cpp scanner/GenericScannerJob.cpp scanner/AbstractDirectoryWatcher.cpp scanner/AbstractScanResultProcessor.cpp ) ##################################################################### # CONTEXT ##################################################################### set( libcontextview_SRCS context/AmarokContextPackageStructure.cpp context/AppletLoader.cpp context/AppletModel.cpp context/ContextDock.cpp context/ContextView.cpp context/LyricsManager.cpp ) ##################################################################### # PODCASTS ##################################################################### set(libpodcasts_SRCS core-impl/podcasts/sql/SqlPodcastMeta.cpp core-impl/podcasts/sql/SqlPodcastProvider.cpp core-impl/podcasts/sql/PodcastSettingsDialog.cpp core-impl/podcasts/sql/PodcastFilenameLayoutConfigDialog.cpp ) ##################################################################### # PLAYLISTBROWSER ##################################################################### set(libplaylistbrowser_SRCS browsers/playlistbrowser/APGCategory.cpp browsers/playlistbrowser/DynamicCategory.cpp browsers/playlistbrowser/DynamicBiasDelegate.cpp browsers/playlistbrowser/DynamicBiasDialog.cpp browsers/playlistbrowser/DynamicView.cpp browsers/playlistbrowser/PlaylistBrowserFilterProxy.cpp browsers/playlistbrowser/PlaylistBrowserModel.cpp browsers/playlistbrowser/PlaylistBrowserCategory.cpp browsers/playlistbrowser/QtGroupingProxy.cpp browsers/playlistbrowser/PlaylistBrowser.cpp browsers/playlistbrowser/PlaylistBrowserView.cpp browsers/playlistbrowser/UserPlaylistCategory.cpp browsers/playlistbrowser/PlaylistsInFoldersProxy.cpp browsers/playlistbrowser/PlaylistsByProviderProxy.cpp browsers/playlistbrowser/PodcastModel.cpp browsers/playlistbrowser/PodcastCategory.cpp browsers/playlistbrowser/UserPlaylistModel.cpp ) ##################################################################### # PLAYLISTMANAGER ##################################################################### set(libplaylistmanager_SRCS playlistmanager/PlaylistManager.cpp playlistmanager/file/PlaylistFileProvider.cpp playlistmanager/file/KConfigSyncRelStore.cpp playlistmanager/sql/SqlUserPlaylistProvider.cpp playlistmanager/sql/SqlPlaylist.cpp playlistmanager/sql/SqlPlaylistGroup.cpp playlistmanager/SyncedPlaylist.cpp playlistmanager/SyncedPodcast.cpp playlistmanager/SyncRelationStorage.cpp ) ##################################################################### # PLAYLIST ##################################################################### set(libplaylist_SRCS playlist/PlaylistActions.cpp playlist/PlaylistBreadcrumbItem.cpp playlist/PlaylistBreadcrumbItemSortButton.cpp playlist/PlaylistBreadcrumbLevel.cpp playlist/PlaylistDefines.cpp playlist/PlaylistController.cpp playlist/PlaylistInfoWidget.cpp playlist/PlaylistItem.cpp playlist/PlaylistModel.cpp playlist/PlaylistModelStack.cpp playlist/PlaylistRestorer.cpp playlist/PlaylistQueueEditor.cpp playlist/PlaylistSortWidget.cpp playlist/PlaylistViewUrlGenerator.cpp playlist/PlaylistViewUrlRunner.cpp playlist/PlaylistDock.cpp playlist/PlaylistToolBar.cpp playlist/ProgressiveSearchWidget.cpp playlist/UndoCommands.cpp playlist/layouts/LayoutEditDialog.cpp playlist/layouts/LayoutEditWidget.cpp playlist/layouts/LayoutConfigAction.cpp playlist/layouts/LayoutItemConfig.cpp playlist/layouts/LayoutManager.cpp playlist/layouts/PlaylistLayoutEditDialog.cpp playlist/navigators/AlbumNavigator.cpp playlist/navigators/DynamicTrackNavigator.cpp playlist/navigators/FavoredRandomTrackNavigator.cpp playlist/navigators/NavigatorConfigAction.cpp playlist/navigators/NonlinearTrackNavigator.cpp playlist/navigators/RandomAlbumNavigator.cpp playlist/navigators/RandomTrackNavigator.cpp playlist/navigators/RepeatAlbumNavigator.cpp playlist/navigators/RepeatTrackNavigator.cpp playlist/navigators/StandardTrackNavigator.cpp playlist/navigators/TrackNavigator.cpp playlist/view/PlaylistViewCommon.cpp playlist/view/listview/InlineEditorWidget.cpp playlist/view/listview/PrettyItemDelegate.cpp playlist/view/listview/PrettyListView.cpp playlist/view/listview/SourceSelectionPopup.cpp playlist/proxymodels/GroupingProxy.cpp playlist/proxymodels/ProxyBase.cpp playlist/proxymodels/SortAlgorithms.cpp playlist/proxymodels/SortFilterProxy.cpp playlist/proxymodels/SortScheme.cpp playlist/proxymodels/SearchProxy.cpp ) ki18n_wrap_ui(libplaylist_SRCS playlist/PlaylistQueueEditor.ui ) ##################################################################### # DYNAMIC ##################################################################### set(libdynamic_SRCS dynamic/TrackSet.cpp dynamic/BiasFactory.cpp dynamic/BiasedPlaylist.cpp dynamic/BiasSolver.cpp dynamic/DynamicPlaylist.cpp dynamic/DynamicModel.cpp # biases dynamic/Bias.cpp dynamic/biases/AlbumPlayBias.cpp dynamic/biases/EchoNestBias.cpp dynamic/biases/IfElseBias.cpp dynamic/biases/PartBias.cpp dynamic/biases/QuizPlayBias.cpp dynamic/biases/TagMatchBias.cpp dynamic/biases/SearchQueryBias.cpp ) ##################################################################### # DBUS ##################################################################### set(dbus_SRCS dbus/mpris1/RootHandler.cpp dbus/mpris1/PlayerHandler.cpp dbus/mpris1/TrackListHandler.cpp dbus/mpris2/DBusAbstractAdaptor.cpp dbus/mpris2/Mpris2.cpp dbus/mpris2/MediaPlayer2.cpp dbus/mpris2/MediaPlayer2Player.cpp dbus/mpris2/MediaPlayer2AmarokExtensions.cpp dbus/mpris2/DBusAmarokApp.cpp dbus/CollectionDBusHandler.cpp dbus/DBusQueryHelper.cpp ) ##################################################################### # SCRIPTING INTERFACE ##################################################################### set(scriptengine_SRCS scripting/scriptengine/AmarokBookmarkScript.cpp scripting/scriptengine/AmarokCollectionScript.cpp scripting/scriptengine/AmarokCollectionViewScript.cpp scripting/scriptengine/AmarokEngineScript.cpp scripting/scriptengine/AmarokEqualizerScript.cpp scripting/scriptengine/AmarokInfoScript.cpp scripting/scriptengine/AmarokKNotifyScript.cpp scripting/scriptengine/AmarokLyricsScript.cpp scripting/scriptengine/AmarokNetworkScript.cpp scripting/scriptengine/AmarokOSDScript.cpp scripting/scriptengine/AmarokPlaylistManagerScript.cpp scripting/scriptengine/AmarokPlaylistScript.cpp scripting/scriptengine/AmarokScript.cpp scripting/scriptengine/AmarokScriptConfig.cpp scripting/scriptengine/AmarokScriptableServiceScript.cpp scripting/scriptengine/AmarokServicePluginManagerScript.cpp scripting/scriptengine/AmarokStatusbarScript.cpp scripting/scriptengine/AmarokStreamItemScript.cpp scripting/scriptengine/AmarokWindowScript.cpp scripting/scriptengine/AmarokScriptXml.cpp scripting/scriptengine/ScriptImporter.cpp scripting/scriptengine/ScriptingDefines.cpp scripting/scriptengine/exporters/CollectionTypeExporter.cpp scripting/scriptengine/exporters/MetaTypeExporter.cpp scripting/scriptengine/exporters/PlaylistExporter.cpp scripting/scriptengine/exporters/PlaylistProviderExporter.cpp scripting/scriptengine/exporters/QueryMakerExporter.cpp scripting/scriptengine/exporters/ScriptableBiasExporter.cpp ) set(scriptconsole_SRCS scripting/scriptconsole/CompletionModel.cpp scripting/scriptconsole/ScriptConsole.cpp scripting/scriptconsole/ScriptEditorDocument.cpp scripting/scriptconsole/ScriptConsoleItem.cpp ) if (PYTHONINTERP_FOUND) execute_process(COMMAND "${PYTHON_EXECUTABLE}" ${CMAKE_SOURCE_DIR}/src/scripting/scriptengine/PHAACG2.py ${CMAKE_SOURCE_DIR}/src/scripting/scriptengine ${CMAKE_BINARY_DIR}/scriptconsole) install(FILES ${CMAKE_BINARY_DIR}/scriptconsole/AutoComplete.txt DESTINATION ${KDE_INSTALL_DATADIR}/amarok/scriptconsole) endif() ##################################################################### # PLAYLIST GENERATOR ##################################################################### set(apg_SRCS playlistgenerator/Constraint.cpp playlistgenerator/ConstraintGroup.cpp playlistgenerator/ConstraintFactory.cpp playlistgenerator/ConstraintNode.cpp playlistgenerator/ConstraintSolver.cpp playlistgenerator/Preset.cpp playlistgenerator/PresetEditDialog.cpp playlistgenerator/PresetModel.cpp playlistgenerator/TreeController.cpp playlistgenerator/TreeModel.cpp playlistgenerator/constraints/Checkpoint.cpp playlistgenerator/constraints/Matching.cpp playlistgenerator/constraints/PlaylistDuration.cpp playlistgenerator/constraints/PlaylistFileSize.cpp playlistgenerator/constraints/PlaylistLength.cpp playlistgenerator/constraints/PreventDuplicates.cpp playlistgenerator/constraints/TagMatch.cpp playlistgenerator/constraints/TagMatchSupport.cpp playlistgenerator/constraints/TrackSpreader.cpp ) ki18n_wrap_ui(apg_SRCS playlistgenerator/ConstraintGroupEditWidget.ui playlistgenerator/PresetEditDialog.ui playlistgenerator/constraints/CheckpointEditWidget.ui playlistgenerator/constraints/PlaylistDurationEditWidget.ui playlistgenerator/constraints/PlaylistFileSizeEditWidget.ui playlistgenerator/constraints/PlaylistLengthEditWidget.ui playlistgenerator/constraints/PreventDuplicatesEditWidget.ui playlistgenerator/constraints/TagMatchEditWidget.ui ) ##################################################################### # NETWORK ACCESS ##################################################################### set(network_access_SRCS network/NetworkAccessManagerProxy.cpp ) if( CMAKE_BUILD_TYPE_TOLOWER MATCHES debug ) set(network_access_SRCS ${network_access_SRCS} network/NetworkAccessViewer.cpp ) ki18n_wrap_ui(network_access_SRCS network/NetworkRequests.ui ) endif() ##################################################################### # STATISTICS SYNCHRONIZATION ##################################################################### set( statsyncing_SRCS statsyncing/Config.cpp statsyncing/Controller.cpp statsyncing/Options.cpp statsyncing/Process.cpp statsyncing/Provider.cpp statsyncing/ProviderFactory.cpp statsyncing/ScrobblingService.cpp statsyncing/SimpleTrack.cpp statsyncing/SimpleWritableTrack.cpp statsyncing/Track.cpp statsyncing/TrackTuple.cpp statsyncing/collection/CollectionProvider.cpp statsyncing/collection/CollectionTrack.cpp statsyncing/jobs/MatchTracksJob.cpp statsyncing/jobs/SynchronizeTracksJob.cpp statsyncing/models/CommonModel.cpp statsyncing/models/MatchedTracksModel.cpp statsyncing/models/ProvidersModel.cpp statsyncing/models/SingleTracksModel.cpp statsyncing/ui/ChooseProvidersPage.cpp statsyncing/ui/CreateProviderDialog.cpp statsyncing/ui/ConfigureProviderDialog.cpp statsyncing/ui/MatchedTracksPage.cpp statsyncing/ui/TrackDelegate.cpp ) ki18n_wrap_ui( statsyncing_SRCS statsyncing/ui/ChooseProvidersPage.ui statsyncing/ui/MatchedTracksPage.ui ) ##################################################################### # STATISTICS IMPORTERS ##################################################################### set( importers_SRCS importers/ImporterManager.cpp importers/ImporterProvider.cpp importers/ImporterSqlConnection.cpp importers/SimpleImporterConfigWidget.cpp ) ##################################################################### # LIBAMAROK ##################################################################### set(amaroklib_LIB_SRCS ${libscriptableservice_SRCS} ${libbrowserframework_SRCS} ${libcontextview_SRCS} ${libcollectionbrowser_SRCS} ${libconfigdialog_SRCS} ${libplaylist_SRCS} ${aggregatecollection_SRCS} ${libpodcasts_SRCS} ${libmediadeviceframework_SRCS} ${libserviceframework_SRCS} ${libservicebrowser_SRCS} ${libdynamic_SRCS} ${libmetaimpl_SRCS} ${apg_SRCS} ${collection_SRCS} ${storage_SRCS} ${scanner_SRCS} ${mac_SRCS} ${network_access_SRCS} ${libplaylistbrowser_SRCS} ${libplaylistmanager_SRCS} ${dbus_SRCS} ${scriptengine_SRCS} ${scriptconsole_SRCS} ${libstatusbar_SRCS} ${libamarokurl_SRCS} ${libsynchronization_SRCS} ${statsyncing_SRCS} ${importers_SRCS} core-impl/logger/ProxyLogger.cpp aboutdialog/AnimatedBarWidget.cpp aboutdialog/AnimatedWidget.cpp aboutdialog/ExtendedAboutDialog.cpp aboutdialog/FramedLabel.cpp aboutdialog/OcsData.cpp aboutdialog/OcsPersonItem.cpp aboutdialog/OcsPersonListWidget.cpp ActionClasses.cpp AmarokMimeData.cpp AmarokProcess.cpp App.cpp CaseConverter.cpp EngineController.cpp KNotificationBackend.cpp MainWindow.cpp MediaDeviceCache.cpp MediaDeviceMonitor.cpp PluginManager.cpp QStringx.cpp scripting/scriptmanager/ScriptManager.cpp scripting/scriptmanager/ScriptItem.cpp scripting/scriptmanager/ScriptUpdater.cpp SvgHandler.cpp SvgTinter.cpp TrayIcon.cpp core-impl/meta/timecode/TimecodeObserver.cpp core-impl/meta/timecode/TimecodeMeta.cpp core-impl/meta/timecode/TimecodeTrackProvider.cpp core-impl/support/TrackLoader.cpp covermanager/CoverCache.cpp covermanager/CoverFetcher.cpp covermanager/CoverFetchingActions.cpp covermanager/CoverFetchQueue.cpp covermanager/CoverFetchUnit.cpp covermanager/CoverFoundDialog.cpp covermanager/CoverManager.cpp covermanager/CoverViewDialog.cpp databaseimporter/SqlBatchImporter.cpp databaseimporter/SqlBatchImporterConfig.cpp dialogs/CollectionSetup.cpp dialogs/DatabaseImporterDialog.cpp dialogs/DiagnosticDialog.cpp dialogs/EditFilterDialog.cpp dialogs/EqualizerDialog.cpp dialogs/MusicBrainzTagger.cpp dialogs/OrganizeCollectionDialog.cpp dialogs/TrackOrganizer.cpp dialogs/TagDialog.cpp dialogs/TagGuesser.cpp dialogs/TagGuesserDialog.cpp dialogs/LabelListModel.cpp equalizer/EqualizerPresets.cpp browsers/filebrowser/DirPlaylistTrackFilterProxyModel.cpp browsers/filebrowser/FileBrowser.cpp browsers/filebrowser/FileView.cpp musicbrainz/MusicBrainzFinder.cpp musicbrainz/MusicBrainzTagsItem.cpp musicbrainz/MusicBrainzTagsModel.cpp musicbrainz/MusicBrainzTagsModelDelegate.cpp musicbrainz/MusicBrainzTagsView.cpp musicbrainz/MusicBrainzXmlParser.cpp OpmlOutline.cpp OpmlParser.cpp OpmlWriter.cpp PaletteHandler.cpp PopupDropperFactory.cpp playback/DelayedDoers.cpp playback/EqualizerController.cpp playback/Fadeouter.cpp playback/PowerManager.cpp statemanagement/ApplicationController.cpp statemanagement/DefaultApplicationController.cpp toolbar/CurrentTrackToolbar.cpp toolbar/SlimToolbar.cpp toolbar/VolumePopupButton.cpp toolbar/MainToolbar.cpp widgets/AlbumBreadcrumbWidget.cpp widgets/AmarokDockWidget.cpp widgets/AnimatedLabelStack.cpp widgets/BoxWidget.cpp widgets/BreadcrumbItemButton.cpp widgets/ClearSpinBox.cpp widgets/CoverLabel.cpp widgets/HintLineEdit.cpp widgets/kdatecombo.cpp widgets/TokenDropTarget.cpp widgets/EditDeleteComboBoxView.cpp widgets/EditDeleteDelegate.cpp widgets/ElidingButton.cpp widgets/FilenameLayoutWidget.cpp widgets/FlowLayout.cpp widgets/HorizontalDivider.cpp widgets/IconButton.cpp widgets/ComboBox.cpp widgets/LineEdit.cpp widgets/Osd.cpp widgets/TimeLabel.cpp widgets/PixmapViewer.cpp widgets/PlayPauseButton.cpp widgets/PrettyTreeView.cpp widgets/PrettyTreeDelegate.cpp widgets/ProgressWidget.cpp widgets/SearchWidget.cpp widgets/SliderWidget.cpp widgets/StarManager.cpp widgets/TokenPool.cpp widgets/Token.cpp widgets/TokenWithLayout.cpp widgets/VolumeDial.cpp widgets/TrackActionButton.cpp widgets/BookmarkTriangle.cpp widgets/BookmarkPopup.cpp widgets/TrackSelectWidget.cpp widgets/MetaQueryWidget.cpp GlobalCollectionActions.cpp GlobalCurrentTrackActions.cpp moodbar/MoodbarManager.cpp ) if( LIBLASTFM_FOUND ) set(amaroklib_LIB_SRCS ${amaroklib_LIB_SRCS} LastfmReadLabelCapability.cpp ) include_directories( ${LIBLASTFM_INCLUDE_DIR}/.. ${LIBLASTFM_INCLUDE_DIR}) set( EXTRA_LIBS ${LIBLASTFM_LIBRARY} ) endif() if( LIBOFA_FOUND AND AVCODEC_FOUND AND AVFORMAT_FOUND AND AVUTIL_FOUND ) add_definitions( ${AVCODEC_DEFINITIONS} ${AVFORMAT_DEFINITIONS} ${AVUTIL_DEFINITIONS} ) include_directories( ${AVCODEC_INCLUDE_DIRS} ${AVFORMAT_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS} ) set( EXTRA_LIBS ${EXTRA_LIBS} ${LIBOFA_LIBRARY} ${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} ) set( amaroklib_LIB_SRCS ${amaroklib_LIB_SRCS} musicbrainz/MusicDNSAudioDecoder.cpp musicbrainz/MusicDNSFinder.cpp musicbrainz/MusicDNSXmlParser.cpp ) endif() qt5_add_dbus_adaptor( AMAROK_MPRIS1_ADAPTOR_SRCS dbus/mpris1/org.freedesktop.MediaPlayer.root.xml dbus/mpris1/RootHandler.h Mpris1::RootHandler Mpris1RootAdaptor Mpris1RootAdaptor ) qt5_add_dbus_adaptor( AMAROK_MPRIS1_ADAPTOR_SRCS dbus/mpris1/org.freedesktop.MediaPlayer.player.xml dbus/mpris1/PlayerHandler.h Mpris1::PlayerHandler Mpris1PlayerAdaptor Mpris1PlayerAdaptor ) qt5_add_dbus_adaptor( AMAROK_MPRIS1_ADAPTOR_SRCS dbus/mpris1/org.freedesktop.MediaPlayer.tracklist.xml dbus/mpris1/TrackListHandler.h Mpris1::TrackListHandler Mpris1TrackListAdaptor Mpris1TrackListAdaptor ) qt5_add_dbus_adaptor( AMAROK_MPRIS1_ADAPTOR_SRCS dbus/org.kde.amarok.App.xml dbus/mpris1/RootHandler.h Mpris1::RootHandler Mpris1AmarokAppAdaptor Mpris1AmarokAppAdaptor ) qt5_add_dbus_adaptor( AMAROK_MPRIS1_ADAPTOR_SRCS dbus/mpris1/org.kde.amarok.Mpris1Extensions.Player.xml dbus/mpris1/PlayerHandler.h Mpris1::PlayerHandler Mpris1AmarokPlayerAdaptor Mpris1AmarokPlayerAdaptor ) qt5_add_dbus_adaptor( AMAROK_MPRIS1_ADAPTOR_SRCS dbus/org.kde.amarok.Collection.xml dbus/CollectionDBusHandler.h CollectionDBusHandler CollectionAdaptor CollectionAdaptor ) # suppress deprecated methods warnings if(NOT WIN32) set_source_files_properties(${AMAROK_MPRIS1_ADAPTOR_SRCS} PROPERTIES COMPILE_FLAGS -Wno-deprecated-declarations) endif() set( amaroklib_DEPENDS "amarokpud" ) set( amaroklib_DEPENDS "amarokcore" ) set( amaroklib_DEPENDS "amarok-transcoding" ) # depends on generated ui_*.h file kconfig_add_kcfg_files(amaroklib_LIB_SRCS amarokconfig.kcfgc) add_custom_target(amarokconfig_h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/amarokconfig.h) ki18n_wrap_ui(amaroklib_LIB_SRCS aboutdialog/OcsPersonItem.ui dialogs/EditFilterDialog.ui dialogs/EqualizerDialog.ui dialogs/MusicBrainzTagger.ui dialogs/TagDialogBase.ui dialogs/TagGuessOptions.ui dialogs/OrganizeCollectionOptions.ui dialogs/OrganizeCollectionDialogBase.ui playlist/layouts/PlaylistLayoutEditDialog.ui core-impl/podcasts/sql/PodcastSettingsBase.ui core-impl/podcasts/sql/SqlPodcastProviderSettingsWidget.ui core-impl/podcasts/sql/PodcastFilenameLayoutConfigWidget.ui browsers/playlistbrowser/PodcastCategoryBase.ui ) add_library(amaroklib SHARED ${amaroklib_LIB_SRCS} ${AMAROK_MPRIS1_ADAPTOR_SRCS}) target_link_libraries(amaroklib Phonon::phonon4qt5 KF5::Archive KF5::CoreAddons KF5::Declarative KF5::GlobalAccel KF5::GuiAddons KF5::I18n KF5::IconThemes KF5::KCMUtils KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::KIONTLM KF5::NewStuff KF5::Notifications KF5::NotifyConfig KF5::Package KF5::TextEditor KF5::ThreadWeaver KF5::WindowSystem ${QT_QTSCRIPTTOOLS_LIBRARY} Qt5::Gui Qt5::Quick Qt5::QuickWidgets Qt5::Script Qt5::ScriptTools Qt5::Sql Qt5::Svg ${CMAKE_DL_LIBS} Threads::Threads ${EXTRA_LIBS} amarokpud amarokcore amarokocsclient amarok-transcoding amarokshared ) +if( Qt5WebEngine_FOUND ) + target_link_libraries( amaroklib Qt5::WebEngine ) + add_definitions( -DWITH_QT_WEBENGINE ) +endif() + include_directories(${TAGLIB_INCLUDES}) add_definitions(${TAGLIB_CFLAGS}) target_link_libraries(amaroklib ${TAGLIB_LIBRARIES}) if( TAGLIB-EXTRAS_FOUND ) include_directories(${TAGLIB-EXTRAS_INCLUDES}) add_definitions(${TAGLIB-EXTRAS_CFLAGS}) target_link_libraries(amaroklib ${TAGLIB-EXTRAS_LIBRARIES}) endif() if(WIN32) target_link_libraries(amaroklib Qt5::WebKitWidgets) endif() if(APPLE) target_link_libraries(amaroklib "/System/Library/Frameworks/Foundation.framework") set_target_properties(amaroklib PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") endif() set_target_properties(amaroklib PROPERTIES VERSION 1.0.0 SOVERSION 1 ) install(TARGETS amaroklib ${INSTALL_TARGETS_DEFAULT_ARGS} ) ##################################################################### # AMAROK ##################################################################### set( amarok_SRCS main.cpp ) file(GLOB ICONS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/../images/*-apps-amarok.png) ecm_add_app_icon(amarok_SRCS ICONS ${ICONS_SRCS}) add_executable(amarok ${amarok_SRCS}) if(APPLE) set_target_properties(amarok PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") set(MACOSX_BUNDLE_BUNDLE_NAME "Amarok 2") set(MACOSX_BUNDLE_BUNDLE_VERSION "2.8.0-git") set(MACOSX_BUNDLE_COPYRIGHT "Amarok Team") set_target_properties(amarok PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${MAC_FILES_DIR}/Info.plist.template) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/amarok.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) endif() target_link_libraries(amarok KF5::CoreAddons KF5::DBusAddons KF5::I18n amarokcore amaroklib ${X11_LIBRARIES} ) install(TARGETS amarok ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(PROGRAMS org.kde.amarok.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install(PROGRAMS org.kde.amarok_containers.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install(FILES org.kde.amarok.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) install(FILES amarok-plugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) install(FILES amarok-contextapplet.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) install(FILES amarok_codecinstall.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) install(FILES amarok_append.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/ServiceMenus) install(FILES amarok-play-audiocd.desktop DESTINATION ${KDE_INSTALL_DATADIR}/solid/actions) install(FILES amarok.knsrc DESTINATION ${KDE_INSTALL_CONFDIR}) # protocol handlers install(FILES amarokurls/amarok.protocol DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES amarokitpc.protocol DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) #install(FILES amarokpcast.protocol DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) install(FILES amarokconfig.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR} ) install(FILES dbus/mpris1/org.freedesktop.MediaPlayer.root.xml dbus/mpris1/org.freedesktop.MediaPlayer.player.xml dbus/mpris1/org.freedesktop.MediaPlayer.tracklist.xml dbus/org.kde.amarok.App.xml dbus/org.kde.amarok.Collection.xml dbus/mpris1/org.kde.amarok.Mpris1Extensions.Player.xml dbus/mpris2/org.kde.amarok.Mpris2Extensions.Player.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR}) install(FILES services/InfoParserLoading.html browsers/hover_info_template.html DESTINATION ${KDE_INSTALL_DATADIR}/amarok/data) ecm_install_icons(ICONS DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor ) diff --git a/src/context/AmarokContextPackageStructure.cpp b/src/context/AmarokContextPackageStructure.cpp index be15e783ff..cc84855858 100644 --- a/src/context/AmarokContextPackageStructure.cpp +++ b/src/context/AmarokContextPackageStructure.cpp @@ -1,31 +1,33 @@ /* * Copyright (C) 2017 Malte Veerman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "AmarokContextPackageStructure.h" #include void AmarokContextPackageStructure::initPackage(KPackage::Package* package) { package->addFileDefinition("mainscript", QStringLiteral("ui/main.qml"), i18n("Main Script File")); + package->addFileDefinition("icon", QStringLiteral("images/icon.png"), i18n("Applet Icon File")); + package->addFileDefinition("icon", QStringLiteral("images/icon.svg"), i18n("Applet Icon File")); package->setDefaultPackageRoot(QStringLiteral("kpackage/amarok")); package->addDirectoryDefinition("images", QStringLiteral("images"), i18n("Images")); auto mimetypes = QStringList() << QStringLiteral("image/svg+xml"); package->setMimeTypes("images", mimetypes); } diff --git a/src/context/AppletModel.cpp b/src/context/AppletModel.cpp index 0eb8d9f14f..7ffe4bc612 100644 --- a/src/context/AppletModel.cpp +++ b/src/context/AppletModel.cpp @@ -1,358 +1,366 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #define DEBUG_PREFIX "AppletModel" #include "AppletModel.h" #include "AmarokContextPackageStructure.h" #include "AppletLoader.h" #include "core/support/Amarok.h" #include "core/support/Debug.h" #include #include #include #include #include using namespace Context; class Context::AppletPackage : public KPackage::Package { public: AppletPackage(const KPackage::Package &package) : KPackage::Package(package) {} bool operator==(const AppletPackage &p) { return metadata() == p.metadata(); } }; AppletModel::AppletModel(AppletLoader *loader, QObject* parent) : QAbstractListModel(parent) , m_loader(loader) { newApplets(loader->applets()); connect(loader, &AppletLoader::finished, this, &AppletModel::newApplets); } AppletModel::~AppletModel() { } int AppletModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent) return m_packages.size(); } void AppletModel::newApplets(const QList& applets) { DEBUG_BLOCK beginResetModel(); m_packages.clear(); for (const auto applet : applets) { auto loader = KPackage::PackageLoader::self(); auto structure = new AmarokContextPackageStructure; loader->addKnownPackageStructure(QStringLiteral("Amarok/Context"), structure); auto package = loader->loadPackage(QStringLiteral("Amarok/Context"), applet.pluginId()); if (package.isValid()) { m_packages << package; } else error() << "Error loading package:" << applet.pluginId(); } //Sort applets by name std::sort(m_packages.begin(), m_packages.end(), [] (const AppletPackage &p1, const AppletPackage &p2) { return p1.metadata().name() < p2.metadata().name(); }); endResetModel(); } QVariant AppletModel::data(const QModelIndex& index, int role) const { int row = index.row(); if (row >= m_packages.size()) return QVariant(); const auto &package = m_packages.at(row); switch (role) { case Name: return package.metadata().name(); case Id: return package.metadata().pluginId(); case Icon: - return package.metadata().iconName(); + return QUrl::fromLocalFile(package.filePath("icon")); case Mainscript: return QUrl::fromLocalFile(package.filePath("mainscript")); case Collapsed: return Amarok::config("Context").readEntry(package.metadata().pluginId() + "_collapsed", false); case ContentHeight: return Amarok::config("Context").readEntry(package.metadata().pluginId() + "_contentHeight", 300); case PackagePath: return QVariant(package.path() + "contents/"); } return QVariant(); } bool Context::AppletModel::setData(const QModelIndex& index, const QVariant& value, int role) { int row = index.row(); if (row >= m_packages.size()) return false; const auto &package = m_packages.at(row); switch (role) { case Collapsed: { Amarok::config("Context").writeEntry(package.metadata().pluginId() + "_collapsed", value.toBool()); emit dataChanged(index, index, QVector{role}); return true; } case ContentHeight: { Amarok::config("Context").writeEntry(package.metadata().pluginId() + "_contentHeight", value.toReal()); emit dataChanged(index, index, QVector{role}); return true; } default: warning() << (Role) role << "is read-only."; } return false; } QHash< int, QByteArray > AppletModel::roleNames() const { QHash roles; roles.insert(Name, "name"); roles.insert(Id, "appletId"); roles.insert(Icon, "icon"); roles.insert(Mainscript, "mainscript"); roles.insert(Collapsed, "collapsed"); roles.insert(PackagePath, "packagePath"); roles.insert(ContentHeight, "contentHeight"); return roles; } void AppletModel::setAppletCollapsed(const QString& id, bool collapsed) { DEBUG_BLOCK debug() << "Set collapsed for applet:" << id << "to:" << collapsed; auto package = findPackage(id); if (package.isValid()) { Amarok::config("Context").writeEntry(id + "_collapsed", collapsed); int row = m_packages.indexOf(package); auto index = createIndex(row, 0); emit dataChanged(index, index, QVector{Collapsed}); } } void Context::AppletModel::setAppletContentHeight(const QString& id, qreal height) { DEBUG_BLOCK debug() << "Set content height for applet:" << id << "to:" << height; auto package = findPackage(id); if (package.isValid()) { Amarok::config("Context").writeEntry(id + "_contentHeight", height); int row = m_packages.indexOf(package); auto index = createIndex(row, 0); emit dataChanged(index, index, QVector{ContentHeight}); } } +QUrl Context::AppletModel::imageUrl(const QString& id, const QString& imageName) +{ + auto package = findPackage(id); + if (package.isValid()) + return QUrl::fromLocalFile( package.filePath("images", imageName) ); + return QUrl(); +} + AppletPackage AppletModel::findPackage(const QString& id) { for (const auto &package : m_packages) { auto metadata = package.metadata(); if (metadata.pluginId() == id) return package; } warning() << "Applet with id:" << id << "not found."; return AppletPackage(KPackage::Package()); } AppletProxyModel::AppletProxyModel(AppletModel* appletModel, QObject *parent) : QSortFilterProxyModel(parent) , m_appletModel(appletModel) { setSourceModel(appletModel); setDynamicSortFilter(true); sort(0); connect(m_appletModel->loader(), &AppletLoader::finished, this, &AppletProxyModel::enabledAppletsChanged); } AppletProxyModel::~AppletProxyModel() { } QStringList AppletProxyModel::enabledApplets() const { QStringList list; for (const auto &applet : m_appletModel->loader()->enabledApplets()) { list << applet.pluginId(); } std::sort(list.begin(), list.end(), [] (const QString &a, const QString &b) { QStringList ae = Amarok::config("Context").readEntry("enabledApplets", QStringList()); return ae.indexOf(a) < ae.indexOf(b); } ); return list; } void AppletProxyModel::setAppletEnabled(const QString& id, bool enabled, int place) { DEBUG_BLOCK debug() << "Set enabled for applet:" << id << "to:" << enabled; if (enabled == appletEnabled(id)) return; QStringList ea = enabledApplets(); if (enabled) { if (place <= -1) place = ea.size(); debug() << "Applet's new place is" << place; ea.insert(place, id); } else { ea.removeAll(id); } Amarok::config("Context").writeEntry("enabledApplets", ea); debug() << "New enabled applets:" << ea; invalidateFilter(); emit enabledAppletsChanged(); } void AppletProxyModel::setAppletPlace(const QString& id, int place) { DEBUG_BLOCK debug() << "Set place for applet:" << id << "to:" << place; int currentPlace = appletPlace(id); debug() << "Current place is" << currentPlace; if (currentPlace == place) return; if (place <= -1) { setAppletEnabled(id, false); return; } if (currentPlace <= -1) setAppletEnabled(id, true, place); QStringList ea = enabledApplets(); place = qMin(place, ea.size() - 1); bool forward = place > currentPlace; beginMoveRows(QModelIndex(), currentPlace, currentPlace, QModelIndex(), forward ? place + 1 : place); ea.move(currentPlace, place); Amarok::config("Context").writeEntry("enabledApplets", ea); endMoveRows(); debug() << "New enabled applets:" << ea; } int AppletProxyModel::appletPlace(const QString& id) const { return enabledApplets().indexOf(id); } bool AppletProxyModel::appletEnabled(const QString& id) const { return enabledApplets().contains(id); } void Context::AppletProxyModel::clear() { for( const auto &applet : enabledApplets() ) { setAppletEnabled( applet, false ); } } bool AppletProxyModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const { int placeLeft = appletPlace(source_left.data(AppletModel::Id).toString()); int placeRight = appletPlace(source_right.data(AppletModel::Id).toString()); return placeLeft < placeRight; } bool AppletProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { QModelIndex index = sourceModel()->index(source_row, 0, source_parent); return appletEnabled(index.data(AppletModel::Id).toString()); } diff --git a/src/context/AppletModel.h b/src/context/AppletModel.h index 74798bea08..d157758478 100644 --- a/src/context/AppletModel.h +++ b/src/context/AppletModel.h @@ -1,145 +1,146 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #ifndef APPLETMODEL_H #define APPLETMODEL_H #include #include class KPluginMetaData; namespace Context { class AppletLoader; class AppletPackage; class AppletModel : public QAbstractListModel { Q_OBJECT public: enum Role { Name, Id, Icon, Mainscript, Collapsed, PackagePath, ContentHeight }; Q_ENUM(Role) AppletModel(AppletLoader *loader, QObject *parent = Q_NULLPTR); virtual ~AppletModel(); virtual int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE; virtual QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE; virtual bool setData(const QModelIndex& index, const QVariant& value, int role) Q_DECL_OVERRIDE; virtual QHash< int, QByteArray > roleNames() const Q_DECL_OVERRIDE; AppletLoader* loader() const { return m_loader; } Q_INVOKABLE void setAppletCollapsed(const QString &id, bool collapsed); Q_INVOKABLE void setAppletContentHeight(const QString& id, qreal height); + Q_INVOKABLE QUrl imageUrl(const QString &id, const QString &imageName); public Q_SLOTS: void newApplets(const QList &applets); protected: AppletPackage findPackage(const QString &id); private: QList m_packages; AppletLoader *const m_loader; }; class AppletProxyModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(QStringList enabledApplets READ enabledApplets NOTIFY enabledAppletsChanged) public: AppletProxyModel(AppletModel *appletModel, QObject *parent = Q_NULLPTR); virtual ~AppletProxyModel(); /** * @returns QStringList with ids of all enabled applets. * Sorted in ascending order of place of applets. */ QStringList enabledApplets() const; /** * Set an applet to be enabled or disabled. Does nothing if id is invalid. * Disabling an applet sets its place to -1. * * @param id Id of the applet. * @param enabled Set to true if applet should be enabled and false for disabled. * @param place The place of the applet after enabling. -1 appends the applet to the end of the list. * Irrelevant if applet is to be disabled. */ Q_INVOKABLE void setAppletEnabled(const QString &id, bool enabled, int place = -1); /** * Set an applet's place. Does nothing if id is invalid. * Enables the applet if it is disabled. * * @param id Id of the applet. * @param place The new place of the applet. Negative values disable the applet. */ Q_INVOKABLE void setAppletPlace(const QString &id, int place); /** * Find out an applet's place. * * @returns an integer with the applet's place. -1 if the applet is disabled. * * @param id Id of applet's place to be returned. */ Q_INVOKABLE int appletPlace(const QString &id) const; /** * Find out if an applet is enabled or disabled. * * @returns true if applet is enabled. Returns false if not. * * @param id Id of the applet. */ Q_INVOKABLE bool appletEnabled(const QString &id) const; /** * Clear the context area by disabling all applets */ Q_INVOKABLE void clear(); Q_SIGNALS: void enabledAppletsChanged(); protected: bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const Q_DECL_OVERRIDE; bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE; private: AppletModel *m_appletModel; }; } #endif // APPLETMODEL_H diff --git a/src/context/applets/CMakeLists.txt b/src/context/applets/CMakeLists.txt index 389aac93bc..22923418e8 100644 --- a/src/context/applets/CMakeLists.txt +++ b/src/context/applets/CMakeLists.txt @@ -1,15 +1,18 @@ add_subdirectory( albums ) add_subdirectory( currenttrack ) #add_subdirectory( info ) #add_subdirectory( labels ) add_subdirectory( lyrics ) add_subdirectory( photos ) #add_subdirectory( tabs ) -#add_subdirectory( wikipedia ) add_subdirectory( analyzer ) +if( Qt5WebEngine_FOUND ) + add_subdirectory( wikipedia ) +endif() + if( LIBLASTFM_FOUND ) # add_subdirectory( upcomingevents ) # add_subdirectory( similarartists ) endif() diff --git a/images/icons/48-actions-media-album-cover-manager-amarok.png b/src/context/applets/albums/package/contents/images/icon.png similarity index 100% rename from images/icons/48-actions-media-album-cover-manager-amarok.png rename to src/context/applets/albums/package/contents/images/icon.png diff --git a/images/icons/48-actions-view-media-analyzer-amarok.png b/src/context/applets/analyzer/package/contents/images/icon.png similarity index 100% rename from images/icons/48-actions-view-media-analyzer-amarok.png rename to src/context/applets/analyzer/package/contents/images/icon.png diff --git a/images/icons/48-actions-current-track-amarok.png b/src/context/applets/currenttrack/package/contents/images/icon.png similarity index 100% rename from images/icons/48-actions-current-track-amarok.png rename to src/context/applets/currenttrack/package/contents/images/icon.png diff --git a/images/icons/48-actions-amarok_lyrics.png b/src/context/applets/lyrics/package/contents/images/icon.png similarity index 100% rename from images/icons/48-actions-amarok_lyrics.png rename to src/context/applets/lyrics/package/contents/images/icon.png diff --git a/images/icons/48-actions-photos-amarok.png b/src/context/applets/photos/package/contents/images/icon.png similarity index 100% rename from images/icons/48-actions-photos-amarok.png rename to src/context/applets/photos/package/contents/images/icon.png diff --git a/src/context/applets/wikipedia/WikipediaCustomStyle.css b/src/context/applets/wikipedia/WikipediaCustomStyle.css index 937e8dbe83..76d7a8fdd5 100644 --- a/src/context/applets/wikipedia/WikipediaCustomStyle.css +++ b/src/context/applets/wikipedia/WikipediaCustomStyle.css @@ -1,346 +1,333 @@ first { element: is; completely: ignored; } body { margin: 0px; padding: 6px 2px; + background-color: /*{background_color}*/; color: /*{text_color}*/; font-size: medium; } h1, h2, h3, h4, h5, h6 { - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; overflow: hidden; margin: 5pt 0; padding: 2pt 5pt; background-color: /*{headings_background_color}*/; color: /*{text_color}*/; } p, div, table, ul, li { font-size: medium; } span.citation { font-size: 90%; } ul li { margin-right: 5pt; } ul li a { text-decoration: none; color: /*{link_color}*/; } ul li a:hover { text-decoration: underline; color: /*{link_hover_color}*/; } div#wiki_otherlangs { clear: both; - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; background-color: /*{shaded_text_background_color}*/; padding: 5pt; color: /*{text_color}*/; } div#bodyContent { color: /*{text_color}*/; } div#bodyContent * { color: /*{text_color}*/; } /* Bullet list definition gracefully gottened from wikipedia - since we're * showing their data, we should really present it like it was intended. So, we * use their bullet. */ div#bodyContent ul { list-style-type: square; margin: 0 1em; padding: 0 1em; list-style-image: url(bullet.gif); } div#bodyContent ul li { display: list-item; } div#bodyContent a { text-decoration: none; color: /*{link_color}*/; } div#bodyContent a:hover { text-decoration: underline; color: /*{link_hover_color}*/; } /* table for embedded media clip boxes */ table.metadata, table.ambox { - border-radius: 1.6em; - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; position: relative; left: 50%; width: 50%; margin: 5pt 0; padding: 5pt; } table.infobox { clear: right; float: right; width: 150pt; - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; background-color: /*{table_background_color}*/; margin: 5pt 2pt 0 5pt; } table.bordered { clear: both; display: inline-block; margin: 5pt 2pt 0 5pt; } table.infobox th { padding: 2pt; - border: 1px solid /*{border_color}*/; background-color: /*{alternate_table_background_color}*/; color: /*{text_color}*/; } table.gallery { clear: both; display: block; - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; background-color: /*{table_background_color}*/; margin: 5pt 0; } table#toc { display: none; } /* We're hiding the TOC, as it currently links directly to the wikipedia URL, not relatively to the anchor inside the document, which make it open up in an external browser - not really what we want it to do... table#toc { border: 1px dotted silver; background: #f0f0f0; } #toctitle h2 { font-size: 11pt; background: silver; padding: 2pt; } table#toc ul { list-style: none; } table#toc a,table#toc a span { color: #424280; } table#toc a:hover,table#toc a:hover span { color: #7E7EFF; } */ /* heading text - e.g. "This article is about the band", etc. */ div.dablink { width: 100%; text-align: left; font-style: italic; color: /*{text_color}*/; } div#contentSub { width: 100%; text-align: right; color: gray; } div#jump-to-nav { width: 100%; text-align: right; color: gray; margin-right: 5pt; } div#contentSub a, div#jump-to-nav a, div.dablink a { color: /*{link_hover_color}*/; } div#stub { clear: right; background-color: /*{shaded_text_background_color}*/; - border: 2px solid /*{border_color}*/; border-radius: 4px; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; width: 80%; padding: 5pt; margin-bottom: 10pt; margin-left: auto; margin-right: auto; } table.wikitable { - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; border-collapse: collapse; margin: 5pt; background-color: /*{table_background_color}*/; } table.wikitable th { padding: 2pt; background-color: /*{alternate_table_background_color}*/; - border: 2px solid /*{border_color}*/; } table.wikitable td { padding: 2pt; background-color: /*{table_background_color}*/; - border: 2px solid /*{border_color}*/; } table.navbox { - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; border-collapse: collapse; margin: 5pt 2% 5pt 2%; width: 96%; background-color: /*{shaded_text_background_color}*/; } table.navbox td { - border: 2px solid /*{border_color}*/; background-color: /*{table_background_color}*/; } /* article thumbnail images */ div.thumb { - border: 2px solid /*{border_color}*/; -webkit-border-radius: 4px; -khtml-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; margin: 5pt; padding: 2pt; width: auto; background-color: /*{table_background_color}*/; } div.thumbinner { text-align: center; overflow: hidden; } div.thumbimage { margin: 2pt 0; } /* captions for thumbnail images */ div.thumbcaption { border: none; text-align: left; line-height: 1.4em; font-size: smaller; } div.magnify { float: right; border: none !important; background: none !important; } div.tright { clear: right; float: right; } div.tleft { float: left; clear: left; } div.medialist ul li { list-style: none; } div#ogg_player_1, div#ogg_player_2, div#ogg_player_3, div#ogg_player_4, div#ogg_player_5, div#ogg_player_6, div#ogg_player_7, div#ogg_player_8, div#ogg_player_9, div#ogg_player_10, div#ogg_player_11, div#ogg_player_12, div#ogg_player_13 { display: none; } div#jump-to-nav, div.NavFrame, table.metadata { display: none; } div.medialist table { margin: 5pt; width: 100%; } diff --git a/src/context/applets/wikipedia/package/contents/images/amarok-wikipedia.svg b/src/context/applets/wikipedia/package/contents/images/amarok-wikipedia.svg deleted file mode 100644 index 1b34f49e5e..0000000000 --- a/src/context/applets/wikipedia/package/contents/images/amarok-wikipedia.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - image/svg+xml - - - - image/svg+xml - - - - - - - - - - - diff --git a/src/context/applets/wikipedia/package/contents/images/icon.svg b/src/context/applets/wikipedia/package/contents/images/icon.svg new file mode 100644 index 0000000000..dc32f9848f --- /dev/null +++ b/src/context/applets/wikipedia/package/contents/images/icon.svg @@ -0,0 +1 @@ +]>Wikipedia logo version 2 \ No newline at end of file diff --git a/src/context/applets/wikipedia/package/contents/ui/main.qml b/src/context/applets/wikipedia/package/contents/ui/main.qml index 3a7558375c..c8e5de889c 100644 --- a/src/context/applets/wikipedia/package/contents/ui/main.qml +++ b/src/context/applets/wikipedia/package/contents/ui/main.qml @@ -1,119 +1,117 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import QtWebEngine 1.1 -import org.kde.kirigami 2.0 as Kirigami +import QtWebEngine 1.3 import org.kde.amarok.qml 1.0 as AmarokQml import org.kde.amarok.wikipedia 1.0 AmarokQml.Applet { id: applet ColumnLayout { anchors.fill: parent RowLayout { - Layout:fillWidth: true + Layout.fillWidth: true Layout.alignment: Qt.AlignTop Button { iconName: "go-previous" enabled: content.canGoBack Layout.alignment: Qt.AlignLeft - ToolTip.text: i18n("Previous") + tooltip: i18n("Previous") onClicked: content.goBack() } Button { iconName: "go-next" enabled: content.canGoForward Layout.alignment: Qt.AlignLeft - ToolTip.text: i18n("Next") + tooltip: i18n("Next") onClicked: content.goForward() } Button { iconName: "view-refresh" enabled: !content.loading Layout.alignment: Qt.AlignLeft - ToolTip.text: i18n("Refresh") + tooltip: i18n("Refresh") onClicked: content.reload() } Item { Layout.fillWidth: true } Button { iconName: "filename-artist-amarok" Layout.alignment: Qt.AlignRight - ToolTip.text: i18n("Artist") + tooltip: i18n("Artist") onClicked: WikipediaEngine.selection = WikipediaEngine.Artist } Button { iconName: "filename-composer-amarok" Layout.alignment: Qt.AlignRight - ToolTip.text: i18n("Composer") + tooltip: i18n("Composer") onClicked: WikipediaEngine.selection = WikipediaEngine.Composer } Button { iconName: "filename-album-amarok" Layout.alignment: Qt.AlignRight - ToolTip.text: i18n("Album") + tooltip: i18n("Album") onClicked: WikipediaEngine.selection = WikipediaEngine.Album } Button { iconName: "filename-title-amarok" Layout.alignment: Qt.AlignRight - ToolTip.text: i18n("Track") + tooltip: i18n("Track") onClicked: WikipediaEngine.selection = WikipediaEngine.Track } } WebEngineView { id: content + backgroundColor: "transparent" + Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignBottom - height: Kirigami.Units.largeSpacing * 25 //TODO: Find a more elegant solution to set the height onNavigationRequested: { - if (request.navigationType == WebEngineNavigationRequest.LinkClickedNavigation) { - request.action = WebEngineNavigationRequest.IgnoreRequest; - WikipediaEngine.url = request.url; - } + request.action = WebEngineNavigationRequest.IgnoreRequest; + WikipediaEngine.url = request.url; } Connections { target: WikipediaEngine onPageChanged: content.loadHtml(WikipediaEngine.page, WikipediaEngine.url) } BusyIndicator { anchors.centerIn: parent running: WikipediaEngine.busy } } } } diff --git a/src/context/applets/wikipedia/package/metadata.desktop b/src/context/applets/wikipedia/package/metadata.desktop index 09f2143e9b..5867e18449 100644 --- a/src/context/applets/wikipedia/package/metadata.desktop +++ b/src/context/applets/wikipedia/package/metadata.desktop @@ -1,71 +1,71 @@ [Desktop Entry] Name=Wikipedia Name[bg]=Уикипедия Name[bs]=Wikipedia Name[ca]=Viquipèdia Name[ca@valencia]=Viquipèdia Name[cs]=Wikipedia Name[csb]=Wikipedijô Name[da]=Wikipedia Name[de]=Wikipedia Name[el]=Wikipedia Name[en_GB]=Wikipedia Name[es]=Wikipedia Name[et]=Wikipedia Name[eu]=Wikipedia Name[fa]=ویکی‌پدیا Name[fi]=Wikipedia Name[fr]=Wikipédia Name[ga]=Vicipéid Name[gl]=Wikipedia Name[hu]=Wikipedia Name[id]=Wikipedia Name[is]=Wikipedia Name[it]=Wikipedia Name[ja]=Wikipedia Name[km]=វីគីភីឌៀ Name[ko]=위키백과 Name[lt]=Vikipedija Name[lv]=Wikipēdija Name[mr]=विकिपेडिया Name[nb]=Wikipedia Name[nds]=Wikipedia Name[nl]=Wikipedia Name[nn]=Wikipedia Name[pa]=ਵਿਕਿਪੀਡਿਆ Name[pl]=Wikipedia Name[pt]=Wikipédia Name[pt_BR]=Wikipédia Name[ro]=Wikipedia Name[ru]=Википедия Name[sk]=Wikipédia Name[sl]=Wikipedija Name[sq]=Wikipedia Name[sr]=Википедија Name[sr@ijekavian]=Википедија Name[sr@ijekavianlatin]=Wikipedia Name[sr@latin]=Wikipedia Name[sv]=Wikipedia Name[th]=วิกิพีเดีย Name[tr]=Wikipedia Name[ug]=ۋىكىپېدىيە Name[uk]=Вікіпедія Name[wa]=Wikipedia Name[x-test]=xxWikipediaxx Name[zh_CN]=维基百科 Name[zh_TW]=維基百科 Type=Service ServiceTypes=Amarok/ContextApplet -Icon=wikipedia-amarok +Icon=amarok-wikipedia X-KDE-PluginInfo-Author=Leo Franchi X-KDE-PluginInfo-Email=lfranchi@gmail.com X-KDE-PluginInfo-Name=org.kde.amarok.wikipedia X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true X-KDE-PluginInfo-Category=Multimedia diff --git a/src/context/applets/wikipedia/plugin/WikipediaEngine.cpp b/src/context/applets/wikipedia/plugin/WikipediaEngine.cpp index 0283d11be7..b2f3d2d66f 100644 --- a/src/context/applets/wikipedia/plugin/WikipediaEngine.cpp +++ b/src/context/applets/wikipedia/plugin/WikipediaEngine.cpp @@ -1,825 +1,871 @@ /**************************************************************************************** * Copyright (c) 2012 Ryan McCoskrie * * Copyright (c) 2008 Mark Kretschmann * * Copyright (c) 2009 Simon Esneault * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #define DEBUG_PREFIX "Wikipedia" #include "WikipediaEngine.h" #include "EngineController.h" +#include "PaletteHandler.h" #include "core/meta/support/MetaConstants.h" #include "core/support/Amarok.h" #include "core/support/Debug.h" #include +#include +#include #include #include #include WikipediaEngine::WikipediaEngine( QObject* parent ) : QObject( parent ) , currentSelection( Artist ) , useMobileVersion( false ) { preferredLangs = Amarok::config("Wikipedia Applet").readEntry( "PreferredLang", QStringList() << "en" ); EngineController *engine = The::engineController(); _checkRequireUpdate( engine->currentTrack() ); + _paletteChanged( The::paletteHandler()->palette() ); connect( engine, &EngineController::trackChanged, this, &WikipediaEngine::_checkRequireUpdate ); connect( engine, &EngineController::trackMetadataChanged, this, &WikipediaEngine::_checkRequireUpdate ); connect( engine, &EngineController::stopped, this, &WikipediaEngine::_stopped ); + connect( The::paletteHandler(), &PaletteHandler::newPalette, + this, &WikipediaEngine::_paletteChanged ); } WikipediaEngine::~WikipediaEngine() { } void WikipediaEngine::_wikiResult( const QUrl &url, QByteArray result, NetworkAccessManagerProxy::Error e ) { if( !urls.contains( url ) ) return; urls.remove( url ); if( e.code != QNetworkReply::NoError ) { clear(); setMessage( i18n("Unable to retrieve Wikipedia information: %1", e.description) ); return; } debug() << "Received page from wikipedia:" << url; QString wiki( result ); // FIXME: For now we test if we got an article or not with a test on this string "wgArticleId=0" // This is bad if( wiki.contains(QLatin1String("wgArticleId=0")) && (wiki.contains(QLatin1String("wgNamespaceNumber=0")) || wiki.contains(QLatin1String("wgPageName=\"Special:Badtitle\"")) ) ) // The article does not exist { debug() << "article does not exist"; clear(); setMessage( i18n( "No information found..." ) ); return; } // We've found a page wikiParse( wiki ); setPage( wiki ); setBusy( false ); Meta::TrackPtr currentTrack = The::engineController()->currentTrack(); if( !currentTrack ) return; if( currentSelection == Artist ) // default, or applet told us to fetch artist { if( currentTrack && currentTrack->artist() ) { setTitle( currentTrack->artist()->prettyName() ); } } else if( currentSelection == Composer ) { setTitle( currentTrack->composer()->prettyName() ); } else if( currentSelection == Track ) { setTitle( currentTrack->prettyName() ); } else if( currentSelection == Album ) { if( currentTrack && currentTrack->album() ) { setTitle( currentTrack->album()->prettyName() ); } } } void WikipediaEngine::_parseLangLinksResult( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ) { if( !urls.contains( url ) ) return; urls.remove( url ); if( e.code != QNetworkReply::NoError || data.isEmpty() ) { debug() << "Parsing langlinks result failed" << e.description; clear(); setMessage( i18n("Unable to retrieve Wikipedia information: %1", e.description) ); return; } QString hostLang = url.host(); hostLang.remove( QLatin1String(".wikipedia.org") ); const QString &title = QUrlQuery( url ).queryItemValue( QLatin1String("titles") ); QHash langTitleMap; // a hash of langlinks and their titles QString llcontinue; QXmlStreamReader xml( data ); while( !xml.atEnd() && !xml.hasError() ) { xml.readNext(); if( xml.isStartElement() && xml.name() == QLatin1String("page") ) { if( xml.attributes().hasAttribute(QLatin1String("missing")) ) break; QXmlStreamAttributes a = xml.attributes(); if( a.hasAttribute(QLatin1String("pageid")) && a.hasAttribute(QLatin1String("title")) ) { const QString &pageTitle = a.value( QLatin1String("title") ).toString(); if( pageTitle.endsWith(QLatin1String("(disambiguation)")) ) { fetchListing( title, hostLang ); return; } langTitleMap[hostLang] = title; } while( !xml.atEnd() ) { xml.readNext(); if( xml.isEndElement() && xml.name() == QLatin1String("page") ) break; if( xml.isStartElement() ) { if( xml.name() == QLatin1String("ll") ) { QXmlStreamAttributes a = xml.attributes(); if( a.hasAttribute(QLatin1String("lang")) ) { QString lang = a.value( QLatin1String("lang") ).toString(); langTitleMap[lang] = xml.readElementText(); } } else if( xml.name() == QLatin1String("query-continue") ) { xml.readNext(); if( xml.isStartElement() && xml.name() == QLatin1String("langlinks") ) { QXmlStreamAttributes a = xml.attributes(); if( a.hasAttribute(QLatin1String("llcontinue")) ) llcontinue = a.value( QLatin1String("llcontinue") ).toString(); } } } } } } if( !langTitleMap.isEmpty() ) { /* When we query langlinks using a particular language, interwiki * results will not contain links for that language. However, it may * appear as part of the "page" element if there's a match or a redirect * has been set. So we need to manually add it here if it's still empty. */ if( preferredLangs.contains(hostLang) && !langTitleMap.contains(hostLang) ) langTitleMap[hostLang] = title; setBusy( false ); QStringListIterator langIter( preferredLangs ); while( langIter.hasNext() ) { QString prefix = langIter.next().split( QLatin1Char(':') ).back(); if( langTitleMap.contains(prefix) ) { QString pageTitle = langTitleMap.value( prefix ); fetchListing( pageTitle, prefix ); return; } } } if( !llcontinue.isEmpty() ) { fetchLangLinks( title, hostLang, llcontinue ); } else { QRegExp regex( QLatin1Char('^') + hostLang + QLatin1String(".*$") ); int index = preferredLangs.indexOf( regex ); if( (index != -1) && (index < preferredLangs.count() - 1) ) { // use next preferred language as base for fetching langlinks since // the current one did not get any results we want. QString prefix = preferredLangs.value( index + 1 ).split( QLatin1Char(':') ).back(); fetchLangLinks( title, prefix ); } else { QStringList refinePossibleLangs = preferredLangs.filter( QRegExp("^(en|fr|de|pl).*$") ); if( refinePossibleLangs.isEmpty() ) { clear(); setMessage( i18n( "No information found..." ) ); return; } fetchListing( title, refinePossibleLangs.first().split( QLatin1Char(':') ).back() ); } } } void WikipediaEngine::_parseListingResult( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ) { if( !urls.contains( url ) ) return; urls.remove( url ); if( e.code != QNetworkReply::NoError || data.isEmpty() ) { debug() << "Parsing listing result failed" << e.description; clear(); setMessage( i18n("Unable to retrieve Wikipedia information: %1", e.description) ); return; } QString hostLang = url.host(); hostLang.remove( QLatin1String(".wikipedia.org") ); const QString &title = QUrlQuery( url ).queryItemValue( QLatin1String("srsearch") ); QStringList titles; QXmlStreamReader xml( data ); while( !xml.atEnd() && !xml.hasError() ) { xml.readNext(); if( xml.isStartElement() && xml.name() == QLatin1String("search") ) { while( xml.readNextStartElement() ) { if( xml.name() == QLatin1String("p") ) { if( xml.attributes().hasAttribute( QLatin1String("title") ) ) titles << xml.attributes().value( QLatin1String("title") ).toString(); xml.skipCurrentElement(); } else xml.skipCurrentElement(); } } } if( titles.isEmpty() ) { QStringList refinePossibleLangs = preferredLangs.filter( QRegExp("^(en|fr|de|pl).*$") ); int index = refinePossibleLangs.indexOf( hostLang ); if( (index != -1) && (index < refinePossibleLangs.count() - 1) ) fetchListing( title, refinePossibleLangs.value( index + 1 ).split( QLatin1Char(':') ).back() ); else { clear(); setMessage( i18n( "No information found..." ) ); } return; } QString pattern; switch( currentSelection ) { default: case Artist: pattern = i18nc("Search pattern for an artist or band", ".*\\(.*(artist|band).*\\))").toLatin1(); break; case Composer: pattern = i18nc("Search pattern for a composer", ".*\\(.*(composer|musician).*\\))").toLatin1(); break; case Album: pattern = i18nc("Search pattern for an album", ".*\\(.*(album|score|soundtrack).*\\)").toLatin1(); break; case Track: pattern = i18nc("Search pattern for a song", ".*\\(.*(song|track).*\\)").toLatin1(); break; } pattern.prepend( title ); int patternIndex = titles.indexOf( QRegExp(pattern, Qt::CaseInsensitive) ); const QString result = ( patternIndex != -1 ) ? titles.at( patternIndex ) : titles.first(); fetchWikiUrl( result, hostLang ); // end of the line } void WikipediaEngine::_checkRequireUpdate( Meta::TrackPtr track ) { if( !track ) return; bool updateNeeded(false); switch( currentSelection ) { case WikipediaEngine::Artist: if( track->artist() ) updateNeeded = track->artist()->name() != m_previousTrackMetadata.artist; break; case WikipediaEngine::Composer: if( track->composer() ) updateNeeded = track->composer()->name() != m_previousTrackMetadata.composer; break; case WikipediaEngine::Album: if( track->album() ) updateNeeded = track->album()->name() != m_previousTrackMetadata.album; break; case WikipediaEngine::Track: updateNeeded = track->name() != m_previousTrackMetadata.track; break; } if( updateNeeded ) { m_previousTrackMetadata.clear(); if( track->artist() ) m_previousTrackMetadata.artist = track->artist()->name(); if( track->composer() ) m_previousTrackMetadata.composer = track->composer()->name(); if( track->album() ) m_previousTrackMetadata.album = track->album()->name(); m_previousTrackMetadata.track = track->name(); urls.clear(); updateEngine(); } } void WikipediaEngine::_stopped() { DEBUG_BLOCK clear(); // dataContainer->setData( "stopped", 1 ); m_previousTrackMetadata.clear(); } +void +WikipediaEngine::_paletteChanged( const QPalette &palette ) +{ + DEBUG_BLOCK + + // read css, replace color placeholders, write to file, load into page + QFile file( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/data/WikipediaCustomStyle.css" ) ); + if( file.open(QIODevice::ReadOnly | QIODevice::Text) ) + { + QString contents = QString( file.readAll() ); + contents.replace( "/*{text_color}*/", palette.text().color().name() ); + contents.replace( "/*{link_color}*/", palette.link().color().name() ); + contents.replace( "/*{link_hover_color}*/", palette.linkVisited().color().name() ); + contents.replace( "/*{background_color}*/", palette.base().color().name() ); + + const QString abg = palette.window().color().name(); + contents.replace( "/*{shaded_text_background_color}*/", abg ); + contents.replace( "/*{table_background_color}*/", abg ); + contents.replace( "/*{headings_background_color}*/", abg ); + + const QString atbg = palette.alternateBase().color().name(); + contents.replace( "/*{alternate_table_background_color}*/", atbg ); + + if( m_css == contents ) + return; + + m_css = contents; + updateEngine(); + } + else + { + error() << "Could not load WikipediaCustomStyle.css"; + } +} + void WikipediaEngine::fetchWikiUrl( const QString &title, const QString &urlPrefix ) { QUrl pageUrl; QString host( ".wikipedia.org" ); pageUrl.setScheme( QLatin1String( "https" ) ); // if( useMobileVersion ) // { // host.prepend( ".m" ); // host.prepend( urlPrefix ); // pageUrl.setHost( host ); // pageUrl.setPath( QString("/wiki/%1").arg(title) ); // DataEngine::Data data; // data[QLatin1String("sourceUrl")] = pageUrl; // removeAllData( QLatin1String("wikipedia") ); // setData( QLatin1String("wikipedia"), data ); // return; // } // We now use: http://en.wikipedia.org/w/index.php?title=The_Beatles&useskin=monobook // instead of: http://en.wikipedia.org/wiki/The_Beatles // So that wikipedia skin is forced to default "monoskin", and the page can be parsed correctly (see BUG 205901 ) host.prepend( urlPrefix ); pageUrl.setHost( host ); pageUrl.setPath( QLatin1String("/w/index.php") ); QUrlQuery query; query.addQueryItem( QLatin1String("title"), title ); query.addQueryItem( QLatin1String("redirects"), QString::number(1) ); query.addQueryItem( QLatin1String("useskin"), QLatin1String("monobook") ); pageUrl.setQuery( query ); wikiCurrentUrl = pageUrl; urls << pageUrl; emit urlChanged(); - The::networkAccessManager()->getData( pageUrl, this, - SLOT(_wikiResult(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); + The::networkAccessManager()->getData( pageUrl, this, &WikipediaEngine::_wikiResult ); } void WikipediaEngine::fetchLangLinks( const QString &title, const QString &hostLang, const QString &llcontinue ) { QUrl url; url.setScheme( QLatin1String( "https" ) ); url.setHost( hostLang + QLatin1String(".wikipedia.org") ); url.setPath( QLatin1String("/w/api.php") ); QUrlQuery query; query.addQueryItem( QLatin1String("action"), QLatin1String("query") ); query.addQueryItem( QLatin1String("prop"), QLatin1String("langlinks") ); query.addQueryItem( QLatin1String("titles"), title ); query.addQueryItem( QLatin1String("format"), QLatin1String("xml") ); query.addQueryItem( QLatin1String("lllimit"), QString::number(100) ); query.addQueryItem( QLatin1String("redirects"), QString::number(1) ); if( !llcontinue.isEmpty() ) query.addQueryItem( QLatin1String("llcontinue"), llcontinue ); url.setQuery( query ); urls << url; debug() << "Fetching langlinks:" << url; - The::networkAccessManager()->getData( url, this, - SLOT(_parseLangLinksResult(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); + The::networkAccessManager()->getData( url, this, &WikipediaEngine::_parseLangLinksResult ); } void WikipediaEngine::fetchListing( const QString &title, const QString &hostLang ) { QUrl url; url.setScheme( QLatin1String( "https" ) ); url.setHost( hostLang + QLatin1String(".wikipedia.org") ); url.setPath( QLatin1String("/w/api.php") ); QUrlQuery query; query.addQueryItem( QLatin1String("action"), QLatin1String("query") ); query.addQueryItem( QLatin1String("list"), QLatin1String("search") ); query.addQueryItem( QLatin1String("srsearch"), title ); query.addQueryItem( QLatin1String("srprop"), QLatin1String("size") ); query.addQueryItem( QLatin1String("srredirects"), QString::number(1) ); query.addQueryItem( QLatin1String("srlimit"), QString::number(20) ); query.addQueryItem( QLatin1String("format"), QLatin1String("xml") ); url.setQuery( query ); urls << url; debug() << "Fetching listing:" << url; - The::networkAccessManager()->getData( url, this, - SLOT(_parseListingResult(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); + The::networkAccessManager()->getData( url, this, &WikipediaEngine::_parseListingResult ); } void WikipediaEngine::updateEngine() { static QMap typeToFieldMap; if( typeToFieldMap.isEmpty() ) { typeToFieldMap.insert( Artist, Meta::valArtist ); typeToFieldMap.insert( Composer, Meta::valComposer ); typeToFieldMap.insert( Album, Meta::valAlbum ); typeToFieldMap.insert( Track, Meta::valTitle ); } Meta::TrackPtr currentTrack = The::engineController()->currentTrack(); if( !currentTrack ) return; //TODO: Look into writing one function that can be used with different arguments for each case in this switch. QString tmpWikiStr; QString notice = i18nc( "%1 is field name such as 'Artist Name'", "%1 is needed for searching Wikipedia.", Meta::i18nForField( typeToFieldMap.value( currentSelection ) ) ); switch( currentSelection ) { case Artist: if( currentTrack->artist() ) { if( currentTrack->artist()->name().isEmpty() ) { clear(); setMessage( notice ); return; } if( ( currentTrack->playableUrl().scheme() == QLatin1String("lastfm") ) || ( currentTrack->playableUrl().scheme() == QLatin1String("daap") ) || !The::engineController()->isStream() ) tmpWikiStr = currentTrack->artist()->name(); else tmpWikiStr = currentTrack->artist()->prettyName(); } break; case Composer: if( currentTrack->composer() ) { if( currentTrack->composer()->name().isEmpty() ) { clear(); setMessage( notice ); return; } if( ( currentTrack->playableUrl().scheme() == QLatin1String("lastfm") ) || ( currentTrack->playableUrl().scheme() == QLatin1String("daap") ) || !The::engineController()->isStream() ) tmpWikiStr = currentTrack->composer()->name(); } break; case Album: if( currentTrack->album() ) { if( currentTrack->album()->name().isEmpty() ) { clear(); setMessage( notice ); return; } if( ( currentTrack->playableUrl().scheme() == QLatin1String("lastfm") ) || ( currentTrack->playableUrl().scheme() == QLatin1String("daap") ) || !The::engineController()->isStream() ) tmpWikiStr = currentTrack->album()->name(); } break; case Track: if( currentTrack->name().isEmpty() ) { clear(); setMessage( notice ); return; } tmpWikiStr = currentTrack->prettyName(); break; } //Hack to make wiki searches work with magnatune preview tracks if( tmpWikiStr.contains( QLatin1String("PREVIEW: buy it at www.magnatune.com") ) ) { tmpWikiStr = tmpWikiStr.remove(QLatin1String(" (PREVIEW: buy it at www.magnatune.com)") ); int index = tmpWikiStr.indexOf( QLatin1Char('-') ); if( index != -1 ) tmpWikiStr = tmpWikiStr.left (index - 1); } if( preferredLangs.isEmpty() ) preferredLangs = QStringList() << QLatin1String("en:en"); fetchLangLinks( tmpWikiStr, preferredLangs.first().split( QLatin1Char(':') ).back() ); } void WikipediaEngine::wikiParse( QString &wiki ) { //remove the new-lines and tabs(replace with spaces IS needed). - wiki.replace( '\n', QLatin1Char(' ') ); - wiki.replace( '\t', QLatin1Char(' ') ); +// wiki.replace( '\n', QLatin1Char(' ') ); +// wiki.replace( '\t', QLatin1Char(' ') ); // Get the available language list QString wikiLanguagesSection; QMap langMap; int langSectionIndex = 0; if( (langSectionIndex = wiki.indexOf( QLatin1String("
") )) != -1 ) { QStringRef sref = wiki.midRef( langSectionIndex ); sref = wiki.midRef( sref.position(), wiki.indexOf( QLatin1String("
    "), sref.position() ) - sref.position() ); sref = wiki.midRef( sref.position(), wiki.indexOf( QLatin1String(""), sref.position() ) - sref.position() ); wikiLanguagesSection = sref.toString(); QXmlStreamReader xml( wikiLanguagesSection ); while( !xml.atEnd() && !xml.hasError() ) { xml.readNext(); if( xml.isStartElement() && xml.name() == QLatin1String("li") ) { while( xml.readNextStartElement() ) { if( xml.name() == QLatin1String("a") ) { QString url = xml.attributes().value( QLatin1String("href") ).toString(); langMap[ xml.readElementText() ] = url; } else xml.skipCurrentElement(); } } } } QString copyright; const QString copyrightMark = QLatin1String("
  • "); int copyrightIndex = wiki.indexOf( copyrightMark ); if( copyrightIndex != -1 ) { QStringRef sref = wiki.midRef( copyrightIndex + copyrightMark.length() ); sref = wiki.midRef( sref.position(), wiki.indexOf( QLatin1String("
  • "), sref.position() ) - sref.position() ); copyright = sref.toString(); copyright.remove( QLatin1String("
    ") ); //only one br at the beginning copyright.prepend( QLatin1String("
    ") ); } const int titleIndex = wiki.indexOf( QRegExp( QLatin1String("[^<]*") ) ) + 7; const int bsTitleIndex = wiki.indexOf( QLatin1String(""), titleIndex ) - titleIndex; const QString title = wiki.mid( titleIndex, bsTitleIndex ); // Ok lets remove the top and bottom parts of the page QStringRef wikiRef; wikiRef = wiki.midRef( wiki.indexOf( QLatin1String("") ) ); wikiRef = wiki.midRef( wikiRef.position(), wiki.indexOf( QLatin1String("
    "), wikiRef.position() ) - wikiRef.position() ); wiki = wikiRef.toString(); auto removeTag = [&wiki] ( const QString& tagStart, const QString& tagEnd ) { const int tagEndSize = tagEnd.size(); int matchIndex = 0; const QStringMatcher tagMatcher( tagStart ); while( ( matchIndex = tagMatcher.indexIn( wiki, matchIndex ) ) != -1 ) { const int nToTagEnd = wiki.indexOf( tagEnd, matchIndex ) - matchIndex; const QStringRef tagRef = wiki.midRef( matchIndex, nToTagEnd + tagEndSize ); wiki.remove( tagRef.toString() ); } }; + QString header = QString( "\n\n%1\n\n\n" ).arg( title ); + + // add own stylesheet + if( !m_css.isEmpty() ) + { + removeTag( "" ); + int index = header.indexOf( QStringLiteral( "" ) ); + header.insert( index, QString( "\n\n" ).arg( m_css ) ); + } + + wiki.prepend( header ); + // lets remove the warning box removeTag( "" ); // remove protection policy (we don't do edits) removeTag( "
    " ); // lets also remove the "lock" image removeTag( "" ); // remove
    ") ); wiki.remove( QRegExp( QLatin1String("

    [^<]*

    ") ) ); wiki.remove( QRegExp( QLatin1String("]*>[^<]*<[^>]*>[^<]*<[^>]*>[^<]*") ) ); wiki.remove( QRegExp( QLatin1String("

    ]*><[^\"]*\"#_skip_noteTA\">[^<]*<[^<]*

    ") ) ); wiki.replace( QRegExp( QLatin1String("
    ]*>([^<]*)") ), QLatin1String("\\1") ); // Remove anything inside of a class called urlexpansion, as it's pointless for us wiki.remove( QRegExp( QLatin1String("[^(]*[(][^)]*[)]") ) ); // Remove hidden table rows as well QRegExp hidden( QLatin1String("
    .*"), Qt::CaseInsensitive ); hidden.setMinimal( true ); //greedy behaviour wouldn't be any good! wiki.remove( hidden ); // we want to keep our own style (we need to modify the stylesheet a bit to handle things nicely) wiki.remove( QRegExp( QLatin1String("style= *\"[^\"]*\"") ) ); - // We need to leave the classes behind, otherwise styling it ourselves gets really nasty and tedious and roughly impossible to do in a sane maner + // We need to leave the classes behind, otherwise styling it ourselves gets really nasty and tedious and roughly impossible to do in a sane manner //wiki.replace( QRegExp( "class= *\"[^\"]*\"" ), QString() ); // let's remove the form elements, we don't want them. wiki.remove( QRegExp( QLatin1String("]*>") ) ); wiki.remove( QRegExp( QLatin1String("]*>") ) ); wiki.remove( QLatin1String("\n") ); wiki.remove( QRegExp( QLatin1String("]*>") ) ); wiki.remove( QLatin1String("\n") ); wiki.remove( QRegExp( QLatin1String("]*>") ) ); wiki.remove( QLatin1String("") ); - wiki.prepend( QLatin1String("\n") ); - wiki.append( QString(QLatin1String("%1\n")).arg(title) ); - wiki.append( QLatin1String("\n") ); // wiki.append( createLanguageComboBox(langMap) ); // BUG:259075 wiki.append( QLatin1String("\n") ); } QString WikipediaEngine::createLanguageComboBox( const QMap &languageMap ) { if( languageMap.isEmpty() ) return QString(); QString html; QMapIterator i(languageMap); while( i.hasNext() ) { i.next(); html += QString( "" ).arg( i.value(), i.key() ); } html.prepend( QString("
    ") ); return html; } void WikipediaEngine::reloadWikipedia() { if( !wikiCurrentUrl.isValid() ) return; urls << wikiCurrentUrl; setBusy( true ); - The::networkAccessManager()->getData( wikiCurrentUrl, this, - SLOT(_wikiResult(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); + The::networkAccessManager()->getData( wikiCurrentUrl, this, &WikipediaEngine::_wikiResult ); } WikipediaEngine::SelectionType WikipediaEngine::selection() const { return currentSelection; } bool WikipediaEngine::setSelection( SelectionType type ) { if( currentSelection == type ) return false; currentSelection = type; emit selectionChanged(); updateEngine(); return true; } bool WikipediaEngine::setSelection( const QString &type ) { bool changed( false ); if( type == QLatin1String("artist") ) changed = setSelection( Artist ); else if( type == QLatin1String("composer") ) changed = setSelection( Composer ); else if( type == QLatin1String("album") ) changed = setSelection( Album ); else if( type == QLatin1String("track") ) changed = setSelection( Track ); return changed; } void WikipediaEngine::setPage(const QString& page) { if( m_page == page ) return; m_page = page; emit pageChanged(); } void WikipediaEngine::setMessage(const QString& message) { if( m_message == message ) return; m_message = message; emit messageChanged(); } void WikipediaEngine::setBusy(bool busy) { if( m_busy == busy ) return; m_busy = busy; emit busyChanged(); } void WikipediaEngine::setTitle(const QString& title) { if( m_title == title ) return; m_title = title; emit titleChanged(); } void WikipediaEngine::clear() { setPage( QString() ); setBusy( false ); setTitle( QString() ); } void WikipediaEngine::setLanguage(const QString& language) { if( preferredLangs.first() == language ) return; preferredLangs.removeAll( language ); preferredLangs.prepend( language ); emit languageChanged(); updateEngine(); } void WikipediaEngine::setUrl(const QUrl& url) { if( wikiCurrentUrl == url ) return; wikiCurrentUrl = url; urls << url; emit urlChanged(); - The::networkAccessManager()->getData( url, this, SLOT(_wikiResult(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); + The::networkAccessManager()->getData( url, this, &WikipediaEngine::_wikiResult ); } diff --git a/src/context/applets/wikipedia/plugin/WikipediaEngine.h b/src/context/applets/wikipedia/plugin/WikipediaEngine.h index f995d7729b..b7e082132d 100644 --- a/src/context/applets/wikipedia/plugin/WikipediaEngine.h +++ b/src/context/applets/wikipedia/plugin/WikipediaEngine.h @@ -1,122 +1,125 @@ /**************************************************************************************** * Copyright (c) 2007 Leo Franchi * * Copyright (c) 2008 Mark Kretschmann * * Copyright (c) 2009 Simon Esneault * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #ifndef AMAROK_WIKIPEDIA_ENGINE #define AMAROK_WIKIPEDIA_ENGINE #include "core/meta/Meta.h" #include "network/NetworkAccessManagerProxy.h" #include +#include class WikipediaEngine : public QObject { Q_OBJECT Q_PROPERTY(QString page READ page NOTIFY pageChanged) Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) Q_PROPERTY(QString message READ message NOTIFY messageChanged) Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) Q_PROPERTY(SelectionType selection READ selection WRITE setSelection NOTIFY selectionChanged) Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged) public: enum SelectionType { Artist, Composer, Album, Track }; Q_ENUM(SelectionType) WikipediaEngine( QObject* parent = Q_NULLPTR ); virtual ~WikipediaEngine(); QString page() const { return m_page; } QUrl url() const { return wikiCurrentUrl; } void setUrl( const QUrl &url ); QString message() const { return m_message; } bool busy() const { return m_busy; } SelectionType selection() const; bool setSelection( SelectionType type ); // returns true if selection is changed QString title() const { return m_title; } QString language() const { return preferredLangs.first(); } void setLanguage( const QString &language ); signals: void pageChanged(); void messageChanged(); void busyChanged(); void selectionChanged(); void languageChanged(); void titleChanged(); void urlChanged(); private: void fetchWikiUrl( const QString &title, const QString &urlPrefix ); void fetchLangLinks( const QString &title, const QString &hostLang, const QString &llcontinue = QString() ); void fetchListing( const QString &title, const QString &hostLang ); void reloadWikipedia(); bool setSelection( const QString &type ); void updateEngine(); void wikiParse( QString &page ); QString createLanguageComboBox( const QMap &languageMap ); void setPage( const QString &page ); void setMessage( const QString &message ); void setBusy( bool busy ); void setTitle( const QString &title ); void clear(); SelectionType currentSelection; QUrl wikiCurrentUrl; QStringList preferredLangs; struct TrackMetadata { QString artist; QString composer; QString album; QString track; void clear() { artist.clear(); composer.clear(); album.clear(); track.clear(); } } m_previousTrackMetadata; bool useMobileVersion; QSet< QUrl > urls; QString m_page; QString m_message; bool m_busy; QString m_title; + QString m_css; private slots: void _checkRequireUpdate( Meta::TrackPtr track ); void _parseLangLinksResult( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ); void _parseListingResult( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ); void _wikiResult( const QUrl &url, QByteArray result, NetworkAccessManagerProxy::Error e ); void _stopped(); + void _paletteChanged( const QPalette &palette ); }; #endif diff --git a/src/context/context_qml_package/contents/ui/main.qml b/src/context/context_qml_package/contents/ui/main.qml index 5d805a30f8..c707e575e4 100644 --- a/src/context/context_qml_package/contents/ui/main.qml +++ b/src/context/context_qml_package/contents/ui/main.qml @@ -1,117 +1,117 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ import QtQuick 2.4 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.2 import QtQml.Models 2.2 import org.kde.kirigami 2.0 as Kirigami import "toolbar" Item { id: root Component.onCompleted: Context.debug("Context created") ColumnLayout { anchors.fill: parent ListView { id: appletListView signal scrollToApplet(string id) Layout.alignment: Qt.AlignTop Layout.fillHeight: true Layout.fillWidth: true spacing: Kirigami.Units.smallSpacing displayMarginEnd: 100000 displayMarginBeginning: 100000 clip: true model: AppletProxyModel ScrollBar.vertical: ScrollBar { id: scrollBar } delegate: Loader { width: scrollBar.visible ? parent.width - scrollBar.width : parent.width active: true asynchronous: true function initialize() { setSource(mainscript, { "name": name, "appletId": appletId, - "iconSource": "image://icon/" + icon, + "iconSource": icon, "collapsed": collapsed, "contentHeight": contentHeight, "packagePath": packagePath, "configEnabled": Qt.binding(function() { return appletToolbar.configEnabled; } ) }); } Component.onCompleted: initialize() onStatusChanged: { if (status == Loader.Error) { Context.error("Error loading applet: " + appletId); Context.error(sourceComponent.errorString()); } if (status == Loader.Ready) { Context.debug("Applet loaded: " + appletId); } } Connections { target: AppletProxyModel onDataChanged: { if (!!mainscript && mainscript != source) { Context.debug("Data changed for applet " + appletId); initialize(); } } } Connections { target: appletListView onScrollToApplet: { if (id == appletId) { appletListView.positionViewAtIndex(index, ListView.Beginning); Context.debug("Scroll to applet: " + appletId); } } } } } AppletToolbarAddItem { id: appletToolbarAddItem Layout.fillWidth: true height: Kirigami.Units.iconSizes.enormous visible: appletToolbar.configEnabled } AppletToolbar { id: appletToolbar contextRoot: root addItem: appletToolbarAddItem listView: appletListView Layout.alignment: Qt.AlignBottom Layout.fillWidth: true } } } diff --git a/src/context/context_qml_package/contents/ui/toolbar/AppletToolbarAddItem.qml b/src/context/context_qml_package/contents/ui/toolbar/AppletToolbarAddItem.qml index 4afca27c7c..d2cc5c7e61 100644 --- a/src/context/context_qml_package/contents/ui/toolbar/AppletToolbarAddItem.qml +++ b/src/context/context_qml_package/contents/ui/toolbar/AppletToolbarAddItem.qml @@ -1,85 +1,86 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.0 as Kirigami ScrollView { id: root verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff frameVisible: true ListView { id: listView anchors.margins: Kirigami.Units.smallSpacing orientation: ListView.Horizontal spacing: Kirigami.Units.smallSpacing model: AppletModel delegate: Rectangle { readonly property bool appletEnabled: AppletProxyModel.enabledApplets.indexOf(appletId) != -1 height: root.height - 3 * Kirigami.Units.smallSpacing width: height radius: Kirigami.Units.smallSpacing color: delegateMouseArea.pressed ? palette.highlight : appletEnabled ? palette.highlight : "transparent" border.color: delegateMouseArea.containsMouse ? palette.highlight : "transparent" border.width: 2 ColumnLayout { anchors.fill: parent Image { - source: "image://icon/" + icon + source: icon Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignTop Layout.margins: Kirigami.Units.smallSpacing sourceSize.width: width sourceSize.height: height + fillMode: Image.PreserveAspectFit } Label { Layout.alignment: Qt.AlignBottom Layout.margins: Kirigami.Units.smallSpacing Layout.fillWidth: true text: name wrapMode: Text.Wrap horizontalAlignment: Text.AlignHCenter } } MouseArea { id: delegateMouseArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton onClicked: AppletProxyModel.setAppletEnabled(appletId, !appletEnabled); } } SystemPalette { id: palette } } } diff --git a/src/context/qml_plugin/Applet.qml b/src/context/qml_plugin/Applet.qml index 46e15a62c7..2879a1f889 100644 --- a/src/context/qml_plugin/Applet.qml +++ b/src/context/qml_plugin/Applet.qml @@ -1,101 +1,106 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ import QtQuick 2.4 import QtQuick.Dialogs 1.2 import org.kde.kirigami 2.0 as Kirigami import org.kde.kirigami 2.0 as Kirigami Rectangle { id: root default property alias contents: content.data property alias title: header.title property string name: "Nameless Applet" property string appletId property string packagePath property url iconSource property bool collapsed: false property bool configEnabled: false property real spacing: Kirigami.Units.smallSpacing property real padding: spacing property real contentHeight: content.childrenRect.height property Dialog configDialog: null + readonly property AppletHeader appletHeader: header readonly property SystemPalette palette: palette radius: Kirigami.Units.smallSpacing border.width: 2 border.color: palette.mid color: "transparent" clip: true height: content.height + header.height + 2 * padding + !collapsed * spacing + function imageUrl(filename) { + return AppletModel.imageUrl(root.appletId, filename); + } + onCollapsedChanged: AppletModel.setAppletCollapsed(appletId, collapsed) onContentHeightChanged: AppletModel.setAppletContentHeight(appletId, contentHeight) AppletHeader { id: header title: root.name iconSource: root.iconSource } Item { id: content anchors { top: header.bottom left: root.left right: root.right topMargin: root.spacing leftMargin: root.padding rightMargin: root.padding } height: root.collapsed ? 0 : root.contentHeight clip: true Behavior on height { enabled: !resizeMouseArea.pressed NumberAnimation { duration: 350 } } } MouseArea { id: resizeMouseArea anchors { bottom: parent.bottom left: parent.left right: parent.right } height: root.padding enabled: root.configEnabled cursorShape: enabled ? Qt.SizeVerCursor : Qt.ArrowCursor acceptedButtons: Qt.LeftButton preventStealing: true onMouseYChanged: { if(pressed) { root.contentHeight = Math.max(Kirigami.Units.largeSpacing, root.contentHeight + mouseY); } } } SystemPalette { id: palette } } diff --git a/src/context/qml_plugin/AppletHeader.qml b/src/context/qml_plugin/AppletHeader.qml index 25ffd41c54..ce18f6568d 100644 --- a/src/context/qml_plugin/AppletHeader.qml +++ b/src/context/qml_plugin/AppletHeader.qml @@ -1,75 +1,76 @@ /**************************************************************************************** * Copyright (c) 2017 Malte Veerman * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 RowLayout { id: root property var applet: parent property alias title: label.text property alias iconSource: icon.source anchors { left: parent.left right: parent.right top: parent.top margins: parent.padding } height: collapseButton.height Image { id: icon height: collapseButton.height width: height sourceSize.width: width sourceSize.height: height + fillMode: Image.PreserveAspectFit Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } Label { id: label text: root.title fontSizeMode: Text.VerticalFit horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter } ToolButton { id: configButton visible: applet.configEnabled && !!applet.configDialog iconName: "preferences-other" Layout.alignment: Qt.AlignRight | Qt.AlignVCenter onClicked: applet.configDialog.open() } ToolButton { id: collapseButton //TODO: Icons are not part of official standard. Maybe provide our own icons? iconName: !applet.collapsed ? "window-minimize" : "window-restore" Layout.alignment: Qt.AlignRight | Qt.AlignVCenter onClicked: applet.collapsed = applet.collapsed ? false : true } } diff --git a/src/main.cpp b/src/main.cpp index b2377b6f67..9c87bc143e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,344 +1,353 @@ /**************************************************************************************** * Copyright (c) 2002 Mark Kretschmann * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #include "core/support/Amarok.h" #include "core/support/Debug.h" #include "App.h" #include "aboutdialog/OcsData.h" #include #include #include #include #include +#ifdef WITH_QT_WEBENGINE + #include +#endif + #ifdef Q_WS_X11 #include #endif #include #ifdef Q_OS_WIN AMAROK_EXPORT OcsData ocsData; #endif int main( int argc, char *argv[] ) { App app(argc, argv); + +#ifdef WITH_QT_WEBENGINE + QtWebEngine::initialize(); +#endif + app.setApplicationDisplayName(i18n("Amarok")); QCoreApplication::setApplicationName("amarok"); QCoreApplication::setOrganizationDomain("kde.org"); QCoreApplication::setApplicationVersion(AMAROK_VERSION); KAboutData aboutData( "amarok", ki18n( "Amarok" ).toString(), AMAROK_VERSION, ki18n( "The audio player by KDE" ).toString(), KAboutLicense::GPL, ki18n( "(C) 2002-2003, Mark Kretschmann\n(C) 2003-2013, The Amarok Development Squad" ).toString(), ki18n( "IRC:\nirc.freenode.net - #amarok, #amarok.de, #amarok.es, #amarok.fr\n\nFeedback:\namarok@kde.org\n\n(Build Date: %1)" ).subs( __DATE__ ).toString(), ( "http://amarok.kde.org" ) ); //------------ About data ---------------------- //Currently active Authors extern OcsData ocsData; aboutData.addAuthor( ki18n("Bart 'Where are my toothpicks' Cerneels").toString(), ki18n("Developer (Stecchino)").toString(), "bart.cerneels@kde.org", "http://commonideas.blogspot.com" ); ocsData.addAuthor( "Stecchino", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Edward \"Hades\" Toroshchin").toString(), ki18n("Developer (dr_lepper)").toString(), "edward.hades@gmail.com" ); ocsData.addAuthor( "hadeschief", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Mark Kretschmann" ).toString(), ki18n("Project founder (markey)").toString(), "kretschmann@kde.org", "https://plus.google.com/102602725322221030250/posts" ); ocsData.addAuthor( "MarkKretschmann", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Matěj Laitl").toString(), ki18n("iPod collection rewrite & more (strohel)").toString(), "matej@laitl.cz", "http://strohel.blogspot.com/" ); ocsData.addAuthor( "strohel", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Myriam Schweingruber").toString(), ki18n("Rokymoter, Bug triaging (Mamarok)").toString(), "myriam@kde.org", "http://blogs.fsfe.org/myriam" ); ocsData.addAuthor( "Mamarok", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Ralf 'SalsaMaster' Engels").toString(), ki18n("Developer (rengels)").toString(), "ralf.engels@nokia.com" ); ocsData.addAuthor( QString(), aboutData.authors().last() ); aboutData.addAuthor( ki18n("Patrick von Reth").toString(), ki18n("Windows build (TheOneRing)").toString(), "patrick.vonreth@gmail.com" ); ocsData.addAuthor( QString(), aboutData.authors().last() ); aboutData.addAuthor( ki18n("Rick W. Chen").toString(), ki18n("Developer (stuffcorpse)").toString(), "stuffcorpse@archlinux.us" ); ocsData.addAuthor( "stuffcorpse", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Sam Lade").toString(), ki18n("Developer (Sentynel)").toString(), "sam@sentynel.com" ); ocsData.addAuthor( "Sentynel", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Sven Krohlas").toString(), ki18n("Rokymoter, Developer (sven423)").toString(), "sven@asbest-online.de" ); ocsData.addAuthor( "krohlas", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Téo Mrnjavac").toString(), ki18n("Developer (Teo`)").toString(), "teo@kde.org", "http://teom.wordpress.com/" ); ocsData.addAuthor( "teom", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Valorie Zimmerman").toString(), ki18n("Rokymoter, Handbook (valorie)").toString(), "valorie@kde.org" ); ocsData.addAuthor( "valorie", aboutData.authors().last() ); //Inactive authors /* This list should contain people who still hold major copyright on the current code * For instance: does not include authors of 1.4 who have not contributed to 2.x */ aboutData.addAuthor( ki18n("Inactive authors").toString(), ki18n("Amarok authorship is not a hobby, it's a lifestyle. " "But when people move on we want to keep respecting " "them by mentioning them here:").toString(), "" ); ocsData.addAuthor( "%%category%%", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Ian 'The Beard' Monroe").toString(), ki18n("Developer (eean)").toString(), "ian@monroe.nu" ); ocsData.addAuthor( "eean", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Jeff 'IROKSOHARD' Mitchell").toString(), ki18n("Developer (jefferai)").toString(), "mitchell@kde.org" ); ocsData.addAuthor( "jefferai", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Leo Franchi").toString(), ki18n("Developer (lfranchi)").toString(), "lfranchi@kde.org" ); ocsData.addAuthor( "lfranchi", aboutData.authors().last() ); aboutData.addAuthor( ki18n("Lydia 'is wrong(TM)' Pintscher").toString(), ki18n("Release Vixen (Nightrose)").toString(), "lydia@kde.org" ); ocsData.addAuthor( "nightrose", aboutData.authors().last() ); aboutData.addCredit( ki18n("Max Howell").toString(), ki18n("Developer, Vision").toString(), "max.howell@methylblue.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addAuthor( ki18n("Maximilian Kossick").toString(), ki18n("Developer (maxx_k)").toString(), "maximilian.kossick@gmail.com" ); ocsData.addAuthor( QString(), aboutData.authors().last() ); aboutData.addAuthor( ki18n("Nikolaj Hald 'Also very hot' Nielsen").toString(), ki18n("Developer (nhn)").toString(), "nhn@kde.org" ); ocsData.addAuthor( "nhnFreespirit", aboutData.authors().last() ); aboutData.addCredit( ki18n("Seb 'Surfin' down under' Ruiz").toString(), ki18n("Developer (sebr)").toString(), "ruiz@kde.org" ); ocsData.addCredit( "seb", aboutData.credits().last() ); //Contributors aboutData.addCredit( ki18n("Alejandro Wainzinger").toString(), ki18n("Developer (xevix)").toString(), "aikawarazuni@gmail.com" ); ocsData.addCredit( "xevix", aboutData.credits().last() ); aboutData.addCredit( ki18n("Alex Merry").toString(), ki18n("Developer, Replay Gain support").toString(), "kde@randomguy3.me.uk" ); ocsData.addCredit( "randomguy3", aboutData.credits().last() ); aboutData.addCredit( ki18n("Casey Link").toString(), ki18n("MP3tunes integration").toString(), "unnamedrambler@gmail.com" ); ocsData.addCredit( "Ramblurr", aboutData.credits().last() ); aboutData.addCredit( ki18n("Casper van Donderen").toString(), ki18n("Windows porting").toString(), "casper.vandonderen@gmail.com" ); ocsData.addCredit( "cvandonderen", aboutData.credits().last() ); aboutData.addCredit( ki18n("Christie Harris").toString(), ki18n("Rokymoter (dangle)").toString(), "dangle.baby@gmail.com" ); ocsData.addCredit( "dangle", aboutData.credits().last() ); aboutData.addCredit( ki18n("Dan Leinir Turthra Jensen").toString(), ki18n("Usability").toString(), "admin@leinir.dk" ); ocsData.addCredit( "leinir", aboutData.credits().last() ); aboutData.addCredit( ki18n("Dan 'Hey, it compiled...' Meltzer").toString(), ki18n("Developer (hydrogen)").toString(), "parallelgrapefruit@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Daniel Caleb Jones").toString(), ki18n("Biased playlists").toString(), "danielcjones@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Daniel Dewald").toString(), ki18n("Tag Guesser, Labels, Spectrum Analyzer").toString(), "Daniel.Dewald@time-shift.de" ); ocsData.addCredit( "TheCrasher", aboutData.credits().last() ); aboutData.addCredit( ki18n("Daniel Winter").toString(), ki18n("Nepomuk integration").toString(), "dw@danielwinter.de" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Frank Meerkötter").toString(), ki18n("Podcast improvements").toString(), "frank@meerkoetter.org" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Greg Meyer").toString(), ki18n("Live CD, Bug squashing (oggb4mp3)").toString(), "greg@gkmweb.com" ); ocsData.addCredit( "oggb4mp3", aboutData.credits().last() ); aboutData.addCredit( ki18n("Harald Sitter").toString(), ki18n("Phonon, Lord-President of KDE Multimedia (apachelogger)").toString(), "harald.sitter@kdemail.net" ); ocsData.addCredit( "apachelogger", aboutData.credits().last() ); aboutData.addCredit( ki18n("John Atkinson").toString(), ki18n("Assorted patches").toString(), "john@fauxnetic.co.uk" ); ocsData.addCredit( "fauxnetic", aboutData.credits().last() ); aboutData.addCredit( ki18n("Kenneth Wesley Wimer II").toString(), ki18n("Icons").toString(), "kwwii@bootsplash.org" ); ocsData.addCredit( "kwwii", aboutData.credits().last() ); aboutData.addCredit( ki18n("Kevin Funk").toString(), ki18n("Developer, Website theme (KRF)").toString(), "krf@electrostorm.net" ); ocsData.addCredit( "krf", aboutData.credits().last() ); aboutData.addCredit( ki18n("Kuba Serafinowski").toString(), ki18n("Rokymoter").toString(), "zizzfizzix@gmail.com" ); ocsData.addCredit( "zizzfizzix", aboutData.credits().last() ); aboutData.addCredit( ki18n("Lee Olson").toString(), ki18n("Artwork").toString(), "leetolson@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Ljubomir Simin").toString(), ki18n("Rokymoter (ljubomir)").toString(), "ljubomir.simin@gmail.com" ); ocsData.addCredit( "ljubomir", aboutData.credits().last() ); aboutData.addCredit( ki18n("Lucas Gomes").toString(), ki18n("Developer (MaskMaster)").toString(), "x8lucas8x@gmail.com" ); ocsData.addCredit( "x8lucas8x", aboutData.credits().last() ); aboutData.addCredit( ki18n("Mathias Panzenböck").toString(), ki18n("Podcast improvements").toString(), "grosser.meister.morti@gmx.net" ); ocsData.addCredit( "panzi", aboutData.credits().last() ); aboutData.addCredit( ki18n("Mikko Caldara").toString(), ki18n("Bug triaging and sanitizing").toString(), "mikko.cal@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Nikhil Marathe").toString(), ki18n("UPnP support and patches (nsm)").toString(), "nsm.nikhil@gmail.com" ); ocsData.addCredit( "nikhilm", aboutData.credits().last() ); aboutData.addCredit( ki18n("Nuno Pinheiro").toString(), ki18n("Artwork").toString(), "nuno@oxygen-icons.org" ); ocsData.addCredit( "nunopinheirokde", aboutData.credits().last() ); aboutData.addCredit( ki18n("Olivier Bédard").toString(), ki18n("Website hosting").toString(), "paleo@pwsp.net" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Pasi Lalinaho").toString(), ki18n("Rokymoter (emunkki)").toString(), "pasi@getamarok.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Peter Zhou Lei").toString(), ki18n("Scripting interface").toString(), "peterzhoulei@gmail.com" ); ocsData.addCredit( "peterzl", aboutData.credits().last() ); aboutData.addCredit( ki18n("Phalgun Guduthur").toString(), ki18n("Nepomuk Collection (phalgun)").toString(), "me@phalgun.in" ); ocsData.addCredit( "phalgun", aboutData.credits().last() ); aboutData.addCredit( ki18n("Scott Wheeler").toString(), ki18n("TagLib & ktrm code").toString(), "wheeler@kde.org" ); ocsData.addCredit( "wheels", aboutData.credits().last() ); aboutData.addCredit( ki18n("Shane King").toString(), ki18n("Patches & Windows porting (shakes)").toString(), "kde@dontletsstart.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Simon Esneault").toString(), ki18n("Photos & Videos applets, Context View").toString(), "simon.esneault@gmail.com" ); ocsData.addCredit( "Takahani", aboutData.credits().last() ); aboutData.addCredit( ki18n("Soren Harward").toString(), ki18n("Developer, Automated Playlist Generator").toString(), "stharward@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Thomas Lübking").toString(), ki18n("Developer").toString(), "thomas.luebking@web.de" ); ocsData.addCredit( "thomas12777", aboutData.credits().last() ); aboutData.addCredit( ki18n("Valentin Rouet").toString(), ki18n("Developer").toString(), "v.rouet@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Wade Olson").toString(), ki18n("Splash screen artist").toString(), "wade@corefunction.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("William Viana Soares").toString(), ki18n("Context view").toString(), "vianasw@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); //Former Contributors aboutData.addCredit( ki18n("Former contributors").toString(), ki18n("People listed below have contributed to Amarok in the past. Thank you!").toString(), "" ); ocsData.addCredit( "%%category%%", aboutData.credits().last() ); aboutData.addCredit( ki18n("Adam Pigg").toString(), ki18n("Analyzers, patches, shoutcast").toString(), "adam@piggz.co.uk" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Adeodato Simó").toString(), ki18n("Patches").toString(), "asp16@alu.ua.es" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Alexandre Oliveira").toString(), ki18n("Developer").toString(), "aleprj@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Andreas Mair").toString(), ki18n("MySQL support").toString(), "am_ml@linogate.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Andrew de Quincey").toString(), ki18n("Postgresql support").toString(), "adq_dvb@lidskialf.net" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Andrew Turner").toString(), ki18n("Patches").toString(), "andrewturner512@googlemail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Andy Kelk").toString(), ki18n("MTP and Rio Karma media devices, patches").toString(), "andy@mopoke.co.uk" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Christian Muehlhaeuser").toString(), ki18n("Developer").toString(), "chris@chris.de" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Derek Nelson").toString(), ki18n("Graphics, splash-screen").toString(), "admrla@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Enrico Ros").toString(), ki18n("Analyzers, Context Browser and systray eye-candy").toString(), "eros.kde@email.it" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Frederik Holljen").toString(), ki18n("Developer").toString(), "fh@ez.no" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Gábor Lehel").toString(), ki18n("Developer").toString(), "illissius@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Gérard Dürrmeyer").toString(), ki18n("Icons and image work").toString(), "gerard@randomtree.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Giovanni Venturi").toString(), ki18n("Dialog to filter the collection titles").toString(), "giovanni@ksniffer.org" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Jarkko Lehti").toString(), ki18n("Tester, IRC channel operator, whipping").toString(), "grue@iki.fi" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Jocke Andersson").toString(), ki18n("Rokymoter, bug fixer (Firetech)").toString(), "ajocke@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Marco Gulino").toString(), ki18n("Konqueror Sidebar, some DCOP methods").toString(), "marco@kmobiletools.org" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Martin Aumueller").toString(), ki18n("Developer").toString(), "aumuell@reserv.at" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Melchior Franz").toString(), ki18n("FHT routine, bugfixes").toString(), "mfranz@kde.org" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Michael Pyne").toString(), ki18n("K3b export code").toString(), "michael.pyne@kdemail.net" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Mike Diehl").toString(), ki18n("Developer").toString(), "madpenguin8@yahoo.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Paul Cifarelli").toString(), ki18n("Developer").toString(), "paul@cifarelli.net" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Peter C. Ndikuwera").toString(), ki18n("Bugfixes, PostgreSQL support").toString(), "pndiku@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Pierpaolo Panfilo").toString(), ki18n("Developer").toString(), "pippo_dp@libero.it" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Reigo Reinmets").toString(), ki18n("Wikipedia support, patches").toString(), "xatax@hot.ee" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Roman Becker").toString(), ki18n("Former Amarok logo, former splash screen, former icons").toString(), "roman@formmorf.de" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Sami Nieminen").toString(), ki18n("Audioscrobbler support").toString(), "sami.nieminen@iki.fi" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Stanislav Karchebny").toString(), ki18n("Developer").toString(), "berkus@madfire.net" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Stefan Bogner").toString(), ki18n("Loads of stuff").toString(), "bochi@online.ms" ); ocsData.addCredit( QString(), aboutData.credits().last() ); aboutData.addCredit( ki18n("Tomasz Dudzik").toString(), ki18n("Splash screen").toString(), "madsheytan@gmail.com" ); ocsData.addCredit( QString(), aboutData.credits().last() ); //Donors: //Last update: 2012/11/07, post Roktober 2012 ocsData.addDonor( "ayleph", KAboutPerson( ki18n( "Andrew Browning" ).toString() ) ); ocsData.addDonor( QString(), KAboutPerson( ki18n( "Chris Wales" ).toString() ) ); ocsData.addDonor( QString(), KAboutPerson( ki18n( "ZImin Stanislav" ).toString() ) ); KAboutData::setApplicationData(aboutData); // Command line parser QCommandLineParser parser; aboutData.setupCommandLine(&parser); app.initCliArgs(&parser); parser.process(app); aboutData.processCommandLine(&parser); KDBusService::StartupOptions startOptions = parser.isSet( "multipleinstances" ) ? KDBusService::Multiple : KDBusService::Unique ; // register the app to dbus KDBusService dbusService( startOptions ); QObject::connect(&dbusService, &KDBusService::activateRequested, &app, &App::activateRequested); const bool debugColorsEnabled = !parser.isSet( "coloroff" ); const bool debugEnabled = parser.isSet( "debug" ); Debug::setDebugEnabled( debugEnabled ); Debug::setColoredDebug( debugColorsEnabled ); if ( parser.isSet( "debug-audio" ) ) { qputenv( "PHONON_DEBUG", QByteArray( "3" ) ); qputenv( "PHONON_BACKEND_DEBUG", QByteArray( "3" ) ); qputenv( "PHONON_PULSEAUDIO_DEBUG", QByteArray( "3" ) ); } #pragma message("PORT KF5: This *if* hould be moved to activateRequested() slot") if( !dbusService.isRegistered() ) { QList instanceOptions; instanceOptions << "previous" << "play" << "play-pause" << "stop" << "next" << "append" << "queue" << "load"; // Check if an option for a running instance is set bool isSet = false; for( int i = 0; i < instanceOptions.size(); ++i ) if( parser.isSet( instanceOptions[ i ] ) ) isSet = true; if ( !isSet ) fprintf( stderr, "Amarok is already running!\n" ); return 0; } // Rewrite default SIGINT and SIGTERM handlers // to make amarok save current playlists during forced // application termination (logout, Ctr+C in console etc.) signal( SIGINT, &QCoreApplication::exit ); signal( SIGTERM, &QCoreApplication::exit ); // This call is needed to prevent a crash on exit with Phonon-VLC and LibPulse #ifdef Q_WS_X11 XInitThreads(); #endif app.continueInit(); return app.exec(); }