diff --git a/CMakeLists.txt b/CMakeLists.txt index 3312aefad..3a1c02513 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ PROJECT( tomahawk ) CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) -SET( CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_SOURCE_DIR}/CMakeModules" ) +SET( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" ) IF( ${CMAKE_VERSION} VERSION_GREATER 2.8.3 ) CMAKE_POLICY(SET CMP0017 NEW) @@ -15,10 +15,10 @@ SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" ) SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" ) SET( TOMAHAWK_VERSION_MAJOR 0 ) -SET( TOMAHAWK_VERSION_MINOR 1 ) +SET( TOMAHAWK_VERSION_MINOR 2 ) SET( TOMAHAWK_VERSION_PATCH 0 ) -# SET( TOMAHAWK_VERSION_RC 0 ) +SET( TOMAHAWK_VERSION_RC 1 ) # build options @@ -28,9 +28,9 @@ option(BUILD_GUI "Build Tomahawk with GUI" ON) # generate version string IF( NOT CMAKE_BUILD_TYPE STREQUAL "Release" ) # Use the date as the tweak level. - INCLUDE( ${CMAKE_MODULE_PATH}/CMakeDateStamp.cmake ) + INCLUDE( CMakeDateStamp ) SET( TOMAHAWK_VERSION_TWEAK "${CMAKE_DATESTAMP_YEAR}${CMAKE_DATESTAMP_MONTH}${CMAKE_DATESTAMP_DAY}" ) - INCLUDE( ${CMAKE_MODULE_PATH}/CMakeVersionSource.cmake ) + INCLUDE( CMakeVersionSource ) ENDIF() SET( TOMAHAWK_VERSION ${TOMAHAWK_VERSION_MAJOR}.${TOMAHAWK_VERSION_MINOR}.${TOMAHAWK_VERSION_PATCH} ) @@ -54,7 +54,7 @@ SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) # installer creation -INCLUDE( CPack.cmake ) +INCLUDE( CPack ) #deps INCLUDE( MacroOptionalFindPackage ) @@ -67,11 +67,11 @@ IF( NOT BUILD_GUI ) MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} in HEADLESS mode ***" ) ELSE() MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} full GUI version ***" ) - LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui") + LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" ) ENDIF() macro_optional_find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS} ) -macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "") +macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "If you see this, although libqt4-devel is installed, check whether \n the qtwebkit-devel package is installed as well") macro_optional_find_package(Phonon 4.5.0) macro_log_feature(PHONON_FOUND "Phonon" "The Phonon multimedia library" "http://phonon.kde.org" TRUE "" "") @@ -93,6 +93,11 @@ macro_log_feature(TAGLIB_FOUND "TagLib" "Audio Meta-Data Library" "http://develo include( CheckTagLibFileName ) check_taglib_filename( COMPLEX_TAGLIB_FILENAME ) +macro_optional_find_package(Boost) +macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++ source libraries" "http://www.boost.org" TRUE "" "") #FIXME: give useful explaination + + + # required #While we distribute our own liblastfm2, don't need to look for it #macro_optional_find_package(LibLastFm 0.3.3) @@ -111,7 +116,7 @@ IF( INTERNAL_JREEN ) ELSE( INTERNAL_JREEN ) macro_optional_find_package(Jreen) ENDIF( INTERNAL_JREEN ) -macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "http://gitorious.org/jreen/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin. \n\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!\n") +macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "https://github.com/euroelessar/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin. \n\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!\n") # this installs headers and such and should really be handled in a separate package by packagers IF( INTERNAL_QTWEETLIB ) diff --git a/CMakeModules/AddAppIconMacro.cmake b/CMakeModules/AddAppIconMacro.cmake index ea65edaa5..64f8f3210 100644 --- a/CMakeModules/AddAppIconMacro.cmake +++ b/CMakeModules/AddAppIconMacro.cmake @@ -1,3 +1,5 @@ +SET(WINDRES_EXECUTABLE ${CMAKE_RC_COMPILER}) + # This macro is taken from kdelibs/cmake/modules/KDE4Macros.cmake. # # Copyright (c) 2006-2009 Alexander Neundorf, @@ -76,9 +78,9 @@ macro (KDE4_ADD_APP_ICON appsources pattern) file(GLOB_RECURSE files "${pattern}") # we can only test for the 128-icon like that - we don't use patterns anymore foreach (it ${files}) - if (it MATCHES ".*512.*" ) + if (it MATCHES ".*128.*" ) set (_icon ${it}) - endif (it MATCHES ".*512.*") + endif (it MATCHES ".*128.*") endforeach (it) if (_icon) @@ -101,8 +103,8 @@ macro (KDE4_ADD_APP_ICON appsources pattern) set_source_files_properties(${_outfilename}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) else(_icon) - # TODO - try to scale a non-512 icon...? Try to convert an SVG on the fly? - message(STATUS "Unable to find an 512x512 icon that matches pattern ${pattern} for variable ${appsources} - application will not have an application icon!") + # TODO - try to scale a non-128 icon...? Try to convert an SVG on the fly? + message(STATUS "Unable to find an 128x128 icon that matches pattern ${pattern} for variable ${appsources} - application will not have an application icon!") endif(_icon) else(SIPS_EXECUTABLE AND TIFF2ICNS_EXECUTABLE) diff --git a/ChangeLog b/ChangeLog index 9cf4b39ad..0c96ba8e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,20 @@ Version 0.2.0: + * Fix inability to create Echonest playlists based solely on style or mood. + * Created new Album page (that shows other albums from that artist available in your Super Collection) + * Update playlists in dashboard to keep them in sync + * Added support for "playing" Rdio track URLs and ability to drag/drop them into Tomahawk + * Change "Recently Played" page to "Dashboard" + * Prioritize resolving newer queries to make GUI more responsive + * Automatically expand local collection node in sidebar on launch + * Display spinner animation while searching for tracks + * Fix for occasionally flashing play control buttons + * Remove horizontal scrollbars when they aren't needed + * Let headless-Tomahawk users trigger a rescan with --filescan + * Removed "test login" button from Last.fm settings (OS X only) + * Fix font and image sizes from being too big/small on some OSes + * Include Stations and Automatic Playlists in News Stations and Playlists widget + * When click through to station or playlist ensure that sidebar navigation reflects it + * Even more design tweaks, new placeholder icons (and use them in right places) * Show search and artist page temporary navigation in sidebar when on those pages * Fixed bug where drop indicator wouldn't show under last track if that was drop zone * Fixed cross-wiring of Previous and Next song in "Music Player" menu (OS X) @@ -19,8 +35,7 @@ Version 0.2.0: * Fixed a few crashes that could occur when fetching data from Last.fm. * Made Twitter dialog more readable/understandable. * Added Artist pages (and links to them from now playing metadata and from collection track list views) - with artist bio snippet, related artists, top tracks and view of all tracks/albums from that - artist in user's Super Collection + with artist bio snippet, related artists, top tracks and view of all tracks/albums from that artist in user's Super Collection * Fixed streaming from https:// links * Desktop notifications for now playing (Linux only) * Implement new javascript resolver API and ability to present configuration options for resolvers @@ -47,11 +62,11 @@ Version 0.2.0: * Don't require @foo.com domains for jabber and google * Added global search function that searches all available sources (super collection and all enabled resolvers) * Cleaned up Preference Window and styling - * Collection scanner now can now run automatically, watching files and + * Collection scanner now can run automatically, watching files and directories for changes. On by default. * Added Pipeline view window * Allow seeking in songs - if possible - * Added ability to make a copy of a sources' playlists and add to your own playlists + * Added ability to make a copy of a peer's playlists and add to your own playlists * Added MediaKey support on OS X * Shuffle and Repeat settings are stored on a playlist by playlist basis diff --git a/admin/mac/add-Qt-to-bundle.sh b/admin/mac/add-Qt-to-bundle.sh deleted file mode 100755 index 8720e3f8d..000000000 --- a/admin/mac/add-Qt-to-bundle.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/sh -# author: max@last.fm -# usage: Run from inside the bundle root directory, eg. Last.fm.app -# The first parameter should be the QtFrameworks to copy. -# Remaining parameters are plugins to copy, directories and files are -# valid. -# eg: add-Qt-to-bundle.sh 'QtCore QtGui QtXml' \ -# imageformats \ -# sqldrivers/libsqlite.dylib -################################################################################ - -QT_FRAMEWORKS_DIR="$QTDIR/lib" -QT_PLUGINS_DIR="$QTDIR/plugins" - -if [[ ! -d "$QTDIR/lib/QtCore.framework" ]] -then - # this dir is the location of install for the official Trolltech dmg - if [[ -d /Library/Frameworks/QtCore.framework ]] - then - QT_FRAMEWORKS_DIR=/Library/Frameworks - QT_PLUGINS_DIR=/Developer/Applications/Qt/plugins - fi -fi - -echo "Plugins go to: $QT_PLUGINS_DIR" - -if [ -z $QTDIR ] -then - echo QTDIR must be set, or install the official Qt dmg - exit 1 -fi -################################################################################ - - -#first frameworks -mkdir -p Contents/Frameworks -for x in $1 -do - echo "C $x" - cp -R $QT_FRAMEWORKS_DIR/$x.framework Contents/Frameworks/ - chmod -R u+rw Contents/Frameworks/ -done - -#plugins -shift -mkdir -p Contents/MacOS -mkdir -p Contents/MacOS/sqldrivers -mkdir -p Contents/MacOS/imageformats -mkdir -p Contents/MacOS/phonon_backend -mkdir -p Contents/MacOS/crypto - -cp -R $QT_PLUGINS_DIR/sqldrivers/libqsqlite.dylib Contents/MacOS/sqldrivers/ -cp -R $QT_PLUGINS_DIR/imageformats/libqgif.dylib Contents/MacOS/imageformats/ -cp -R $QT_PLUGINS_DIR/imageformats/libqjpeg.dylib Contents/MacOS/imageformats/ -cp -R $QT_PLUGINS_DIR/imageformats/libqico.dylib Contents/MacOS/imageformats/ -cp -R $QT_PLUGINS_DIR/imageformats/libqmng.dylib Contents/MacOS/imageformats/ -#cp -R $QT_PLUGINS_DIR/imageformats/libqsvg.dylib Contents/MacOS/imageformats/ -#cp -R $QT_PLUGINS_DIR/imageformats/libqtiff.dylib Contents/MacOS/imageformats/ -cp -R $QT_PLUGINS_DIR/crypto/libqca-ossl.dylib Contents/MacOS/crypto/ -cp -R $QT_PLUGINS_DIR/phonon_backend/phonon_vlc.so Contents/MacOS/phonon_backend/ - -#cleanup -find Contents/Frameworks -name Headers -o -name \*.prl -o -name \*_debug | xargs rm -rf -find Contents -name \*_debug -o -name \*_debug.dylib | xargs rm diff --git a/admin/mac/add-spotify.sh b/admin/mac/add-spotify.sh deleted file mode 100755 index 170c67e18..000000000 --- a/admin/mac/add-spotify.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -# author: lfranchi@kde.org -# usage: Run from inside the bundle root directory, eg. Tomahawk.app -# The first parameter should be the spotify resolver binary to copy. -# eg: add-spotify.sh /path/to/spotify_tomahawkresolver -################################################################################ - -mkdir -p Contents/Frameworks -cp -R /Library/Frameworks/libspotify.framework Contents/Frameworks - -install_name_tool -change /usr/local/Cellar/qt/4.7.3/lib/QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore $1 -install_name_tool -change /usr/local/Cellar/qt/4.7.3/lib/QtNetwork.framework/Versions/4/QtNetwork @executable_path/../Frameworks/QtNetwork.framework/Versions/4/QtNetwork $1 -install_name_tool -change libqjson.0.dylib @executable_path/libqjson.0.7.1.dylib $1 -install_name_tool -change /usr/local/Cellar/qjson/0.7.1/lib/libqjson.0.7.1.dylib @executable_path/libqjson.0.7.1.dylib $1 -mkdir -p Contents/MacOS -cp $1 Contents/MacOS/ diff --git a/admin/mac/build-release-osx.sh b/admin/mac/build-release-osx.sh index bd0153ff5..c3dcbcd83 100755 --- a/admin/mac/build-release-osx.sh +++ b/admin/mac/build-release-osx.sh @@ -23,65 +23,26 @@ then fi ROOT=`pwd` - -QTDIR=`which qmake` -LINKDIR=`readlink $QTDIR` -QTDIR=`dirname $QTDIR` -QTDIR=$QTDIR/`dirname $LINKDIR` -QTDIR=`dirname $QTDIR` -test -L "$QTDIR" && QTDIR=`readlink $QTDIR` - -echo "Goes here: $QTDIR" - -export QMAKESPEC='macx-g++' -export QTDIR -export VERSION -export QTVERSION='4.7.3' -################################################################################ - - -CLEAN='1' -BUILD='1' -NOTQUICK='1' -CREATEDMG='1' VERSION=$1 - header "Adding Qt to app bundle" - cd tomahawk.app - $ROOT/../admin/mac/add-Qt-to-bundle.sh \ - 'QtCore QtGui QtXml QtNetwork QtSql QtXmlPatterns QtWebKit phonon' -# 'QtCore QtGui QtXml QtNetwork QtSql QtXmlPatterns QtWebKit QtDbus phonon' +################################################################################ - header "Renaming files" + mv tomahawk.app Tomahawk.app + mv Tomahawk.app/Contents/MacOS/tomahawk Tomahawk.app/Contents/MacOS/Tomahawk + + header "Fixing and copying libraries" + $ROOT/../admin/mac/macdeploy.py Tomahawk.app quiet + + cd Tomahawk.app + + header "Renaming icon" mv Contents/Resources/tomahawkSources.icns Contents/Resources/Tomahawk.icns - mv Contents/MacOS/tomahawk Contents/MacOS/Tomahawk -# cp $ROOT/../admin/mac/Info.plist Contents/Info.plist + cp $ROOT/../admin/mac/qt.conf Contents/Resources/qt.conf - header "Copying VLC plugins into bundle" - mkdir -p Contents/plugins - cp -R /usr/local/Cellar/vlc-git/HEAD/lib/vlc/plugins/ Contents/plugins - rm -rf Contents/plugins/video_* Contents/plugins/gui Contents/plugins/*/libold* Contents/plugins/*/libvcd* Contents/plugins/*/libdvd* \ - Contents/plugins/*/liblibass* Contents/plugins/*/libx264* Contents/plugins/*/libschroe* Contents/plugins/*/liblibmpeg2* \ - Contents/plugins/*/libstream_out_* Contents/plugins/*/libmjpeg_plugin* Contents/plugins/*/libh264_plugin* Contents/plugins/*/libzvbi_plugin* Contents/plugins/*/lib*sub* - - header "Running install_name_tool" - $ROOT/../admin/mac/deposx.sh - - header "Copying Sparkle pubkey & framework, and qt.conf" - cp $ROOT/../admin/mac/sparkle_pub.pem Contents/Resources - cp -R /Library/Frameworks/Sparkle.framework Contents/Frameworks - cp $ROOT/../admin/mac/qt.conf Contents/Resources - - header "Adding spotify resolver to bundle if spotify_tomahawkresolver found in $ROOT" - if [ -e $ROOT/spotify_tomahawkresolver ] - then - header "Found, so adding spotify resolver."ac - $ROOT/../admin/mac/add-spotify.sh $ROOT/spotify_tomahawkresolver - fi header "Creating DMG" cd .. - mv tomahawk.app Tomahawk.app + $ROOT/../admin/mac/create-dmg.sh Tomahawk.app mv Tomahawk.dmg Tomahawk-$VERSION.dmg diff --git a/admin/mac/deposx.sh b/admin/mac/deposx.sh deleted file mode 100755 index 131cfea37..000000000 --- a/admin/mac/deposx.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# author: max@last.fm, chris@last.fm -################################################################################ - - -if [ -z $QTDIR ] -then - echo QTDIR must be set - exit 1 -fi - -if [ -z $QTVERSION ] -then - echo QTVERSION must be set - exit 1 -fi - -cd .. -ORIGROOT=`pwd` -cd - - -cd Contents - -QTLIBS=`ls Frameworks | cut -d. -f1` -LIBS=`cd MacOS && ls -fR1 | grep dylib` -PLUGINFOLDERS=`ls plugins | cut -d. -f1` - -################################################################################ - - -function import_lib -{ - echo "L \`$1'" - cp -R -L $1 MacOS/`basename $1` - chmod u+rw MacOS/`basename $1` - deplib_change MacOS/`basename $1` - deposx_change MacOS/`basename $1` -} - -function deposx_change -{ - echo "D \`$1'" - echo $QTDIR - - for y in $QTLIBS - do - install_name_tool -change $QTDIR/lib/$y.framework/Versions/4/$y \ - @executable_path/../Frameworks/$y.framework/Versions/4/$y \ - "$1" - - install_name_tool -change /usr/local/Cellar/qt/$QTVERSION/lib/$y.framework/Versions/4/$y \ - @executable_path/../Frameworks/$y.framework/Versions/4/$y \ - "$1" - - install_name_tool -change /usr/X11/lib/libpng12.0.dylib \ - @executable_path/libpng12.0.dylib \ - "$1" - done - - for y in $LIBS - do - install_name_tool -change $y \ - @executable_path/$y \ - "$1" - done -} - -function deplib_change -{ - install_name_tool -change /usr/local/Cellar/qjson/0.7.1/lib/libqjson.0.7.1.dylib @executable_path/libqjson.0.7.1.dylib $1 - install_name_tool -change /usr/local/lib/libechonest.1.1.dylib @executable_path/libechonest.1.1.dylib $1 - install_name_tool -change /usr/local/lib/libclucene-core.1.dylib @executable_path/libclucene-core.1.dylib $1 - install_name_tool -change /usr/local/lib/libclucene-shared.1.dylib @executable_path/libclucene-shared.1.dylib $1 - install_name_tool -change /usr/local/Cellar/taglib/1.7/lib/libtag.1.7.0.dylib @executable_path/libtag.1.7.0.dylib $1 -# install_name_tool -change /usr/local/Cellar/gloox/1.0/lib/libgloox.8.dylib @executable_path/libgloox.8.dylib $1 -# install_name_tool -change /usr/local/Cellar/libogg/1.2.0/lib/libogg.0.dylib @executable_path/libogg.0.dylib $1 -# install_name_tool -change /usr/local/Cellar/libvorbis/1.3.1/lib/libvorbis.0.dylib @executable_path/libvorbis.0.dylib $1 -# install_name_tool -change /usr/local/Cellar/libvorbis/1.3.1/lib/libvorbisfile.3.dylib @executable_path/libvorbisfile.3.dylib $1 -# install_name_tool -change /usr/local/Cellar/mad/0.15.1b/lib/libmad.0.dylib @executable_path/libmad.0.dylib $1 -# install_name_tool -change /usr/local/Cellar/flac/1.2.1/lib/libFLAC++.6.dylib @executable_path/libFLAC++.6.dylib $1 -# install_name_tool -change /usr/local/Cellar/flac/1.2.1/lib/libFLAC.8.dylib @executable_path/libFLAC.8.dylib $1 - install_name_tool -change /usr/local/Cellar/kde-phonon/4.5.0/lib/libphonon.4.dylib @executable_path/libphonon.4.dylib $1 - install_name_tool -change /usr/local/Cellar/kde-phonon/4.5.0/lib/libphonon.4.5.0.dylib @executable_path/libphonon.4.dylib $1 - - install_name_tool -change $ORIGROOT/libtomahawklib.dylib @executable_path/libtomahawklib.dylib $1 - install_name_tool -change $ORIGROOT/libtomahawk_sipjabber.dylib @executable_path/libtomahawk_sipjabber.dylib $1 - install_name_tool -change $ORIGROOT/libtomahawk_sipgoogle.dylib @executable_path/libtomahawk_sipgoogle.dylib $1 - install_name_tool -change $ORIGROOT/libtomahawk_siptwitter.dylib @executable_path/libtomahawk_siptwitter.dylib $1 - install_name_tool -change $ORIGROOT/libtomahawk_sipzeroconf.dylib @executable_path/libtomahawk_sipzeroconf.dylib $1 - install_name_tool -change $ORIGROOT/libtomahawk_qtweetlib.dylib @executable_path/libtomahawk_qtweetlib.dylib $1 - install_name_tool -change $ORIGROOT/libtomahawk_portfwd.dylib @executable_path/libtomahawk_portfwd.dylib $1 - install_name_tool -change $ORIGROOT/libjreen.dylib @executable_path/libjreen.dylib $1 - install_name_tool -change /usr/local/Cellar/jreen/HEAD/lib/libjreen.dylib @executable_path/libjreen.dylib $1 - install_name_tool -change /usr/local/Cellar/qca/2.0.2/lib/qca.framework/Versions/2/qca @executable_path/../Frameworks/qca.framework/Versions/2/qca $1 - install_name_tool -change /usr/local/Cellar/gettext/0.18.1.1/lib/libintl.8.dylib @executable_path/libintl.8.dylib $1 - install_name_tool -change /usr/local/Cellar/vlc-git/HEAD/lib/libvlc.5.dylib @executable_path/libvlc.5.dylib $1 - install_name_tool -change /usr/local/Cellar/vlc-git/HEAD/lib/libvlccore.4.dylib @executable_path/libvlccore.4.dylib $1 - - install_name_tool -change libqjson.0.dylib @executable_path/libqjson.0.7.1.dylib $1 - install_name_tool -change libechonest.1.1.dylib @executable_path/libechonest.1.1.dylib $1 - install_name_tool -change libclucene-core.1.dylib @executable_path/libclucene-core.1.dylib $1 - install_name_tool -change libclucene-shared.1.dylib @executable_path/libclucene-shared.1.dylib $1 -} - -################################################################################ - - -# first all libraries and executables -find MacOS -type f -a -perm -100 | while read x -do - echo $x - y=$(file "$x" | grep 'Mach-O') - deposx_change "$x" - deplib_change "$x" -done - -import_lib /usr/local/Cellar/qjson/0.7.1/lib/libqjson.0.7.1.dylib -import_lib /usr/local/Cellar/taglib/1.7/lib/libtag.1.7.0.dylib -#import_lib /usr/local/Cellar/gloox/1.0/lib/libgloox.8.dylib -#import_lib /usr/local/Cellar/libogg/1.2.0/lib/libogg.0.dylib -#import_lib /usr/local/Cellar/libvorbis/1.3.1/lib/libvorbis.0.dylib -#import_lib /usr/local/Cellar/libvorbis/1.3.1/lib/libvorbisfile.3.dylib -#import_lib /usr/local/Cellar/mad/0.15.1b/lib/libmad.0.dylib -#import_lib /usr/local/Cellar/flac/1.2.1/lib/libFLAC++.6.dylib -#import_lib /usr/local/Cellar/flac/1.2.1/lib/libFLAC.8.dylib -import_lib /usr/local/lib/libechonest.1.1.dylib -import_lib /usr/local/lib/libclucene-core.1.dylib -import_lib /usr/local/lib/libclucene-shared.1.dylib -import_lib /usr/local/Cellar/kde-phonon/4.5.0/lib/libphonon.4.dylib -import_lib /usr/local/Cellar/vlc-git/HEAD/lib/libvlc.5.dylib -import_lib /usr/local/Cellar/vlc-git/HEAD/lib/libvlccore.4.dylib -import_lib /usr/local/Cellar/gettext/0.18.1.1/lib/libintl.8.dylib -import_lib /usr/X11/lib/libpng12.0.dylib - -import_lib $ORIGROOT/libjreen.dylib -import_lib $ORIGROOT/libtomahawklib.dylib -import_lib $ORIGROOT/libtomahawk_sipjabber.dylib -import_lib $ORIGROOT/libtomahawk_sipgoogle.dylib -import_lib $ORIGROOT/libtomahawk_siptwitter.dylib -import_lib $ORIGROOT/libtomahawk_sipzeroconf.dylib -import_lib $ORIGROOT/libtomahawk_qtweetlib.dylib -import_lib $ORIGROOT/libtomahawk_portfwd.dylib - -cp -R /usr/local/Cellar/qca/2.0.2/lib/qca.framework Frameworks/ -chmod 644 Frameworks/qca.framework/Versions/2/qca -deplib_change Frameworks/qca.framework/Versions/2/qca -deposx_change Frameworks/qca.framework/Versions/2/qca - -# now Qt -for x in $QTLIBS -do - echo `pwd` -# ls -l Frameworks/$x.framework/Versions/4/$x - deposx_change Frameworks/$x.framework/Versions/4/$x - install_name_tool -id @executable_path/../Frameworks/$x.framework/Versions/4/$x \ - Frameworks/$x.framework/Versions/4/$x - deplib_change "Frameworks/$x.framework/Versions/4/$x" -done - -# now VLC plugins -for x in plugins/$PLUGINFOLDERS -do - for plugin in `ls plugins/$x | cut -f1` - do - echo "Fixing VLC plugin: $plugin" - chmod 644 plugins/$x/$plugin - deplib_change plugins/$x/$plugin - done -done diff --git a/admin/mac/macdeploy.py b/admin/mac/macdeploy.py new file mode 100755 index 000000000..0461c7bb8 --- /dev/null +++ b/admin/mac/macdeploy.py @@ -0,0 +1,517 @@ +#!/usr/bin/python + +# This file is part of Clementine. +# +# Clementine is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Clementine 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 Clementine. If not, see . + +import os +import re +import subprocess +import sys + +FRAMEWORK_SEARCH_PATH=[ + '/Library/Frameworks', + os.path.join(os.environ['HOME'], 'Library/Frameworks') +] + +LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.18.1.1/lib', '.'] + + +VLC_PLUGINS=[ + 'access/libaccess_attachment_plugin.dylib', + #'access/libaccess_avio_plugin.dylib', + 'access/libaccess_fake_plugin.dylib', + 'access/libaccess_ftp_plugin.dylib', + 'access/libaccess_http_plugin.dylib', + 'access/libaccess_imem_plugin.dylib', + 'access/libaccess_mmap_plugin.dylib', + 'access/libaccess_mms_plugin.dylib', + 'access/libaccess_realrtsp_plugin.dylib', + 'access/libaccess_tcp_plugin.dylib', + 'access/libaccess_udp_plugin.dylib', + 'access/libcdda_plugin.dylib', + 'access/libfilesystem_plugin.dylib', + 'access/libqtcapture_plugin.dylib', + 'access/librtp_plugin.dylib', + 'access/libzip_plugin.dylib', + 'access_output/libaccess_output_dummy_plugin.dylib', + 'access_output/libaccess_output_file_plugin.dylib', + 'access_output/libaccess_output_http_plugin.dylib', + 'access_output/libaccess_output_shout_plugin.dylib', + 'access_output/libaccess_output_udp_plugin.dylib', + 'audio_filter/liba52tofloat32_plugin.dylib', + 'audio_filter/liba52tospdif_plugin.dylib', + 'audio_filter/libaudio_format_plugin.dylib', + 'audio_filter/libaudiobargraph_a_plugin.dylib', + 'audio_filter/libchorus_flanger_plugin.dylib', + 'audio_filter/libconverter_fixed_plugin.dylib', + 'audio_filter/libdolby_surround_decoder_plugin.dylib', + 'audio_filter/libdtstofloat32_plugin.dylib', + 'audio_filter/libdtstospdif_plugin.dylib', + 'audio_filter/libequalizer_plugin.dylib', + 'audio_filter/libheadphone_channel_mixer_plugin.dylib', + 'audio_filter/libmono_plugin.dylib', + 'audio_filter/libmpgatofixed32_plugin.dylib', + 'audio_filter/libnormvol_plugin.dylib', + 'audio_filter/libparam_eq_plugin.dylib', + 'audio_filter/libscaletempo_plugin.dylib', + 'audio_filter/libsimple_channel_mixer_plugin.dylib', + 'audio_filter/libspatializer_plugin.dylib', + 'audio_filter/libtrivial_channel_mixer_plugin.dylib', + 'audio_filter/libugly_resampler_plugin.dylib', + 'audio_mixer/libfloat32_mixer_plugin.dylib', + 'audio_mixer/libspdif_mixer_plugin.dylib', + 'audio_mixer/libtrivial_mixer_plugin.dylib', + 'audio_output/libaout_file_plugin.dylib', + 'audio_output/libauhal_plugin.dylib', + 'codec/liba52_plugin.dylib', + 'codec/libadpcm_plugin.dylib', + 'codec/libaes3_plugin.dylib', + 'codec/libaraw_plugin.dylib', + 'codec/libavcodec_plugin.dylib', + 'codec/libcc_plugin.dylib', + 'codec/libcdg_plugin.dylib', + 'codec/libdts_plugin.dylib', + 'codec/libfaad_plugin.dylib', + 'codec/libfake_plugin.dylib', + 'codec/libflac_plugin.dylib', + 'codec/libfluidsynth_plugin.dylib', + 'codec/libinvmem_plugin.dylib', + 'codec/liblpcm_plugin.dylib', + 'codec/libmpeg_audio_plugin.dylib', + 'codec/libpng_plugin.dylib', + 'codec/librawvideo_plugin.dylib', + 'codec/libspeex_plugin.dylib', + 'codec/libspudec_plugin.dylib', + 'codec/libtheora_plugin.dylib', + 'codec/libtwolame_plugin.dylib', + 'codec/libvorbis_plugin.dylib', + 'control/libgestures_plugin.dylib', + 'control/libhotkeys_plugin.dylib', + 'control/libmotion_plugin.dylib', + 'control/libnetsync_plugin.dylib', + 'control/libsignals_plugin.dylib', + 'demux/libaiff_plugin.dylib', + 'demux/libasf_plugin.dylib', + 'demux/libau_plugin.dylib', + #'demux/libavformat_plugin.dylib', + 'demux/libavi_plugin.dylib', + 'demux/libdemux_cdg_plugin.dylib', + 'demux/libdemuxdump_plugin.dylib', + 'demux/libdirac_plugin.dylib', + 'demux/libes_plugin.dylib', + 'demux/libflacsys_plugin.dylib', + 'demux/liblive555_plugin.dylib', + 'demux/libmkv_plugin.dylib', + 'demux/libmod_plugin.dylib', + 'demux/libmp4_plugin.dylib', + 'demux/libmpc_plugin.dylib', + 'demux/libmpgv_plugin.dylib', + 'demux/libnsc_plugin.dylib', + 'demux/libnsv_plugin.dylib', + 'demux/libnuv_plugin.dylib', + 'demux/libogg_plugin.dylib', + 'demux/libplaylist_plugin.dylib', + 'demux/libps_plugin.dylib', + 'demux/libpva_plugin.dylib', + 'demux/librawaud_plugin.dylib', + 'demux/librawdv_plugin.dylib', + 'demux/librawvid_plugin.dylib', + 'demux/libreal_plugin.dylib', + 'demux/libsmf_plugin.dylib', + 'demux/libts_plugin.dylib', + 'demux/libtta_plugin.dylib', + 'demux/libty_plugin.dylib', + 'demux/libvc1_plugin.dylib', + 'demux/libvoc_plugin.dylib', + 'demux/libwav_plugin.dylib', + 'demux/libxa_plugin.dylib', + 'meta_engine/libfolder_plugin.dylib', + 'meta_engine/libtaglib_plugin.dylib', + 'misc/libaudioscrobbler_plugin.dylib', + 'misc/libdummy_plugin.dylib', + 'misc/libexport_plugin.dylib', + 'misc/libfreetype_plugin.dylib', + 'misc/libgnutls_plugin.dylib', + 'misc/liblogger_plugin.dylib', + 'misc/liblua_plugin.dylib', + 'misc/libosd_parser_plugin.dylib', + 'misc/libquartztext_plugin.dylib', + 'misc/libstats_plugin.dylib', + 'misc/libvod_rtsp_plugin.dylib', + 'misc/libxml_plugin.dylib', + 'misc/libxtag_plugin.dylib', + 'mmx/libi420_rgb_mmx_plugin.dylib', + 'mmx/libi420_yuy2_mmx_plugin.dylib', + 'mmx/libi422_yuy2_mmx_plugin.dylib', + 'mmx/libmemcpymmx_plugin.dylib', + 'mmxext/libmemcpymmxext_plugin.dylib', + 'mux/libmux_asf_plugin.dylib', + 'mux/libmux_avi_plugin.dylib', + 'mux/libmux_dummy_plugin.dylib', + 'mux/libmux_mp4_plugin.dylib', + 'mux/libmux_mpjpeg_plugin.dylib', + 'mux/libmux_ogg_plugin.dylib', + 'mux/libmux_ps_plugin.dylib', + 'mux/libmux_ts_plugin.dylib', + 'mux/libmux_wav_plugin.dylib', + 'packetizer/libpacketizer_copy_plugin.dylib', + 'packetizer/libpacketizer_dirac_plugin.dylib', + 'packetizer/libpacketizer_flac_plugin.dylib', + 'packetizer/libpacketizer_h264_plugin.dylib', + 'packetizer/libpacketizer_mlp_plugin.dylib', + 'packetizer/libpacketizer_mpeg4audio_plugin.dylib', + 'packetizer/libpacketizer_mpeg4video_plugin.dylib', + 'packetizer/libpacketizer_mpegvideo_plugin.dylib', + 'packetizer/libpacketizer_vc1_plugin.dylib', + 'sse2/libi420_rgb_sse2_plugin.dylib', + 'sse2/libi420_yuy2_sse2_plugin.dylib', + 'sse2/libi422_yuy2_sse2_plugin.dylib', + 'stream_filter/libdecomp_plugin.dylib', + 'stream_filter/libstream_filter_rar_plugin.dylib', + 'stream_filter/libstream_filter_record_plugin.dylib', + 'visualization/libvisual_plugin.dylib', +] + +VLC_SEARCH_PATH=[ + '/usr/local/lib/vlc/plugins/', +] + +QT_PLUGINS = [ + 'crypto/libqca-ossl.dylib', + 'phonon_backend/phonon_vlc.so', + 'sqldrivers/libqsqlite.dylib', + 'imageformats/libqgif.dylib', + 'imageformats/libqico.dylib', + 'imageformats/libqjpeg.dylib', + 'imageformats/libqmng.dylib', +] + +TOMAHAWK_PLUGINS = [ + 'libtomahawk_sipjabber.dylib', + 'libtomahawk_sipgoogle.dylib', + 'libtomahawk_siptwitter.dylib', + 'libtomahawk_sipzeroconf.dylib', + 'libtomahawk_qtweetlib.dylib', +] + +QT_PLUGINS_SEARCH_PATH=[ + '/usr/local/Cellar/qt/4.7.3/plugins', +] + + +class Error(Exception): + pass + + +class CouldNotFindQtPluginErrorFindFrameworkError(Error): + pass + + +class InstallNameToolError(Error): + pass + + +class CouldNotFindQtPluginError(Error): + pass + + +class CouldNotFindVLCPluginError(Error): + pass + + +class CouldNotFindScriptPluginError(Error): + pass + + + +if len(sys.argv) < 2: + print 'Usage: %s ' % sys.argv[0] + +bundle_dir = sys.argv[1] + +bundle_name = os.path.basename(bundle_dir).split('.')[0] + +commands = [] + +binary_dir = os.path.join(bundle_dir, 'Contents', 'MacOS') +frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks') +commands.append(['mkdir', '-p', frameworks_dir]) +resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources') +commands.append(['mkdir', '-p', resources_dir]) +plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns') +binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name) + +fixed_libraries = [] +fixed_frameworks = [] + +def GetBrokenLibraries(binary): + #print "Checking libs for binary: %s" % binary + output = subprocess.Popen(['otool', '-L', binary], stdout=subprocess.PIPE).communicate()[0] + broken_libs = { + 'frameworks': [], + 'libs': []} + for line in [x.split(' ')[0].lstrip() for x in output.split('\n')[1:]]: + #print "Checking line: %s" % line + if not line: # skip empty lines + continue + if os.path.basename(binary) == os.path.basename(line): + #print "mnope %s-%s" % (os.path.basename(binary), os.path.basename(line)) + continue + if re.match(r'^\s*/System/', line): + continue # System framework + elif re.match(r'^\s*/usr/lib/', line): + #print "unix style system lib" + continue # unix style system library + elif re.match(r'Breakpad', line): + continue # Manually added by cmake. + elif re.match(r'^\s*@executable_path', line) or re.match(r'^\s*@loader_path', line): + # Potentially already fixed library + if '.framework' in line: + relative_path = os.path.join(*line.split('/')[3:]) + if not os.path.exists(os.path.join(frameworks_dir, relative_path)): + broken_libs['frameworks'].append(relative_path) + else: + relative_path = os.path.join(*line.split('/')[1:]) + #print "RELPATH %s %s" % (relative_path, os.path.join(binary_dir, relative_path)) + if not os.path.exists(os.path.join(binary_dir, relative_path)): + broken_libs['libs'].append(relative_path) + elif re.search(r'\w+\.framework', line): + broken_libs['frameworks'].append(line) + else: + broken_libs['libs'].append(line) + + return broken_libs + +def FindFramework(path): + for search_path in FRAMEWORK_SEARCH_PATH: + abs_path = os.path.join(search_path, path) + if os.path.exists(abs_path): + return abs_path + + raise CouldNotFindFrameworkError(path) + +def FindLibrary(path): + if os.path.exists(path): + return path + for search_path in LIBRARY_SEARCH_PATH: + abs_path = os.path.join(search_path, path) + if os.path.exists(abs_path): + return abs_path + else: # try harder---look for lib name in library folders + newpath = os.path.join(search_path,os.path.basename(path)) + if os.path.exists(newpath): + return newpath + + return "" + #raise CouldNotFindFrameworkError(path) + +def FixAllLibraries(broken_libs): + for framework in broken_libs['frameworks']: + FixFramework(framework) + for lib in broken_libs['libs']: + FixLibrary(lib) + +def FixFramework(path): + if path in fixed_libraries: + return + else: + fixed_libraries.append(path) + abs_path = FindFramework(path) + broken_libs = GetBrokenLibraries(abs_path) + FixAllLibraries(broken_libs) + + new_path = CopyFramework(abs_path) + id = os.sep.join(new_path.split(os.sep)[3:]) + FixFrameworkId(new_path, id) + for framework in broken_libs['frameworks']: + FixFrameworkInstallPath(framework, new_path) + for library in broken_libs['libs']: + FixLibraryInstallPath(library, new_path) + +def FixLibrary(path): + if path in fixed_libraries or FindSystemLibrary(os.path.basename(path)) is not None: + return + else: + fixed_libraries.append(path) + abs_path = FindLibrary(path) + if abs_path == "": + print "Could not resolve %s, not fixing!" % path + return + broken_libs = GetBrokenLibraries(abs_path) + FixAllLibraries(broken_libs) + + new_path = CopyLibrary(abs_path) + FixLibraryId(new_path) + for framework in broken_libs['frameworks']: + FixFrameworkInstallPath(framework, new_path) + for library in broken_libs['libs']: + FixLibraryInstallPath(library, new_path) + +def FixVLCPlugin(abs_path, subdir): + broken_libs = GetBrokenLibraries(abs_path) + FixAllLibraries(broken_libs) + + #print "Copying plugin....%s %s %s" % (plugins_dir, subdir, os.path.join(abs_path.split('/')[-2:])) + plugindir = abs_path.split('/')[-2] + new_path = os.path.join(plugins_dir, subdir, plugindir, os.path.basename(abs_path)) + args = ['mkdir', '-p', os.path.dirname(new_path)] + commands.append(args) + args = ['ditto', '--arch=i386', '--arch=x86_64', abs_path, new_path] + commands.append(args) + args = ['chmod', 'u+w', new_path] + commands.append(args) + for framework in broken_libs['frameworks']: + FixFrameworkInstallPath(framework, new_path) + for library in broken_libs['libs']: + FixLibraryInstallPath(library, new_path) + +def FixPlugin(abs_path, subdir): + broken_libs = GetBrokenLibraries(abs_path) + FixAllLibraries(broken_libs) + + new_path = CopyPlugin(abs_path, subdir) + for framework in broken_libs['frameworks']: + FixFrameworkInstallPath(framework, new_path) + for library in broken_libs['libs']: + FixLibraryInstallPath(library, new_path) + +def FixBinary(path): + broken_libs = GetBrokenLibraries(path) + FixAllLibraries(broken_libs) + for framework in broken_libs['frameworks']: + FixFrameworkInstallPath(framework, path) + for library in broken_libs['libs']: + FixLibraryInstallPath(library, path) + +def CopyLibrary(path): + new_path = os.path.join(frameworks_dir, os.path.basename(path)) + args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path] + commands.append(args) + args = ['chmod', 'u+w', new_path] + commands.append(args) + return new_path + +def CopyPlugin(path, subdir): + new_path = os.path.join(plugins_dir, subdir, os.path.basename(path)) + args = ['mkdir', '-p', os.path.dirname(new_path)] + commands.append(args) + args = ['ditto', '--arch=i386', '--arch=x86_64', path, new_path] + commands.append(args) + args = ['chmod', 'u+w', new_path] + commands.append(args) + return new_path + +def CopyFramework(path): + parts = path.split(os.sep) + for i, part in enumerate(parts): + if re.match(r'\w+\.framework', part): + full_path = os.path.join(frameworks_dir, *parts[i:-1]) + break + args = ['mkdir', '-p', full_path] + commands.append(args) + args = ['ditto', '--arch=i386', '--arch=x86_64', path, full_path] + commands.append(args) + args = ['chmod', 'u+w', os.path.join(full_path, parts[-1])] + commands.append(args) + + menu_nib = os.path.join(os.path.split(path)[0], 'Resources', 'qt_menu.nib') + if os.path.exists(menu_nib): + args = ['cp', '-r', menu_nib, resources_dir] + commands.append(args) + + return os.path.join(full_path, parts[-1]) + +def FixId(path, library_name): + id = '@executable_path/../Frameworks/%s' % library_name + args = ['install_name_tool', '-id', id, path] + commands.append(args) + +def FixLibraryId(path): + library_name = os.path.basename(path) + FixId(path, library_name) + +def FixFrameworkId(path, id): + FixId(path, id) + +def FixInstallPath(library_path, library, new_path): + args = ['install_name_tool', '-change', library_path, new_path, library] + commands.append(args) + +def FindSystemLibrary(library_name): + for path in ['/lib', '/usr/lib']: + full_path = os.path.join(path, library_name) + if os.path.exists(full_path): + return full_path + return None + +def FixLibraryInstallPath(library_path, library): + system_library = FindSystemLibrary(os.path.basename(library_path)) + if system_library is None: + new_path = '@executable_path/../Frameworks/%s' % os.path.basename(library_path) + FixInstallPath(library_path, library, new_path) + else: + FixInstallPath(library_path, library, system_library) + +def FixFrameworkInstallPath(library_path, library): + parts = library_path.split(os.sep) + for i, part in enumerate(parts): + if re.match(r'\w+\.framework', part): + full_path = os.path.join(*parts[i:]) + break + new_path = '@executable_path/../Frameworks/%s' % full_path + FixInstallPath(library_path, library, new_path) + +def FindQtPlugin(name): + for path in QT_PLUGINS_SEARCH_PATH: + if os.path.exists(path): + if os.path.exists(os.path.join(path, name)): + return os.path.join(path, name) + raise CouldNotFindQtPluginError(name) + + +def FindVLCPlugin(name): + for path in VLC_SEARCH_PATH: + if os.path.exists(path): + if os.path.exists(os.path.join(path, name)): + return os.path.join(path, name) + raise CouldNotFindVLCPluginError(name) + +FixBinary(binary) + +for plugin in VLC_PLUGINS: + FixVLCPlugin(FindVLCPlugin(plugin), '.') + +for plugin in TOMAHAWK_PLUGINS: + FixPlugin(plugin, '../MacOS') + +try: + FixPlugin('spotify_tomahawkresolver', '../MacOS') +except: + print 'Failed to find spotify resolver' + +for plugin in QT_PLUGINS: + FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin)) + +if len(sys.argv) <= 2: + print 'Would run %d commands:' % len(commands) + for command in commands: + print ' '.join(command) + + print 'OK?' + raw_input() + +for command in commands: + p = subprocess.Popen(command) + os.waitpid(p.pid, 0) diff --git a/admin/mac/qt.conf b/admin/mac/qt.conf index 1c7b73536..64d729736 100644 --- a/admin/mac/qt.conf +++ b/admin/mac/qt.conf @@ -1,2 +1,2 @@ [Paths] -Plugins = plugins +Plugins = PlugIns diff --git a/admin/win/Toolchain-mingw32-openSUSE.cmake b/admin/win/Toolchain-mingw32-openSUSE.cmake index afcddedd7..0be73a183 100644 --- a/admin/win/Toolchain-mingw32-openSUSE.cmake +++ b/admin/win/Toolchain-mingw32-openSUSE.cmake @@ -1,20 +1,27 @@ +SET(MINGW_PREFIX "i686-w64-mingw32") + # this one is important SET(CMAKE_SYSTEM_NAME Windows) # specify the cross compiler -SET(CMAKE_C_COMPILER ccache i686-w64-mingw32-gcc) -SET(CMAKE_CXX_COMPILER ccache i686-w64-mingw32-g++) +SET(CMAKE_C_COMPILER ccache ${MINGW_PREFIX}-gcc) +SET(CMAKE_CXX_COMPILER ccache ${MINGW_PREFIX}-g++) +SET(CMAKE_RC_COMPILER /usr/bin/${MINGW_PREFIX}-windres) # where is the target environment containing libraries -SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32/sys-root/mingw) +SET(CMAKE_FIND_ROOT_PATH /usr/${MINGW_PREFIX}/sys-root/mingw) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -# windres executable for application icon support -SET(WINDRES_EXECUTABLE /usr/bin/i686-w64-mingw32-windres) + # libs with broken find modules SET(TAGLIB_FOUND true) SET(TAGLIB_LIBRARIES ${CMAKE_FIND_ROOT_PATH}/lib/libtag.dll.a) SET(TAGLIB_INCLUDES ${CMAKE_FIND_ROOT_PATH}/include/taglib) + +SET(QT_PLUGINS_DIR ${CMAKE_FIND_ROOT_PATH}/lib/qt4/plugins/) +SET(QT_QTUITOOLS_LIBRARY_RELEASE ${CMAKE_FIND_ROOT_PATH}/lib/libQtUiTools.a) +SET(QT_QTUITOOLS_LIBRARY_DEBUG ${CMAKE_FIND_ROOT_PATH}/lib/libQtUiToolsd.a) +SET(QT_QTUITOOLS_LIBRARY ${QT_QTUITOOLS_LIBRARY_RELEASE}) \ No newline at end of file diff --git a/data/images/album-shadow.png b/data/images/album-shadow.png new file mode 100644 index 000000000..a053655e2 Binary files /dev/null and b/data/images/album-shadow.png differ diff --git a/data/images/avatar_frame.png b/data/images/avatar_frame.png index 999ba0cae..120fe8894 100644 Binary files a/data/images/avatar_frame.png and b/data/images/avatar_frame.png differ diff --git a/data/images/supercollection.png b/data/images/supercollection.png index e965f88e4..6c6f192d9 100644 Binary files a/data/images/supercollection.png and b/data/images/supercollection.png differ diff --git a/data/images/track-placeholder.png b/data/images/track-placeholder.png new file mode 100644 index 000000000..fbc578124 Binary files /dev/null and b/data/images/track-placeholder.png differ diff --git a/data/images/user-avatar.png b/data/images/user-avatar.png index ae26a18a4..0c761043b 100644 Binary files a/data/images/user-avatar.png and b/data/images/user-avatar.png differ diff --git a/resources.qrc b/resources.qrc index 2360b353b..977d1dfff 100644 --- a/resources.qrc +++ b/resources.qrc @@ -10,6 +10,7 @@ data/images/not-loved.png data/images/no-album-art-placeholder.png data/images/no-artist-image-placeholder.png + data/images/track-placeholder.png data/images/now-playing-panel.png data/images/now-playing-speaker.png data/images/pause-pressed.png @@ -85,6 +86,7 @@ data/images/station.png data/images/new-additions.png data/images/loved_playlist.png + data/images/dashboard.png data/stylesheets/topbar-radiobuttons.css data/icons/tomahawk-icon-16x16.png data/icons/tomahawk-icon-32x32.png diff --git a/src/CMakeLists.osx.txt b/src/CMakeLists.osx.txt index f88939b80..27edb81b8 100644 --- a/src/CMakeLists.osx.txt +++ b/src/CMakeLists.osx.txt @@ -49,4 +49,8 @@ if (APPLE) ) ENDIF() FILE( WRITE ${CMAKE_BINARY_DIR}/Info.plist "${edited_plist}" ) + + FILE(COPY ${CMAKE_SOURCE_DIR}/admin/mac/sparkle_pub.pem + DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/Resources") + endif (APPLE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1eaf2afb1..2a1cc320b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ SET( QT_USE_QTXML TRUE ) SET( QT_USE_QTWEBKIT TRUE ) INCLUDE( ${QT_USE_FILE} ) -INCLUDE( ${CMAKE_MODULE_PATH}/AddAppIconMacro.cmake ) +INCLUDE( AddAppIconMacro ) #SET( CMAKE_BUILD_TYPE "Release" ) SET( CMAKE_VERBOSE_MAKEFILE ON ) diff --git a/src/PipelineStatusView.cpp b/src/PipelineStatusView.cpp index c6206a076..6d4fb28d0 100644 --- a/src/PipelineStatusView.cpp +++ b/src/PipelineStatusView.cpp @@ -43,6 +43,7 @@ PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent ) headers << tr( "Searching For" ) << tr( "Pending" ); m_tree->setHeaderLabels( headers ); + m_tree->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_tree->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); m_tree->setColumnCount( 2 ); m_tree->setColumnWidth( 0, 200 ); @@ -59,6 +60,17 @@ PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent ) connect( Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), SLOT( onPipelineUpdate( Tomahawk::query_ptr ) ) ); connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onPipelineUpdate() ) ); +#ifndef Q_WS_WIN + QFont f = font(); + f.setPointSize( f.pointSize() - 1 ); + setFont( f ); +#endif + +#ifdef Q_WS_MAC + f.setPointSize( f.pointSize() - 2 ); + setFont( f ); +#endif + onPipelineUpdate(); } diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index a37675893..947ba5f0c 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -50,8 +50,6 @@ AudioControls::AudioControls( QWidget* parent ) ui->setupUi( this ); setAcceptDrops( true ); - ui->buttonAreaLayout->setSpacing( 2 ); - QFont font( ui->artistTrackLabel->font() ); font.setPixelSize( 12 ); @@ -181,6 +179,15 @@ AudioControls::AudioControls( QWidget* parent ) connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); + + ui->buttonAreaLayout->setSpacing( 0 ); + ui->stackedLayout->setSpacing( 0 ); + ui->stackedLayout->setContentsMargins( 0, 0, 0, 0 ); + ui->stackedLayout->setMargin( 0 ); + ui->playPauseButton->setContentsMargins( 0, 0, 0, 0 ); + ui->pauseButton->setContentsMargins( 0, 0, 0, 0 ); + ui->stackedLayout->setSizeConstraint( QLayout::SetFixedSize ); + onPlaybackStopped(); // initial state } @@ -301,10 +308,8 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result ) /* m_playAction->setEnabled( false ); m_pauseAction->setEnabled( true ); */ - ui->pauseButton->setEnabled( true ); - ui->pauseButton->setVisible( true ); - ui->playPauseButton->setVisible( false ); - ui->playPauseButton->setEnabled( false ); + ui->stackedLayout->setCurrentWidget( ui->pauseButton ); + ui->loveButton->setEnabled( true ); ui->loveButton->setVisible( true ); @@ -341,23 +346,16 @@ AudioControls::onPlaybackPaused() /* m_pauseAction->setEnabled( false ); m_playAction->setEnabled( true ); */ - ui->pauseButton->setVisible( false ); - ui->pauseButton->setEnabled( false ); - ui->playPauseButton->setEnabled( true ); - ui->playPauseButton->setVisible( true ); + ui->stackedLayout->setCurrentWidget( ui->playPauseButton ); } - void AudioControls::onPlaybackResumed() { /* m_playAction->setEnabled( false ); m_pauseAction->setEnabled( true ); */ - ui->playPauseButton->setVisible( false ); - ui->playPauseButton->setEnabled( false ); - ui->pauseButton->setVisible( true ); - ui->pauseButton->setEnabled( true ); + ui->stackedLayout->setCurrentWidget( ui->pauseButton ); ui->loveButton->setVisible( true ); } @@ -375,10 +373,7 @@ AudioControls::onPlaybackStopped() ui->coverImage->setPixmap( QPixmap() ); ui->seekSlider->setVisible( false ); - ui->pauseButton->setVisible( false ); - ui->pauseButton->setEnabled( false ); - ui->playPauseButton->setEnabled( true ); - ui->playPauseButton->setVisible( true ); + ui->stackedLayout->setCurrentWidget( ui->playPauseButton ); ui->loveButton->setEnabled( false ); ui->loveButton->setVisible( false ); diff --git a/src/audiocontrols.ui b/src/audiocontrols.ui index 872d5089f..a73e384b8 100644 --- a/src/audiocontrols.ui +++ b/src/audiocontrols.ui @@ -6,7 +6,7 @@ 0 0 - 939 + 929 80 @@ -60,7 +60,7 @@ - + Qt::Horizontal @@ -80,18 +80,25 @@ - - - Play + + + 0 - - - - - - Pause - - + + + + Play + + + + + + + Pause + + + + @@ -101,7 +108,7 @@ - + Qt::Horizontal diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 702c51ef0..3a2ab78e2 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -173,6 +173,7 @@ set( libSources utils/xspfgenerator.cpp utils/jspfloader.cpp utils/spotifyparser.cpp + utils/rdioparser.cpp utils/shortenedlinkparser.cpp widgets/newplaylistwidget.cpp @@ -185,6 +186,7 @@ set( libSources widgets/SocialPlaylistWidget.cpp widgets/infowidgets/sourceinfowidget.cpp widgets/infowidgets/ArtistInfoWidget.cpp + widgets/infowidgets/AlbumInfoWidget.cpp kdsingleapplicationguard/kdsingleapplicationguard.cpp kdsingleapplicationguard/kdsharedmemorylocker.cpp @@ -352,6 +354,7 @@ set( libHeaders utils/xspfgenerator.h utils/jspfloader.h utils/spotifyparser.h + utils/rdioparser.h utils/shortenedlinkparser.h widgets/newplaylistwidget.h @@ -364,6 +367,7 @@ set( libHeaders widgets/SocialPlaylistWidget.h widgets/infowidgets/sourceinfowidget.h widgets/infowidgets/ArtistInfoWidget.h + widgets/infowidgets/AlbumInfoWidget.h kdsingleapplicationguard/kdsingleapplicationguard.h ) @@ -387,6 +391,7 @@ set( libUI ${libUI} widgets/SocialPlaylistWidget.ui widgets/infowidgets/sourceinfowidget.ui widgets/infowidgets/ArtistInfoWidget.ui + widgets/infowidgets/AlbumInfoWidget.ui playlist/topbar/topbar.ui playlist/infobar/infobar.ui ) @@ -488,7 +493,9 @@ target_link_libraries( tomahawklib ${TAGLIB_LIBRARIES} ${CLUCENE_LIBRARIES} ${LIBECHONEST_LIBRARY} + ${QT_QTUITOOLS_LIBRARY} ${QT_LIBRARIES} + ${QT_QTUITOOLS_LIBRARY} # We really need to link twice against it for windows, maybe QTBUG-20498 is related ${OS_SPECIFIC_LINK_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${LINK_LIBRARIES} diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index a60a01918..1a797ee3a 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -46,6 +46,7 @@ #include "utils/jspfloader.h" #include "utils/spotifyparser.h" #include "utils/shortenedlinkparser.h" +#include "utils/rdioparser.h" GlobalActionManager* GlobalActionManager::s_instance = 0; @@ -791,14 +792,20 @@ GlobalActionManager::acceptsMimeData( const QMimeData* data, bool tracksOnly ) // crude check for spotify tracks if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "spotify" ) && - ( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) ) + ( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) ) + return true; + + // crude check for rdio tracks + if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rdio.com" ) && + ( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) ) return true; // We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them, // so we do an extra level of lookup if ( ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "bit.ly" ) ) || ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "j.mp" ) ) || - ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "t.co" ) ) ) + ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "t.co" ) ) || + ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rd.io" ) ) ) return true; return false; @@ -831,9 +838,18 @@ GlobalActionManager::handleTrackUrls( const QString& urls ) tDebug() << "Got a list of spotify urls!" << tracks; SpotifyParser* spot = new SpotifyParser( tracks, this ); connect( spot, SIGNAL( tracks( QList ) ), this, SIGNAL( tracks( QList ) ) ); + } else if ( urls.contains( "rdio.com" ) ) + { + QStringList tracks = urls.split( "\n" ); + + tDebug() << "Got a list of rdio urls!" << tracks; + RdioParser* rdio = new RdioParser( this ); + connect( rdio, SIGNAL( tracks( QList ) ), this, SIGNAL( tracks( QList ) ) ); + rdio->parse( tracks ); } else if ( urls.contains( "bit.ly" ) || urls.contains( "j.mp" ) || - urls.contains( "t.co" ) ) + urls.contains( "t.co" ) || + urls.contains( "rd.io" ) ) { QStringList tracks = urls.split( "\n" ); @@ -909,3 +925,14 @@ GlobalActionManager::openSpotifyLink( const QString& link ) return true; } + +bool +GlobalActionManager::openRdioLink( const QString& link ) +{ + RdioParser* rdio = new RdioParser( this ); + connect( rdio, SIGNAL( track( Tomahawk::query_ptr ) ), this, SLOT( handleOpenTrack( Tomahawk::query_ptr ) ) ); + rdio->parse( link ); + + return true; +} + diff --git a/src/libtomahawk/globalactionmanager.h b/src/libtomahawk/globalactionmanager.h index 725e8c959..c06561b3f 100644 --- a/src/libtomahawk/globalactionmanager.h +++ b/src/libtomahawk/globalactionmanager.h @@ -44,6 +44,9 @@ public: /// Takes a spotify link and performs the default open action on it bool openSpotifyLink( const QString& link ); + /// Takes a spotify link and performs the default open action on it + bool openRdioLink( const QString& link ); + void copyToClipboard( const Tomahawk::query_ptr& query ) const; QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename ); diff --git a/src/libtomahawk/pipeline.h b/src/libtomahawk/pipeline.h index 599817572..df0c32c19 100644 --- a/src/libtomahawk/pipeline.h +++ b/src/libtomahawk/pipeline.h @@ -66,9 +66,9 @@ public: } public slots: - void resolve( const query_ptr& q, bool prioritized = false, bool temporaryQuery = false ); - void resolve( const QList& qlist, bool prioritized = false, bool temporaryQuery = false ); - void resolve( QID qid, bool prioritized = false, bool temporaryQuery = false ); + void resolve( const query_ptr& q, bool prioritized = true, bool temporaryQuery = false ); + void resolve( const QList& qlist, bool prioritized = true, bool temporaryQuery = false ); + void resolve( QID qid, bool prioritized = true, bool temporaryQuery = false ); void start(); void stop(); diff --git a/src/libtomahawk/playlist/customplaylistview.cpp b/src/libtomahawk/playlist/customplaylistview.cpp index 7c262d8af..d2306f4dd 100644 --- a/src/libtomahawk/playlist/customplaylistview.cpp +++ b/src/libtomahawk/playlist/customplaylistview.cpp @@ -43,6 +43,7 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c connect( m_source.data(), SIGNAL( socialAttributesChanged() ), this, SLOT( reload() ) ); else if ( m_type == AllLovedTracks ) { + connect( SourceList::instance()->getLocal().data(), SIGNAL( socialAttributesChanged() ), this, SLOT( reload() ) ); foreach ( const source_ptr& s, SourceList::instance()->sources( true ) ) connect( s.data(), SIGNAL( socialAttributesChanged() ), this, SLOT( reload() ) ); diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h index 63e29e9fe..35ed57ed9 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h @@ -219,4 +219,6 @@ private: }; // namespace +Q_DECLARE_METATYPE( QSharedPointer< Tomahawk::DynamicPlaylist > ) + #endif diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index dea04b55e..22dafb554 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -401,8 +401,8 @@ EchonestGenerator::appendRadioType( Echonest::DynamicPlaylist::PlaylistParams& p params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistRadioType ) ); else if( onlyThisArtistType( Echonest::DynamicPlaylist::SongRadioType ) ) params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::SongRadioType ) ); - else // no artist or song or description types. default to song-radio - params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::SongRadioType ) ); + else // no artist or song or description types. default to artist-description + params.append( Echonest::DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistDescriptionType ) ); return static_cast< Echonest::DynamicPlaylist::ArtistTypeEnum >( params.last().second.toInt() ); } diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp index 9fa4d0e24..23cfa14a9 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.cpp @@ -427,6 +427,17 @@ DynamicWidget::paintRoundedFilledRect( QPainter& p, QPalette& pal, QRect& r, qre p.drawRoundedRect( r, 10, 10 ); } +QPixmap +DynamicWidget::pixmap() const +{ + if ( m_playlist->mode() == OnDemand ) + return QPixmap( RESPATH "images/station.png" ); + else if ( m_playlist->mode() == Static ) + return QPixmap( RESPATH "images/automatic-playlist.png" ); + else + return QPixmap(); +} + bool DynamicWidget::jumpToCurrentTrack() diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h index 31f1040a3..26f61baae 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicWidget.h @@ -77,7 +77,7 @@ public: virtual QString title() const { return m_model->title(); } virtual QString description() const { return m_model->description(); } - virtual QPixmap pixmap() const { return QPixmap( RESPATH "images/playlist-icon.png" ); } + virtual QPixmap pixmap() const; virtual bool jumpToCurrentTrack(); diff --git a/src/libtomahawk/playlist/playlistitemdelegate.cpp b/src/libtomahawk/playlist/playlistitemdelegate.cpp index 0a51adc9d..6c3f9931b 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.cpp +++ b/src/libtomahawk/playlist/playlistitemdelegate.cpp @@ -57,6 +57,8 @@ PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel* m_centerOption = QTextOption( Qt::AlignVCenter ); m_centerOption.setWrapMode( QTextOption::NoWrap ); + + m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) ); } @@ -75,7 +77,7 @@ PlaylistItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModel if ( index.isValid() ) { int style = index.data( TrackModel::StyleRole ).toInt(); - if ( style == TrackModel::Short ) + if ( style == TrackModel::Short || style == TrackModel::ShortWithAvatars ) size.setHeight( 44 ); } @@ -135,12 +137,14 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti case TrackModel::Short: paintShort( painter, option, index ); break; + case TrackModel::ShortWithAvatars: + paintShort( painter, option, index, true ); } } void -PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, bool useAvatars ) const { TrackModelItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) ); Q_ASSERT( item ); @@ -184,11 +188,14 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& else lowerText = QString( "played %1 ago by %2" ).arg( playtime ).arg( source->friendlyName() ); - pixmap = source->avatar(); + if ( useAvatars ) + pixmap = source->avatar( Source::FancyStyle ); } - if ( pixmap.isNull() ) - pixmap = QPixmap( RESPATH "images/user-avatar.png" ); + if ( pixmap.isNull() && !useAvatars ) + pixmap = QPixmap( RESPATH "images/track-placeholder.png" ); + else if ( pixmap.isNull() && useAvatars ) + pixmap = m_defaultAvatar; painter->save(); { @@ -227,7 +234,8 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& QString text = painter->fontMetrics().elidedText( upperText, Qt::ElideRight, r.width() ); painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_topOption ); - painter->setFont( opt.font ); + + painter->setFont( opt.font); text = painter->fontMetrics().elidedText( lowerText, Qt::ElideRight, r.width() ); painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, m_bottomOption ); } @@ -261,11 +269,7 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt if ( index.column() == TrackModel::Score ) { -#ifdef Q_OS_MAC // On Mac, highlight color is very bright and stands out a lot QColor barColor( 167, 183, 211 ); // This matches the sidebar (sourcetreeview.cpp:672) -#else - QColor barColor = opt.palette.highlight().color(); -#endif if ( opt.state & QStyle::State_Selected ) painter->setPen( opt.palette.brightText().color() ); else diff --git a/src/libtomahawk/playlist/playlistitemdelegate.h b/src/libtomahawk/playlist/playlistitemdelegate.h index 6d9bcae7c..98fc25674 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.h +++ b/src/libtomahawk/playlist/playlistitemdelegate.h @@ -50,12 +50,12 @@ private: void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, TrackModelItem* item ) const; void paintDetailed( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; - void paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + void paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, bool useAvatars = false ) const; unsigned int m_removalProgress; mutable QHash< qint64, QPixmap > m_cache; - QPixmap m_nowPlayingIcon; + QPixmap m_nowPlayingIcon, m_defaultAvatar; mutable QPixmap m_arrowIcon; QTextOption m_topOption; diff --git a/src/libtomahawk/playlist/playlistmodel.cpp b/src/libtomahawk/playlist/playlistmodel.cpp index 43cd42b00..4cbe80019 100644 --- a/src/libtomahawk/playlist/playlistmodel.cpp +++ b/src/libtomahawk/playlist/playlistmodel.cpp @@ -116,7 +116,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn m_waitingForResolved.clear(); foreach( const plentry_ptr& entry, entries ) { - qDebug() << entry->query()->toString(); +// qDebug() << entry->query()->toString(); plitem = new TrackModelItem( entry, m_rootItem ); plitem->index = createIndex( m_rootItem->children.count() - 1, 0, plitem ); diff --git a/src/libtomahawk/playlist/trackmodel.h b/src/libtomahawk/playlist/trackmodel.h index a95c88b80..db456f00e 100644 --- a/src/libtomahawk/playlist/trackmodel.h +++ b/src/libtomahawk/playlist/trackmodel.h @@ -34,7 +34,7 @@ Q_OBJECT public: enum TrackItemStyle - { Detailed = 0, Short = 1 }; + { Detailed = 0, Short = 1, ShortWithAvatars = 2 }; enum TrackModelRole { StyleRole = Qt::UserRole + 1 }; diff --git a/src/libtomahawk/playlist/trackview.h b/src/libtomahawk/playlist/trackview.h index b151a251c..d2eec8344 100644 --- a/src/libtomahawk/playlist/trackview.h +++ b/src/libtomahawk/playlist/trackview.h @@ -56,6 +56,7 @@ explicit TrackView( QWidget* parent = 0 ); TrackHeader* header() const { return m_header; } OverlayWidget* overlay() const { return m_overlay; } Tomahawk::ContextMenu* contextMenu() const { return m_contextMenu; } + LoadingSpinner* loadingSpinner() const { return m_loadingSpinner; } QModelIndex hoveredIndex() const { return m_hoveredIndex; } QModelIndex contextMenuIndex() const { return m_contextMenuIndex; } diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index eda3ae385..cbab0dfb2 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -38,9 +38,12 @@ using namespace Tomahawk; query_ptr Query::get( const QString& artist, const QString& track, const QString& album, const QID& qid, bool autoResolve ) { + if ( qid.isEmpty() ) + autoResolve = false; + query_ptr q = query_ptr( new Query( artist, track, album, qid, autoResolve ) ); - if ( autoResolve && !qid.isEmpty() ) + if ( autoResolve ) Pipeline::instance()->resolve( q ); return q; } diff --git a/src/libtomahawk/source.cpp b/src/libtomahawk/source.cpp index 191906833..24e7aaa37 100644 --- a/src/libtomahawk/source.cpp +++ b/src/libtomahawk/source.cpp @@ -127,10 +127,17 @@ Source::setAvatar( const QPixmap& avatar ) QPixmap -Source::avatar() const +Source::avatar( AvatarStyle style ) const { - if( !m_avatar.isNull() ) - return TomahawkUtils::createAvatarFrame( m_avatar ); + if ( style == FancyStyle && + !m_avatar.isNull() && + m_fancyAvatar.isNull() ) + m_fancyAvatar = TomahawkUtils::createAvatarFrame( m_avatar ); + + if ( style == Original && !m_avatar.isNull() ) + return m_avatar; + else if ( style == FancyStyle && !m_fancyAvatar.isNull() ) + return m_fancyAvatar; else return QPixmap(); } diff --git a/src/libtomahawk/source.h b/src/libtomahawk/source.h index b18dbe407..d368db784 100644 --- a/src/libtomahawk/source.h +++ b/src/libtomahawk/source.h @@ -45,6 +45,8 @@ friend class ::DBSyncConnection; friend class ::DatabaseCommand_SocialAction; public: + enum AvatarStyle { Original, FancyStyle }; + explicit Source( int id, const QString& username = QString() ); virtual ~Source(); @@ -58,7 +60,7 @@ public: void setFriendlyName( const QString& fname ); void setAvatar( const QPixmap& avatar ); - QPixmap avatar() const; + QPixmap avatar( AvatarStyle style = Original ) const; collection_ptr collection() const; void addCollection( const Tomahawk::collection_ptr& c ); @@ -132,6 +134,7 @@ private: ControlConnection* m_cc; QPixmap m_avatar; + mutable QPixmap m_fancyAvatar; Tomahawk::playlistinterface_ptr m_playlistInterface; }; diff --git a/src/libtomahawk/utils/proxystyle.cpp b/src/libtomahawk/utils/proxystyle.cpp index 1e906f0f6..0c1bf1dc0 100644 --- a/src/libtomahawk/utils/proxystyle.cpp +++ b/src/libtomahawk/utils/proxystyle.cpp @@ -80,6 +80,13 @@ ProxyStyle::drawControl( ControlElement ce, const QStyleOption* opt, QPainter* p p->setPen( QColor( 0x8c, 0x8c, 0x8c ) ); p->drawLine( opt->rect.topLeft(), opt->rect.bottomRight() ); } +#ifndef Q_WS_MAC + else + { + p->setPen( QColor( 0xff, 0xff, 0xff ) ); + p->drawLine( opt->rect.topLeft(), opt->rect.bottomRight() ); + } +#endif } else QProxyStyle::drawControl( ce, opt, p, w ); diff --git a/src/libtomahawk/utils/rdioparser.cpp b/src/libtomahawk/utils/rdioparser.cpp new file mode 100644 index 000000000..a10ab2462 --- /dev/null +++ b/src/libtomahawk/utils/rdioparser.cpp @@ -0,0 +1,101 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "rdioparser.h" + +#include +#include + +using namespace Tomahawk; + +RdioParser::RdioParser( QObject* parent ) + : QObject( parent ) + , m_count( 0 ) +{ +} + +RdioParser::~RdioParser() +{ +} + +void +RdioParser::parse( const QString& url ) +{ + m_multi = false; + m_total = 1; + parseUrl( url ); +} + +void +RdioParser::parse( const QStringList& urls ) +{ + m_multi = true; + m_total = urls.count(); + + foreach( const QString& url, urls ) + parseUrl( url ); +} + + +void +RdioParser::parseUrl( const QString& url ) +{ + query_ptr query; + m_count++; + + if ( url.contains( "artist" ) && url.contains( "album" ) ) + { + // this is a "full" url, no redirection needed + QString realUrl = QUrl::fromUserInput( url ).toString().replace( "_", " " ); + + QString artist, trk, album; + QString matchStr = "/%1/([^/]*)/"; + QRegExp r( QString( matchStr ).arg( "artist" ) ); + + int loc = r.indexIn( realUrl ); + if ( loc >= 0 ) + artist = r.cap( 1 ); + + r = QRegExp( QString( matchStr ).arg( "album" ) ); + loc = r.indexIn( realUrl ); + if ( loc >= 0 ) + album = r.cap( 1 ); + + r = QRegExp( QString( matchStr ).arg( "track" ) ); + loc = r.indexIn( realUrl ); + if ( loc >= 0 ) + trk = r.cap( 1 ); + + if ( !trk.isEmpty() && !artist.isEmpty() ) + { + query = Query::get( artist, trk, album, uuid(), true ); + } + } + + if ( m_multi ) + { + if ( !query.isNull() ) + m_queries << query; + + if ( m_count == m_total ) + emit tracks( m_queries ); + } + if ( !m_multi && !query.isNull() ) + emit track( query ); +} + diff --git a/src/libtomahawk/utils/rdioparser.h b/src/libtomahawk/utils/rdioparser.h new file mode 100644 index 000000000..8d2cece5b --- /dev/null +++ b/src/libtomahawk/utils/rdioparser.h @@ -0,0 +1,62 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef RDIOPARSER_H +#define RDIOPARSER_H + +#include +#include + +#include "query.h" +#include "source.h" + +class QNetworkReply; +namespace Tomahawk +{ + +/** + * Small class to parse spotify links into query_ptrs + * + * Connect to the signals to get the results + */ + +class RdioParser : public QObject +{ + Q_OBJECT +public: + explicit RdioParser( QObject* parent = 0 ); + virtual ~RdioParser(); + + void parse( const QString& url ); + void parse( const QStringList& urls ); + +signals: + void track( const Tomahawk::query_ptr& track ); + void tracks( const QList< Tomahawk::query_ptr > tracks ); + +private: + void parseUrl( const QString& url ); + + bool m_multi; + int m_count, m_total; + QList< query_ptr > m_queries; +}; + +} + +#endif // RDIOPARSER_H diff --git a/src/libtomahawk/utils/shortenedlinkparser.cpp b/src/libtomahawk/utils/shortenedlinkparser.cpp index 6b1cade6c..6e2d04847 100644 --- a/src/libtomahawk/utils/shortenedlinkparser.cpp +++ b/src/libtomahawk/utils/shortenedlinkparser.cpp @@ -44,7 +44,8 @@ ShortenedLinkParser::lengthenUrl( const QString& url ) // Whitelisted links if ( !( url.contains( "t.co" ) || url.contains( "bit.ly" ) || - url.contains( "j.mp" ) ) ) + url.contains( "j.mp" ) || + url.contains( "rd.io" ) ) ) return; tDebug() << "Looking up..." << url; diff --git a/src/libtomahawk/utils/tomahawkutils.cpp b/src/libtomahawk/utils/tomahawkutils.cpp index 9b37b9c8d..950e76ebe 100644 --- a/src/libtomahawk/utils/tomahawkutils.cpp +++ b/src/libtomahawk/utils/tomahawkutils.cpp @@ -349,6 +349,46 @@ createDragPixmap( int itemCount ) return dragPixmap; } +void +drawBackgroundAndNumbers( QPainter* painter, const QString& text, const QRect& figRectIn ) +{ + QRect figRect = figRectIn; + if ( text.length() == 1 ) + figRect.adjust( -painter->fontMetrics().averageCharWidth(), 0, 0, 0 ); + + QPen origpen = painter->pen(); + QPen pen = origpen; + pen.setWidth( 1.0 ); + painter->setPen( pen ); + painter->drawRect( figRect ); + + // circles look bad. make it an oval. (thanks, apple) + const int bulgeWidth = 8; + const int offset = 0; // number of pixels to begin, counting inwards from figRect.x() and figRect.width(). 0 means start at each end, negative means start inside the rect. + + QPainterPath ppath; + ppath.moveTo( QPoint( figRect.x() + offset, figRect.y() + figRect.height() / 2 ) ); + QRect leftArcRect( figRect.x() + offset - bulgeWidth, figRect.y(), 2*bulgeWidth, figRect.height() ); + ppath.arcTo( leftArcRect, 90, 180 ); + painter->drawPath( ppath ); + + ppath = QPainterPath(); + ppath.moveTo( figRect.x() + figRect.width() - offset, figRect.y() + figRect.height() / 2 ); + leftArcRect = QRect( figRect.x() + figRect.width() - offset - bulgeWidth, figRect.y(), 2*bulgeWidth, figRect.height() ); + ppath.arcTo( leftArcRect, 270, 180 ); + painter->drawPath( ppath ); + + painter->setPen( origpen ); + +#ifdef Q_OS_MAC + figRect.adjust( -1, 0, 0, 0 ); +#endif + + QTextOption to( Qt::AlignCenter ); + painter->setPen( Qt::white ); + painter->drawText( figRect.adjusted( -5, 0, 6, 0 ), text, to ); +} + void unmarginLayout( QLayout* layout ) diff --git a/src/libtomahawk/utils/tomahawkutils.h b/src/libtomahawk/utils/tomahawkutils.h index d72fcd015..238e63143 100644 --- a/src/libtomahawk/utils/tomahawkutils.h +++ b/src/libtomahawk/utils/tomahawkutils.h @@ -25,9 +25,11 @@ #include #include #include +#include #define RESPATH ":/data/" +class QPainter; class QColor; class QDir; class QDateTime; @@ -74,6 +76,8 @@ namespace TomahawkUtils DLLEXPORT QColor alphaBlend( const QColor& colorFrom, const QColor& colorTo, float opacity ); DLLEXPORT QPixmap createDragPixmap( int itemCount = 1 ); + DLLEXPORT void drawBackgroundAndNumbers( QPainter* p, const QString& text, const QRect& rect ); + DLLEXPORT void unmarginLayout( QLayout* layout ); DLLEXPORT NetworkProxyFactory* proxyFactory(); diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index 54fdd54ce..1be1c6a1e 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -46,6 +46,7 @@ #include "widgets/welcomewidget.h" #include "widgets/infowidgets/sourceinfowidget.h" #include "widgets/infowidgets/ArtistInfoWidget.h" +#include "widgets/infowidgets/AlbumInfoWidget.h" #include "widgets/newplaylistwidget.h" #include "utils/logger.h" @@ -79,10 +80,12 @@ ViewManager::ViewManager( QObject* parent ) m_infobar = new InfoBar(); m_stack = new QStackedWidget(); +#ifdef Q_OS_MAC QFrame* line = new QFrame(); line->setFrameStyle( QFrame::HLine ); line->setStyleSheet( "border: 1px solid gray;" ); line->setMaximumHeight( 1 ); +#endif m_splitter = new AnimatedSplitter(); m_splitter->setOrientation( Qt::Vertical ); @@ -100,7 +103,9 @@ ViewManager::ViewManager( QObject* parent ) m_widget->layout()->addWidget( m_infobar ); m_widget->layout()->addWidget( m_topbar ); +#ifdef Q_OS_MAC m_widget->layout()->addWidget( line ); +#endif m_widget->layout()->addWidget( m_splitter ); m_superCollectionView = new ArtistView(); @@ -237,27 +242,19 @@ ViewManager::show( const Tomahawk::artist_ptr& artist ) Tomahawk::ViewPage* ViewManager::show( const Tomahawk::album_ptr& album ) { - PlaylistView* view; + AlbumInfoWidget* swidget; if ( !m_albumViews.contains( album ) ) { - view = new PlaylistView(); - PlaylistModel* model = new PlaylistModel(); - model->append( album ); - view->setPlaylistModel( model ); - view->setFrameShape( QFrame::NoFrame ); - view->setAttribute( Qt::WA_MacShowFocusRect, 0 ); - - m_albumViews.insert( album, view ); + swidget = new AlbumInfoWidget( album ); + m_albumViews.insert( album, swidget ); } else { - view = m_albumViews.value( album ); + swidget = m_albumViews.value( album ); } - setPage( view ); - emit numSourcesChanged( 1 ); - - return view; + setPage( swidget ); + return swidget; } diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index 2321265cb..8d597d610 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -33,6 +33,7 @@ class AnimatedSplitter; class AlbumModel; class AlbumView; +class AlbumInfoWidget; class ArtistInfoWidget; class ArtistView; class CollectionModel; @@ -188,7 +189,7 @@ private: QHash< Tomahawk::collection_ptr, ArtistView* > m_treeViews; QHash< Tomahawk::collection_ptr, AlbumView* > m_collectionAlbumViews; QHash< Tomahawk::artist_ptr, ArtistInfoWidget* > m_artistViews; - QHash< Tomahawk::album_ptr, PlaylistView* > m_albumViews; + QHash< Tomahawk::album_ptr, AlbumInfoWidget* > m_albumViews; QHash< Tomahawk::playlist_ptr, PlaylistView* > m_playlistViews; QHash< Tomahawk::source_ptr, SourceInfoWidget* > m_sourceViews; diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp new file mode 100644 index 000000000..6e9dc8374 --- /dev/null +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -0,0 +1,162 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "AlbumInfoWidget.h" +#include "ui_AlbumInfoWidget.h" + +#include "viewmanager.h" +#include "playlist/treemodel.h" +#include "playlist/albummodel.h" + +#include "database/databasecommand_alltracks.h" +#include "database/databasecommand_allalbums.h" + +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#include "widgets/overlaywidget.h" + +static QString s_aiInfoIdentifier = QString( "AlbumInfoWidget" ); + +using namespace Tomahawk; + + +AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* parent ) + : QWidget( parent ) + , ui( new Ui::AlbumInfoWidget ) + , m_album( album ) +{ + ui->setupUi( this ); + + ui->albumsView->setFrameShape( QFrame::NoFrame ); + ui->albumsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + ui->tracksView->setFrameShape( QFrame::NoFrame ); + ui->tracksView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + TomahawkUtils::unmarginLayout( layout() ); + + m_albumsModel = new AlbumModel( ui->albumsView ); + ui->albumsView->setAlbumModel( m_albumsModel ); + + m_tracksModel = new TreeModel( ui->tracksView ); + ui->tracksView->setTreeModel( m_tracksModel ); + + m_pixmap = QPixmap( RESPATH "images/no-album-art-placeholder.png" ).scaledToWidth( 48, Qt::SmoothTransformation ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); + + load( album ); +} + + +AlbumInfoWidget::~AlbumInfoWidget() +{ + delete ui; +} + + +void +AlbumInfoWidget::load( const album_ptr& album ) +{ + m_title = album->name(); + m_description = album->artist()->name(); + m_tracksModel->addTracks( album, QModelIndex() ); + + QList al; + al << album; + m_albumsModel->addAlbums( al ); + + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; + trackInfo["artist"] = album->artist()->name(); + trackInfo["album"] = album->name(); + + Tomahawk::InfoSystem::InfoRequestData requestData; + requestData.caller = s_aiInfoIdentifier; + requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt; + requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ); + requestData.customData = QVariantMap(); + + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); +} + + +void +AlbumInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ) +{ + if ( requestData.caller != s_aiInfoIdentifier ) + { + return; + } + + InfoSystem::InfoCriteriaHash trackInfo; + trackInfo = requestData.input.value< InfoSystem::InfoCriteriaHash >(); + + if ( output.canConvert< QVariantMap >() ) + { + if ( trackInfo["album"] != m_album->name() ) + { + qDebug() << "Returned info was for:" << trackInfo["album"] << "- was looking for:" << m_album->name(); + return; + } + } + + QVariantMap returnedData = output.value< QVariantMap >(); + switch ( requestData.type ) + { + case Tomahawk::InfoSystem::InfoAlbumCoverArt: + { + QVariantMap returnedData = output.value< QVariantMap >(); + const QByteArray ba = returnedData["imgbytes"].toByteArray(); + if ( ba.length() ) + { + m_pixmap.loadFromData( ba ); + emit pixmapChanged( m_pixmap ); + } + } + + default: + return; + } +} + + +void +AlbumInfoWidget::infoSystemFinished( QString target ) +{ + Q_UNUSED( target ); +} + + +void +AlbumInfoWidget::changeEvent( QEvent* e ) +{ + QWidget::changeEvent( e ); + switch ( e->type() ) + { + case QEvent::LanguageChange: + ui->retranslateUi( this ); + break; + + default: + break; + } +} diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h new file mode 100644 index 000000000..9975ff522 --- /dev/null +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h @@ -0,0 +1,106 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +/** + * \class AlbumInfoWidget + * \brief ViewPage, which displays an album for an artist and recommends others. + * + * This Tomahawk ViewPage displays the tracks of any given album + * It is our default ViewPage when showing an artist via ViewManager. + * + */ + +#ifndef ALBUMINFOWIDGET_H +#define ALBUMINFOWIDGET_H + +#include + +#include "artist.h" +#include "result.h" +#include "playlistinterface.h" +#include "viewpage.h" +#include "infosystem/infosystem.h" + +#include "dllmacro.h" + +class AlbumModel; +class TreeModel; + +namespace Ui +{ + class AlbumInfoWidget; +} + +class DLLEXPORT AlbumInfoWidget : public QWidget, public Tomahawk::ViewPage +{ +Q_OBJECT + +public: + AlbumInfoWidget( const Tomahawk::album_ptr& album, QWidget* parent = 0 ); + ~AlbumInfoWidget(); + + /** \brief Loads information for a given album. + * \param album The album that you want to load information for. + * + * Calling this method will make AlbumInfoWidget load information about + * an album, and related other albums. This method will be automatically + * called by the constructor, but you can use it to load another album's + * information at any point. + */ + void load( const Tomahawk::album_ptr& album ); + + virtual QWidget* widget() { return this; } + virtual Tomahawk::PlaylistInterface* playlistInterface() const { return 0; } + + virtual QString title() const { return m_title; } + virtual QString description() const { return m_description; } + virtual QString longDescription() const { return m_longDescription; } + virtual QPixmap pixmap() const { if ( m_pixmap.isNull() ) return Tomahawk::ViewPage::pixmap(); else return m_pixmap; } + + virtual bool isTemporaryPage() const { return true; } + virtual bool showStatsBar() const { return false; } + + virtual bool jumpToCurrentTrack() { return false; } + +signals: + void longDescriptionChanged( const QString& description ); + void descriptionChanged( const QString& description ); + void pixmapChanged( const QPixmap& pixmap ); + +protected: + void changeEvent( QEvent* e ); + +private slots: + void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); + void infoSystemFinished( QString target ); + +private: + Ui::AlbumInfoWidget *ui; + + Tomahawk::album_ptr m_album; + + AlbumModel* m_albumsModel; + TreeModel* m_tracksModel; + + QString m_title; + QString m_description; + QString m_longDescription; + QPixmap m_pixmap; +}; + +#endif // ALBUMINFOWIDGET_H diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui new file mode 100644 index 000000000..c06d89099 --- /dev/null +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.ui @@ -0,0 +1,55 @@ + + + AlbumInfoWidget + + + + 0 + 0 + 902 + 696 + + + + Form + + + + + + + + + + + Other Albums by Artist + + + + + + + + + + + + + HeaderLabel + QLabel +
widgets/HeaderLabel.h
+
+ + ArtistView + QTreeView +
artistview.h
+
+ + AlbumView + QListView +
playlist/albumview.h
+
+
+ + +
diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 39e41710c..e911033e6 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -59,6 +59,8 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* m_relatedModel = new TreeModel( ui->relatedArtists ); ui->relatedArtists->setTreeModel( m_relatedModel ); + ui->relatedArtists->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + ui->relatedArtists->header()->setVisible( false ); m_topHitsModel = new PlaylistModel( ui->topHits ); m_topHitsModel->setStyle( TrackModel::Short ); @@ -72,12 +74,10 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) ); - // Apparently headers can only be removed when it's already visible / layed-out - QTimer::singleShot( 0, this ,SLOT( removeHeaders() ) ); - load( artist ); } + ArtistInfoWidget::~ArtistInfoWidget() { delete ui; @@ -125,7 +125,6 @@ ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestD // qDebug() << "Info of wrong type or not with our identifier"; return; } - qDebug() << Q_FUNC_INFO << requestData.caller << requestData.type << s_aiInfoIdentifier; InfoSystem::InfoCriteriaHash trackInfo; trackInfo = requestData.input.value< InfoSystem::InfoCriteriaHash >(); @@ -207,7 +206,6 @@ void ArtistInfoWidget::infoSystemFinished( QString target ) { Q_UNUSED( target ); - qDebug() << Q_FUNC_INFO; } @@ -225,10 +223,3 @@ ArtistInfoWidget::changeEvent( QEvent* e ) break; } } - -void -ArtistInfoWidget::removeHeaders() -{ - for ( int i = 1; i < ui->relatedArtists->header()->count(); i++ ) - ui->relatedArtists->header()->hideSection( ui->relatedArtists->header()->logicalIndex( i ) ); -} diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h index 176adae95..155a3f2f7 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.h @@ -90,7 +90,6 @@ private slots: void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output ); void infoSystemFinished( QString target ); - void removeHeaders(); private: Ui::ArtistInfoWidget *ui; @@ -106,4 +105,4 @@ private: QPixmap m_pixmap; }; -#endif // SOURCEINFOWIDGET_H +#endif // ARTISTINFOWIDGET_H diff --git a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.ui b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.ui index bde48ccbc..42edd0331 100644 --- a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.ui +++ b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.ui @@ -51,7 +51,7 @@ - Latest Additions to their Collection + Latest Additions @@ -65,7 +65,7 @@ - Recently played Tracks + Recently Played Tracks diff --git a/src/libtomahawk/widgets/newplaylistwidget.ui b/src/libtomahawk/widgets/newplaylistwidget.ui index 0e9215b2f..74a6d7956 100644 --- a/src/libtomahawk/widgets/newplaylistwidget.ui +++ b/src/libtomahawk/widgets/newplaylistwidget.ui @@ -6,7 +6,7 @@ 0 0 - 985 + 729 460 @@ -16,11 +16,6 @@ - - - 13 - - Enter a title for the new playlist: @@ -38,11 +33,6 @@ - - - 13 - - Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! @@ -53,14 +43,12 @@ - - - 13 - - Just enter a genre or tag name and Tomahawk will suggest a few songs to get you started with your new playlist: + + true + diff --git a/src/libtomahawk/widgets/searchwidget.cpp b/src/libtomahawk/widgets/searchwidget.cpp index 58b81a7f9..5b253c83a 100644 --- a/src/libtomahawk/widgets/searchwidget.cpp +++ b/src/libtomahawk/widgets/searchwidget.cpp @@ -24,6 +24,7 @@ #include "sourcelist.h" #include "viewmanager.h" +#include "dynamic/widgets/LoadingSpinner.h" #include "playlist/playlistmodel.h" #include "widgets/overlaywidget.h" @@ -48,11 +49,13 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent ) ui->resultsView->setFrameShape( QFrame::NoFrame ); ui->resultsView->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + ui->resultsView->loadingSpinner()->fadeIn(); m_queries << Tomahawk::Query::get( search, uuid() ); foreach ( const Tomahawk::query_ptr& query, m_queries ) { connect( query.data(), SIGNAL( resultsAdded( QList ) ), SLOT( onResultsFound( QList ) ) ); + connect( query.data(), SIGNAL( resolvingFinished( bool ) ), SLOT( onQueryFinished() ) ); } } @@ -91,9 +94,17 @@ SearchWidget::onResultsFound( const QList& results ) rl << result; Tomahawk::query_ptr q = result->toQuery(); + q->setResolveFinished( true ); q->addResults( rl ); qDebug() << result->toString(); m_resultsModel->append( q ); } } + + +void +SearchWidget::onQueryFinished() +{ + ui->resultsView->loadingSpinner()->fadeOut(); +} diff --git a/src/libtomahawk/widgets/searchwidget.h b/src/libtomahawk/widgets/searchwidget.h index f7d7ec021..136be7f11 100644 --- a/src/libtomahawk/widgets/searchwidget.h +++ b/src/libtomahawk/widgets/searchwidget.h @@ -63,6 +63,7 @@ signals: private slots: void onResultsFound( const QList& results ); + void onQueryFinished(); private: Ui::SearchWidget *ui; diff --git a/src/libtomahawk/widgets/welcomeplaylistmodel.cpp b/src/libtomahawk/widgets/welcomeplaylistmodel.cpp index fe855885c..618354562 100644 --- a/src/libtomahawk/widgets/welcomeplaylistmodel.cpp +++ b/src/libtomahawk/widgets/welcomeplaylistmodel.cpp @@ -70,7 +70,13 @@ WelcomePlaylistModel::loadFromSettings() m_recplaylists << pl; if( !m_cached.contains( playlist_guids[i] ) ) + { + if ( pl.dynamicCast< DynamicPlaylist >().isNull() ) + connect( pl.data(), SIGNAL(revisionLoaded(Tomahawk::PlaylistRevision)), this, SLOT(playlistRevisionLoaded()) ); + else + connect( pl.data(), SIGNAL(dynamicRevisionLoaded(Tomahawk::DynamicPlaylistRevision)), this, SLOT(playlistRevisionLoaded()) ); m_cached[playlist_guids[i]] = pl; + } } else m_waitingForSome = true; } @@ -110,21 +116,78 @@ WelcomePlaylistModel::data( const QModelIndex& index, int role ) const return m_artists[pl]; } + case PlaylistTypeRole: + { + if ( !pl.dynamicCast< Tomahawk::DynamicPlaylist >().isNull() ) + { + dynplaylist_ptr dynp = pl.dynamicCast< Tomahawk::DynamicPlaylist >(); + if ( dynp->mode() == Static ) + return AutoPlaylist; + else if ( dynp->mode() == OnDemand ) + return Station; + } else + { + return StaticPlaylist; + } + } + case DynamicPlaylistRole: + { + dynplaylist_ptr dynp = pl.dynamicCast< Tomahawk::DynamicPlaylist >(); + return QVariant::fromValue< Tomahawk::dynplaylist_ptr >( dynp ); + } case TrackCountRole: - return pl->entries().count(); + { + if ( !pl.dynamicCast< Tomahawk::DynamicPlaylist >().isNull() && pl.dynamicCast< Tomahawk::DynamicPlaylist >()->mode() == OnDemand ) + return QString( QChar( 0x221E ) ); + else + return pl->entries().count(); + } default: return QVariant(); } } +void +WelcomePlaylistModel::playlistRevisionLoaded() +{ + Playlist* p = qobject_cast< Playlist* >( sender() ); + Q_ASSERT( p ); + + for ( int i = 0; i < m_recplaylists.size(); i++ ) + { + if ( m_recplaylists[ i ]->guid() == p->guid() ) + { + QModelIndex idx = index( i, 0, QModelIndex() ); + emit dataChanged( idx, idx ); + } + } +} + void WelcomePlaylistModel::onSourceAdded( const Tomahawk::source_ptr& source ) { + connect( source.data(), SIGNAL( online() ), this, SLOT( sourceOnline() ) ); connect( source->collection().data(), SIGNAL( playlistsAdded( QList ) ), SLOT( loadFromSettings() ) ); connect( source->collection().data(), SIGNAL( playlistsDeleted( QList ) ), SLOT( onPlaylistsRemoved( QList ) ) ); } +void +WelcomePlaylistModel::sourceOnline() +{ + Source* s = qobject_cast< Source* >( sender() ); + Q_ASSERT( s ); + + for ( int i = 0; i < m_recplaylists.size(); i++ ) + { + if ( m_recplaylists[ i ]->author().data() == s ) + { + QModelIndex idx = index( i, 0, QModelIndex() ); + emit dataChanged( idx, idx ); + } + } +} + void WelcomePlaylistModel::onPlaylistsRemoved( QList< playlist_ptr > playlists ) diff --git a/src/libtomahawk/widgets/welcomeplaylistmodel.h b/src/libtomahawk/widgets/welcomeplaylistmodel.h index b979dfc95..c30d83ea0 100644 --- a/src/libtomahawk/widgets/welcomeplaylistmodel.h +++ b/src/libtomahawk/widgets/welcomeplaylistmodel.h @@ -30,7 +30,9 @@ class WelcomePlaylistModel : public QAbstractListModel Q_OBJECT public: enum ItemRoles - { ArtistRole = Qt::UserRole, TrackCountRole, PlaylistRole }; + { ArtistRole = Qt::UserRole, TrackCountRole, PlaylistRole, PlaylistTypeRole, DynamicPlaylistRole }; + enum PlaylistTypes + { StaticPlaylist, AutoPlaylist, Station }; explicit WelcomePlaylistModel( QObject* parent = 0 ); @@ -49,6 +51,7 @@ private slots: void loadFromSettings(); void plAdded( const Tomahawk::playlist_ptr& ); + void playlistRevisionLoaded(); private: QList< Tomahawk::playlist_ptr > m_recplaylists; @@ -57,6 +60,8 @@ private: unsigned int m_maxPlaylists; bool m_waitingForSome; + public slots: + void sourceOnline(); }; #endif // WELCOMEPLAYLISTMODEL_H diff --git a/src/libtomahawk/widgets/welcomewidget.cpp b/src/libtomahawk/widgets/welcomewidget.cpp index 5bf94cb74..1316069d2 100644 --- a/src/libtomahawk/widgets/welcomewidget.cpp +++ b/src/libtomahawk/widgets/welcomewidget.cpp @@ -32,9 +32,10 @@ #include "widgets/overlaywidget.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" +#include #define HISTORY_TRACK_ITEMS 25 -#define HISTORY_PLAYLIST_ITEMS 5 +#define HISTORY_PLAYLIST_ITEMS 10 #define HISTORY_RESOLVING_TIMEOUT 2500 using namespace Tomahawk; @@ -70,13 +71,18 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->playlistWidget->setItemDelegate( new PlaylistDelegate() ); ui->playlistWidget->setModel( model ); ui->playlistWidget->overlay()->resize( 380, 86 ); +#ifdef Q_OS_MAC + ui->playlistWidget->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); +#endif connect( model, SIGNAL( emptinessChanged( bool) ), this, SLOT( updatePlaylists() ) ); m_tracksModel = new PlaylistModel( ui->tracksView ); - m_tracksModel->setStyle( TrackModel::Short ); + m_tracksModel->setStyle( TrackModel::ShortWithAvatars ); ui->tracksView->overlay()->setEnabled( false ); ui->tracksView->setPlaylistModel( m_tracksModel ); + ui->tracksView->setHeaderHidden( true ); + ui->tracksView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_recentAlbumsModel = new AlbumModel( ui->additionsView ); ui->additionsView->setAlbumModel( m_recentAlbumsModel ); @@ -189,6 +195,7 @@ WelcomeWidget::changeEvent( QEvent* e ) } } + QSize PlaylistDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { @@ -217,23 +224,82 @@ PlaylistDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, QTextOption to; to.setAlignment( Qt::AlignCenter ); QFont font = opt.font; - QFont boldFont = opt.font; +#ifdef Q_OS_MAC + font.setPointSize( font.pointSize() - 2 ); +#endif + + QFont boldFont = font; boldFont.setBold( true ); - QFont italicFont = opt.font; - italicFont.setItalic( true ); - painter->drawPixmap( option.rect.adjusted( 10, 13, -option.rect.width() + 48, -13 ), m_playlistIcon ); + QPixmap icon; + WelcomePlaylistModel::PlaylistTypes type = (WelcomePlaylistModel::PlaylistTypes)index.data( WelcomePlaylistModel::PlaylistTypeRole ).toInt(); + if( type == WelcomePlaylistModel::StaticPlaylist ) + icon = m_playlistIcon; + else if( type == WelcomePlaylistModel::AutoPlaylist ) + icon = m_autoIcon; + else if( type == WelcomePlaylistModel::Station ) + icon = m_stationIcon; - painter->drawText( option.rect.adjusted( 56, 26, -100, -8 ), index.data( WelcomePlaylistModel::ArtistRole ).toString() ); + QRect pixmapRect = option.rect.adjusted( 10, 13, -option.rect.width() + 48, -13 ); + icon = icon.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); - QString trackCount = tr( "%1 tracks" ).arg( index.data( WelcomePlaylistModel::TrackCountRole ).toString() ); - painter->drawText( option.rect.adjusted( option.rect.width() - 96, 12, 0, -2 - opt.rect.height() / 2 ), trackCount, to ); + painter->drawPixmap( pixmapRect, icon ); - QString author = index.data( WelcomePlaylistModel::PlaylistRole ).value< Tomahawk::playlist_ptr >()->author()->friendlyName(); - QRect r = option.rect.adjusted( option.rect.width() - 96, 2 + opt.rect.height() / 2, 0, -12); - painter->setFont( italicFont ); - author = painter->fontMetrics().elidedText( author, Qt::ElideRight, r.width() ); - painter->drawText( r, author, to ); + QString descText; + if ( type == WelcomePlaylistModel::Station ) + { + descText = index.data( WelcomePlaylistModel::DynamicPlaylistRole ).value< Tomahawk::dynplaylist_ptr >()->generator()->sentenceSummary(); + } else + { + descText = index.data( WelcomePlaylistModel::ArtistRole ).toString(); + } + QColor c = painter->pen().color(); + painter->setPen( QColor( Qt::gray ).darker() ); + QFont font2 = font; +#ifdef Q_OS_MAC + font2.setPointSize( font2.pointSize() - 1 ); +#endif + painter->setFont( font2 ); + + QRect rectText = option.rect.adjusted( 66, 20, -100, -8 ); +#ifdef Q_OS_MAC + rectText.adjust( 0, 1, 0, 0 ); +#elif Q_OS_WIN + rectText.adjust( 0, 2, 0, 0 ); +#endif + + painter->drawText( rectText, descText ); + painter->setPen( c ); + painter->setFont( font ); + + if ( type != WelcomePlaylistModel::Station ) + { + painter->save(); + QString tracks = index.data( WelcomePlaylistModel::TrackCountRole ).toString(); + int width = painter->fontMetrics().width( tracks ); +// int bottomEdge = pixmapRect + // right edge 10px past right edge of pixmapRect + // bottom edge flush with bottom of pixmap + QRect rect( pixmapRect.right() - width , 0, width - 8, 0 ); + rect.adjust( -1, 0, 0, 0 ); + rect.setTop( pixmapRect.bottom() - painter->fontMetrics().height() - 1 ); + rect.setBottom( pixmapRect.bottom() + 1 ); + + QColor figColor( 153, 153, 153 ); + painter->setPen( figColor ); + painter->setBrush( figColor ); + painter->setFont( boldFont ); + + TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, rect ); + painter->restore(); + } + + + QPixmap avatar = index.data( WelcomePlaylistModel::PlaylistRole ).value< Tomahawk::playlist_ptr >()->author()->avatar( Source::FancyStyle ); + if ( avatar.isNull() ) + avatar = m_defaultAvatar; + QRect r( option.rect.width() - avatar.width() - 10, option.rect.top() + option.rect.height()/2 - avatar.height()/2, avatar.width(), avatar.height() ); + painter->drawPixmap( r, avatar ); painter->setFont( boldFont ); painter->drawText( option.rect.adjusted( 56, 6, -100, -option.rect.height() + 20 ), index.data().toString() ); diff --git a/src/libtomahawk/widgets/welcomewidget.h b/src/libtomahawk/widgets/welcomewidget.h index 8889cc76a..6df35c045 100644 --- a/src/libtomahawk/widgets/welcomewidget.h +++ b/src/libtomahawk/widgets/welcomewidget.h @@ -50,6 +50,9 @@ public: PlaylistDelegate() { m_playlistIcon = QPixmap( RESPATH "images/playlist-icon.png" ); + m_autoIcon = QPixmap( RESPATH "images/automatic-playlist.png" ); + m_stationIcon = QPixmap( RESPATH "images/station.png" ); + m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) ); } protected: @@ -57,7 +60,7 @@ protected: QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; private: - QPixmap m_playlistIcon; + QPixmap m_playlistIcon, m_autoIcon, m_stationIcon, m_defaultAvatar; }; class DLLEXPORT PlaylistWidget : public QListView diff --git a/src/sip/jabber/jabber.cpp b/src/sip/jabber/jabber.cpp index 6cc138aa2..9434dc1b4 100644 --- a/src/sip/jabber/jabber.cpp +++ b/src/sip/jabber/jabber.cpp @@ -325,6 +325,12 @@ JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason ) } } +void +JabberPlugin::onError( const Jreen::Connection::SocketError& e ) +{ + tLog() << "JABBER error:" << e; +} + QString JabberPlugin::errorMessage( Jreen::Client::DisconnectReason reason ) { diff --git a/src/sip/jabber/jabber.h b/src/sip/jabber/jabber.h index 1d12bb7de..101ac5c15 100644 --- a/src/sip/jabber/jabber.h +++ b/src/sip/jabber/jabber.h @@ -111,10 +111,7 @@ private slots: void onSubscriptionRequestConfirmed( int result ); void onNewMessage( const Jreen::Message& message ); - void onError( const Jreen::Connection::SocketError& e ) - { - qDebug() << e; - } + void onError( const Jreen::Connection::SocketError& e ); void onNewIq( const Jreen::IQ &iq ); void onNewAvatar( const QString &jid ); void onCheckJidExists( QString jid ); diff --git a/src/sourcetree/items/collectionitem.cpp b/src/sourcetree/items/collectionitem.cpp index 84abafbcd..644498940 100644 --- a/src/sourcetree/items/collectionitem.cpp +++ b/src/sourcetree/items/collectionitem.cpp @@ -1,4 +1,6 @@ /* + * Copyright 2010-2011, Leo Franchi + * * 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 @@ -56,7 +58,7 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons connect( ViewManager::instance(), SIGNAL( tempPageActivated( Tomahawk::ViewPage*) ), this, SLOT( tempPageActivated( Tomahawk::ViewPage* ) ) ); // add misc children of root node - GenericPageItem* recent = new GenericPageItem( model(), this, tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ), + GenericPageItem* recent = new GenericPageItem( model(), this, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ), boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ), boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) ); @@ -69,6 +71,7 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons // ); // m_coolPlaylistsItem->setSortValue( 200 ); + m_superCol = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/supercollection.png" ) ); return; } @@ -99,6 +102,8 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons if( ViewManager::instance()->pageForCollection( source->collection() ) ) model()->linkSourceItemToPage( this, ViewManager::instance()->pageForCollection( source->collection() ) ); + m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) ); + // load auto playlists and stations! connect( source.data(), SIGNAL( stats( QVariantMap ) ), this, SIGNAL( updated() ) ); @@ -114,6 +119,9 @@ CollectionItem::CollectionItem( SourcesModel* mdl, SourceTreeItem* parent, cons SLOT( onAutoPlaylistsAdded( QList ) ), Qt::QueuedConnection ); connect( source->collection().data(), SIGNAL( stationsAdded( QList ) ), SLOT( onStationsAdded( QList ) ), Qt::QueuedConnection ); + + if ( m_source->isLocal() ) + QTimer::singleShot(0, this, SLOT(requestExpanding())); } @@ -160,13 +168,13 @@ QIcon CollectionItem::icon() const { if( m_source.isNull() ) - return QIcon( RESPATH "images/supercollection.png" ); + return m_superCol; else { if( m_source->avatar().isNull() ) - return QIcon( RESPATH "images/user-avatar.png" ); + return m_defaultAvatar; else - return QIcon( m_source->avatar() ); + return m_source->avatar( Source::FancyStyle ); } } @@ -341,6 +349,13 @@ CollectionItem::onStationDeleted( const dynplaylist_ptr& station ) } +void +CollectionItem::requestExpanding() +{ + emit expandRequest(this); +} + + void CollectionItem::tempPageActivated( Tomahawk::ViewPage* v ) { diff --git a/src/sourcetree/items/collectionitem.h b/src/sourcetree/items/collectionitem.h index b92a75e47..5b1f0341e 100644 --- a/src/sourcetree/items/collectionitem.h +++ b/src/sourcetree/items/collectionitem.h @@ -1,4 +1,6 @@ /* + * Copyright 2010-2011, Leo Franchi + * * 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 @@ -51,6 +53,8 @@ private slots: void onStationsAdded( const QList& stations ); void onStationDeleted( const Tomahawk::dynplaylist_ptr& stations ); + void requestExpanding(); + void tempPageActivated( Tomahawk::ViewPage* ); Tomahawk::ViewPage* tempItemClicked(); Tomahawk::ViewPage* getTempPage() const; @@ -70,6 +74,7 @@ private: void playlistDeletedInternal( SourceTreeItem* parent, const T& playlists ); Tomahawk::source_ptr m_source; + QPixmap m_superCol, m_defaultAvatar; CategoryItem* m_playlists; CategoryItem* m_stations; diff --git a/src/sourcetree/items/genericpageitems.cpp b/src/sourcetree/items/genericpageitems.cpp index c37a6aa67..86211dea7 100644 --- a/src/sourcetree/items/genericpageitems.cpp +++ b/src/sourcetree/items/genericpageitems.cpp @@ -1,4 +1,6 @@ /* + * Copyright 2010-2011, Leo Franchi + * * 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 diff --git a/src/sourcetree/items/genericpageitems.h b/src/sourcetree/items/genericpageitems.h index 378224bb1..2b2609ea9 100644 --- a/src/sourcetree/items/genericpageitems.h +++ b/src/sourcetree/items/genericpageitems.h @@ -1,4 +1,6 @@ /* + * Copyright 2010-2011, Leo Franchi + * * 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 diff --git a/src/sourcetree/items/playlistitems.cpp b/src/sourcetree/items/playlistitems.cpp index 2146c9f37..ee7976892 100644 --- a/src/sourcetree/items/playlistitems.cpp +++ b/src/sourcetree/items/playlistitems.cpp @@ -1,4 +1,7 @@ /* + * + * Copyright 2010-2011, Leo Franchi + * * 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 diff --git a/src/sourcetree/items/playlistitems.h b/src/sourcetree/items/playlistitems.h index 1c3e9d463..7ae0d8a96 100644 --- a/src/sourcetree/items/playlistitems.h +++ b/src/sourcetree/items/playlistitems.h @@ -1,4 +1,6 @@ /* + * Copyright 2010-2011, Leo Franchi + * * 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 diff --git a/src/sourcetree/items/sourcetreeitem.cpp b/src/sourcetree/items/sourcetreeitem.cpp index c15c33047..5f82833c3 100644 --- a/src/sourcetree/items/sourcetreeitem.cpp +++ b/src/sourcetree/items/sourcetreeitem.cpp @@ -1,4 +1,6 @@ /* + Copyright 2010-2011, Leo Franchi + 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 @@ -33,6 +35,7 @@ SourceTreeItem::SourceTreeItem( SourcesModel* model, SourceTreeItem* parent, Sou connect( this, SIGNAL( childRowsRemoved() ), m_model, SLOT( onItemRowsRemovedDone() ) ); connect( this, SIGNAL( updated() ), m_model, SLOT( itemUpdated() ) ); connect( this, SIGNAL( selectRequest( SourceTreeItem* ) ), m_model, SLOT( itemSelectRequest( SourceTreeItem* ) ) ); + connect( this, SIGNAL( expandRequest( SourceTreeItem* ) ), m_model, SLOT( itemExpandRequest( SourceTreeItem* ) ) ); if( !m_parent ) return; diff --git a/src/sourcetree/items/sourcetreeitem.h b/src/sourcetree/items/sourcetreeitem.h index 57553988e..b8b971172 100644 --- a/src/sourcetree/items/sourcetreeitem.h +++ b/src/sourcetree/items/sourcetreeitem.h @@ -1,4 +1,6 @@ /* + Copyright 2010-2011, Leo Franchi + 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 @@ -63,6 +65,7 @@ public: signals: void updated(); void selectRequest( SourceTreeItem* ); + void expandRequest( SourceTreeItem* ); void beginChildRowsAdded( int fromRow, int toRow ); void childRowsAdded(); diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index 7330c53c1..8c99f5702 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -493,3 +493,10 @@ SourcesModel::itemSelectRequest( SourceTreeItem* item ) { emit selectRequest( indexFromItem( item ) ); } + +void +SourcesModel::itemExpandRequest( SourceTreeItem *item ) +{ + qDebug() << "expanding source" << indexFromItem( item ) << item; + emit expandRequest( indexFromItem( item ) ); +} diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h index 94ca4008c..cfcb62776 100644 --- a/src/sourcetree/sourcesmodel.h +++ b/src/sourcetree/sourcesmodel.h @@ -102,8 +102,11 @@ public slots: void viewPageActivated( Tomahawk::ViewPage* ); void itemSelectRequest( SourceTreeItem* item ); + void itemExpandRequest( SourceTreeItem* item ); + signals: void selectRequest( const QModelIndex& idx ); + void expandRequest( const QModelIndex& idx ); private slots: void onSourcesAdded( const QList& sources ); diff --git a/src/sourcetree/sourcesproxymodel.cpp b/src/sourcetree/sourcesproxymodel.cpp index 6fe6c3bcb..b449455cc 100644 --- a/src/sourcetree/sourcesproxymodel.cpp +++ b/src/sourcetree/sourcesproxymodel.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,8 +37,8 @@ SourcesProxyModel::SourcesProxyModel( SourcesModel* model, QObject* parent ) setSourceModel( model ); - if ( model && model->metaObject()->indexOfSignal( "trackCountChanged(QModelIndex)" ) > -1 ) - connect( model, SIGNAL( askForExpand( QModelIndex ) ), this, SLOT( askedToExpand( QModelIndex ) ) ); + if ( model && model->metaObject()->indexOfSignal( "expandRequest(QModelIndex)" ) > -1 ) + connect( model, SIGNAL( expandRequest( QModelIndex ) ), this, SLOT( expandRequested( QModelIndex ) ) ); if ( model && model->metaObject()->indexOfSignal( "selectRequest(QModelIndex)" ) > -1 ) connect( model, SIGNAL( selectRequest( QModelIndex ) ), this, SLOT( selectRequested( QModelIndex ) ) ); } @@ -73,6 +73,14 @@ SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePar void SourcesProxyModel::selectRequested( const QModelIndex& idx ) { + qDebug() << "selectRequested for idx" << idx << idx.data(Qt::DisplayRole).toString() << mapFromSource( idx ); emit selectRequest( mapFromSource( idx ) ); } +void +SourcesProxyModel::expandRequested( const QModelIndex& idx ) +{ + qDebug() << "emitting expand for idx" << idx << idx.data(Qt::DisplayRole).toString() << mapFromSource( idx ); + emit expandRequest( mapFromSource( idx ) ); +} + diff --git a/src/sourcetree/sourcesproxymodel.h b/src/sourcetree/sourcesproxymodel.h index 4599d8c5c..57917d815 100644 --- a/src/sourcetree/sourcesproxymodel.h +++ b/src/sourcetree/sourcesproxymodel.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,9 +34,11 @@ public slots: void showOfflineSources( bool offlineSourcesShown ); void selectRequested( const QModelIndex& ); + void expandRequested( const QModelIndex& ); signals: void selectRequest( const QModelIndex& idx ); + void expandRequest( const QModelIndex& idx ); protected: bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const; diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index b7f4226d9..0652da1fd 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -108,6 +108,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) m_model = new SourcesModel( this ); m_proxyModel = new SourcesProxyModel( m_model, this ); connect( m_proxyModel, SIGNAL( selectRequest( QModelIndex ) ), this, SLOT( selectRequest( QModelIndex ) ), Qt::QueuedConnection ); + connect( m_proxyModel, SIGNAL( expandRequest( QModelIndex ) ), this, SLOT( expandRequest( QModelIndex ) ), Qt::QueuedConnection ); setModel( m_proxyModel ); @@ -246,6 +247,13 @@ SourceTreeView::selectRequest( const QModelIndex& idx ) } } +void +SourceTreeView::expandRequest( const QModelIndex &idx ) +{ + qDebug() << "Expanding idx" << idx; + expand( idx ); +} + void SourceTreeView::loadPlaylist() @@ -665,34 +673,19 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co { painter->setRenderHint( QPainter::Antialiasing ); - QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 18, 0, -10, -o.rect.height() + 16 ); + QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 8, 0, -13, -o.rect.height() + 16 ); int hd = ( option.rect.height() - figRect.height() ) / 2; figRect.adjust( 0, hd, 0, hd ); +#ifdef Q_OS_WIN + figRect.adjust( -3, 0, 3, 0 ); +#endif + painter->setFont( bold ); QColor figColor( 167, 183, 211 ); painter->setPen( figColor ); painter->setBrush( figColor ); - QPen origpen = painter->pen(); - QPen pen = origpen; - pen.setWidth( 1.0 ); - painter->setPen( pen ); - painter->drawRect( figRect ); - - QPainterPath ppath; - ppath.moveTo( QPoint( figRect.x(), figRect.y() ) ); - ppath.quadTo( QPoint( figRect.x() - 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x(), figRect.y() + figRect.height() ) ); - painter->drawPath( ppath ); - ppath.moveTo( QPoint( figRect.x() + figRect.width(), figRect.y() ) ); - ppath.quadTo( QPoint( figRect.x() + figRect.width() + 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x() + figRect.width(), figRect.y() + figRect.height() ) ); - painter->drawPath( ppath ); - - painter->setPen( origpen ); - - QTextOption to( Qt::AlignCenter ); - painter->setFont( bold ); - painter->setPen( Qt::white ); - painter->drawText( figRect, tracks, to ); + TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, figRect ); } painter->restore(); diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index 0e62deab6..15c8276f9 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -49,6 +49,7 @@ private slots: void onItemExpanded( const QModelIndex& idx ); void onItemActivated( const QModelIndex& index ); void selectRequest( const QModelIndex& idx ); + void expandRequest( const QModelIndex& idx ); void loadPlaylist(); void deletePlaylist( const QModelIndex& = QModelIndex() ); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 3fade3256..be2a680eb 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -124,6 +124,12 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) void TomahawkApp::init() { + if ( arguments().contains( "--help" ) || arguments().contains( "-h" ) ) + { + printHelp(); + ::exit(0); + } + Logger::setupLogfile(); qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) ); @@ -241,6 +247,11 @@ TomahawkApp::init() tDebug() << "Init Scrobbler."; m_scrobbler = new Scrobbler( this ); #endif + + if ( arguments().contains( "--filescan" ) ) + { + m_scanManager.data()->runScan( true ); + } } @@ -292,6 +303,20 @@ TomahawkApp::instance() return (TomahawkApp*)TOMAHAWK_APPLICATION::instance(); } +void +TomahawkApp::printHelp() +{ + std::cout << QString( "usage: " + arguments().at( 0 ) + " [options] [url]\n" ).toAscii().data(); + std::cout << QString( "options are:\n" ).toAscii().data(); + std::cout << QString( " --help Show this help\n" ).toAscii().data(); + std::cout << QString( " --http Initialize HTTP server\n" ).toAscii().data(); + std::cout << QString( " --filescan Scan for files on startup\n" ).toAscii().data(); + std::cout << QString( " --testdb Use a test database instead of real collection\n" ).toAscii().data(); + std::cout << QString( " --noupnp Disable UPNP\n" ).toAscii().data(); + std::cout << QString( " --nosip Disable SIP\n" ).toAscii().data(); + std::cout << QString( "\nurl is a tomahawk:// command or alternatively a url that Tomahawk can recognize.\n" ).toAscii().data(); + std::cout << QString( "For more documentation, see http://wiki.tomahawk-player.org/mediawiki/index.php/Tomahawk://_Links\n" ).toAscii().data(); +} #ifndef TOMAHAWK_HEADLESS AudioControls* @@ -520,6 +545,8 @@ TomahawkApp::loadUrl( const QString& url ) return GlobalActionManager::instance()->parseTomahawkLink( url ); else if ( url.contains( "open.spotify.com" ) || url.contains( "spotify:track" ) ) return GlobalActionManager::instance()->openSpotifyLink( url ); + else if ( url.contains( "www.rdio.com" ) ) + return GlobalActionManager::instance()->openRdioLink( url ); else { QFile f( url ); diff --git a/src/tomahawkapp.h b/src/tomahawkapp.h index ea13702e7..9e36f802b 100644 --- a/src/tomahawkapp.h +++ b/src/tomahawkapp.h @@ -108,6 +108,8 @@ private slots: private: void registerMetaTypes(); + void printHelp(); + // Start-up order: database, collection, pipeline, servent, http void initDatabase(); void initLocalCollection(); diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index c6e7fcc7b..13dba067d 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -93,6 +93,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) ui->centralWidget->setContentsMargins( 0, 0, 0, 0 ); ui->centralWidget->layout()->setContentsMargins( 0, 0, 0, 0 ); ui->centralWidget->layout()->setMargin( 0 ); + ui->centralWidget->layout()->setSpacing( 0 ); setupSideBar(); setupToolBar(); @@ -174,6 +175,16 @@ TomahawkWindow::applyPlatformTweaks() #ifdef Q_WS_MAC setUnifiedTitleAndToolBarOnMac( true ); #endif + +#ifdef Q_OS_MAC + ui->hline1->setMaximumHeight( 0 ); + ui->hline2->setMaximumHeight( 0 ); + ui->hline1->hide(); + ui->hline2->hide(); +#else + ui->hline1->setStyleSheet( "border: 1px solid gray;" ); + ui->hline2->setStyleSheet( "border: 1px solid gray;" ); +#endif } diff --git a/src/tomahawkwindow.ui b/src/tomahawkwindow.ui index dad448a42..c9fde85c0 100644 --- a/src/tomahawkwindow.ui +++ b/src/tomahawkwindow.ui @@ -15,6 +15,22 @@ + + + + + 16777215 + 1 + + + + QFrame::HLine + + + QFrame::Raised + + + @@ -27,6 +43,22 @@ + + + + + 16777215 + 1 + + + + QFrame::HLine + + + QFrame::Raised + + + @@ -35,7 +67,7 @@ 0 0 1000 - 22 + 20 diff --git a/src/transferview.cpp b/src/transferview.cpp index 688bdc928..77a886d63 100644 --- a/src/transferview.cpp +++ b/src/transferview.cpp @@ -47,6 +47,7 @@ TransferView::TransferView( AnimatedSplitter* parent ) headers << tr( "Peer" ) << tr( "Rate" ) << tr( "Track" ); m_tree->setHeaderLabels( headers ); + m_tree->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_tree->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); m_tree->setColumnCount( 3 ); m_tree->setColumnWidth( 0, 80 ); @@ -58,6 +59,17 @@ TransferView::TransferView( AnimatedSplitter* parent ) m_tree->setFrameShape( QFrame::NoFrame ); m_tree->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + +#ifndef Q_WS_WIN + QFont f = font(); + f.setPointSize( f.pointSize() - 1 ); + setFont( f ); +#endif + +#ifdef Q_WS_MAC + f.setPointSize( f.pointSize() - 2 ); + setFont( f ); +#endif }