diff --git a/ChangeLog b/ChangeLog index d7433e89b..cb01d412d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +Version 0.4.1: + Version 0.4.0: * Added visual notification for database indexing job. * Fixed icons not appearing in resolvers list. diff --git a/data/icons/tomahawk-icon-128x128-grayscale.png b/data/icons/tomahawk-icon-128x128-grayscale.png new file mode 100644 index 000000000..550781596 Binary files /dev/null and b/data/icons/tomahawk-icon-128x128-grayscale.png differ diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 061841a3e..e339dfadd 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -1,6 +1,42 @@ + + AccountFactoryWrapper + + + Dialog + + + + + Description goes here + + + + + Add Account + + + + + AccountFactoryWrapperDelegate + + + Online + + + + + Connecting... + + + + + Offline + + + ActionCollection @@ -14,54 +50,59 @@ - - + + &Follow in real-time + + + + + &Listen Privately - - + + &Listen Publicly - + &Load Playlist - + &Rename Playlist - + &Copy Playlist Link - + &Play - + &Stop - + &Previous Track - + &Next Track - + &Quit @@ -78,31 +119,31 @@ Other Albums by Artist - - - - Click to show Super Collection Tracks - - - + Click to show Official Tracks - - - Click to show Super Collection Albums + + + Click to show SuperCollection Tracks - + + + Click to show SuperCollection Albums + + + + Click to show Official Albums - + Other Albums by %1 @@ -110,18 +151,18 @@ AlbumModel - + Album - - + + All albums from %1 - + All albums @@ -129,12 +170,12 @@ AlbumView - + After you have scanned your music collection you will find your latest album additions right here. - + This collection doesn't have any recent albums. @@ -162,13 +203,13 @@ - - - Click to show Super Collection Albums + + + Click to show SuperCollection Albums - + Click to show Official Albums @@ -176,17 +217,17 @@ ArtistView - + After you have scanned your music collection you will find your tracks right here. - + This collection is currently empty. - + Sorry, your filter '%1' did not match any results. @@ -239,27 +280,27 @@ - + Time Left - + Shuffle - + Repeat - + Low - + High @@ -267,41 +308,41 @@ AudioEngine - + Tomahawk is stopped. - + Tomahawk is playing "%1" by %2%3. - - on album %1 + + on album %1 CategoryAddItem - - + + New Playlist - - - - + + + + New Station - - - + + + %1 Station @@ -309,12 +350,12 @@ CategoryItem - + Playlists - + Stations @@ -340,43 +381,10 @@ - - CollectionItem - - - Top Loved Tracks - - - - - Loved Tracks - - - - - Dashboard - - - - - Charts - - - - - New Additions - - - - - Super Collection - - - CollectionView - + This collection is empty. @@ -452,6 +460,14 @@ + + DelegateConfigWrapper + + + Delete Account + + + DiagnosticsDialog @@ -471,60 +487,10 @@ - GetNewStuffDelegate + DropJob - - Installed - - - - - - Installing - - - - - - Failed - - - - - Uninstalling - - - - - Install - - - - - Upgrading - - - - - Uninstall - - - - - Upgrade - - - - - %1 downloads - - - - - GetNewStuffDialog - - - Download New Resolvers + + No tracks found for given %1 @@ -537,30 +503,10 @@ - GoogleWrapper + IndexingJobItem - - Configure this Google Account - - - - - Google Address - - - - - Enter your Google login to connect with your friends using Tomahawk! - - - - - Add Friend - - - - - Enter Google Address: + + Indexing database @@ -582,152 +528,6 @@ - - JabberConfig - - - Jabber Configuration - - - - - Configure this Jabber account - - - - - Enter your Jabber login to connect with your friends using Tomahawk! - - - - - Login Information - - - - - Jabber ID: - - - - - e.g. user@example.com - - - - - Password: - - - - - An account with this name already exists! - - - - - Advanced Jabber Settings - - - - - Server: - - - - - Port: - - - - - JabberPlugin - - - User Interaction - - - - - Host is unknown - - - - - Item not found - - - - - Authorization Error - - - - - Remote Stream Error - - - - - Remote Connection failed - - - - - Internal Server Error - - - - - System shutdown - - - - - Conflict - - - - - Unknown - - - - - Add Friend - - - - - Enter Jabber ID: - - - - - Add Friend... - - - - - XML Console... - - - - - I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! - - - - - Authorize User - - - - - Do you want to grant <b>%1</b> access to your Collection? - - - JobStatusView @@ -746,6 +546,34 @@ + + LastFmConfig + + + Form + + + + + Scrobble tracks to Last.fm + + + + + Username: + + + + + Password: + + + + + Test Login + + + LastfmContext @@ -847,12 +675,25 @@ PlaylistItemDelegate - + played %1 by you - + + played %1 by %2 + + + + + PlaylistLargeItemDelegate + + + played %1 by you + + + + played %1 by %2 @@ -870,12 +711,12 @@ - + All tracks by %1 on album %2 - + All tracks by %1 @@ -921,7 +762,7 @@ PlaylistView - + This playlist is currently empty. Add some tracks to it and enjoy the music! @@ -975,16 +816,17 @@ - No Proxy Hosts: + No Proxy Hosts: +(Overrides system proxy) - + localhost *.example.com (space separated) - + Use proxy for DNS lookups? @@ -992,7 +834,7 @@ QObject - + %n year(s) ago %n year ago @@ -1000,7 +842,7 @@ - + %n year(s) %n year @@ -1008,7 +850,7 @@ - + %n month(s) ago %n month ago @@ -1016,7 +858,7 @@ - + %n month(s) %n month @@ -1024,7 +866,7 @@ - + %n week(s) ago %n week ago @@ -1032,7 +874,7 @@ - + %n week(s) %n week @@ -1040,7 +882,7 @@ - + %n day(s) ago %n day ago @@ -1048,7 +890,7 @@ - + %n day(s) %n day @@ -1056,7 +898,7 @@ - + %n hour(s) ago %n hour ago @@ -1064,7 +906,7 @@ - + %n hour(s) %n hour @@ -1072,20 +914,35 @@ - + %1 minutes ago - + %1 minutes - + just now + + + Friend Finders + + + + + Music Finders + + + + + Status Updaters + + QuaZipFilePrivate @@ -1104,10 +961,6 @@ - Open Queue - - - Show Queue @@ -1150,12 +1003,12 @@ SearchWidget - + Search: %1 - + Results for '%1' @@ -1163,118 +1016,41 @@ SettingsDialog - - Accounts - - - - + Collection - - Last.fm - - - - - Resolvers - - - - + Advanced - - - Failed + + All - - Success + + Services - - Could not contact server + + Install resolver from file - - Load script resolver file - - - - - Delete Account - - - - + Information - + Changing this setting requires a restart of Tomahawk! - - SipConfigDelegate - - - Online - - - - - Connecting... - - - - - Offline - - - - - SipHandler - - - Legal Warning - - - - - By pressing I Agree below, you agree that your use of Tomahawk will be in accordance with any applicable laws, including copyright and intellectual property laws, in effect in your country of residence, and indemnify the Tomahawk developers and project from liability should you choose to break those laws. - -For more information, please see http://gettomahawk.com/legal - - - - - I Do Not Agree - - - - - I Agree - - - - - SipModel - - - Add New Account... - - - SocialPlaylistWidget @@ -1321,20 +1097,32 @@ For more information, please see http://gettomahawk.com/legal - + Offline - + All available tracks - + Online + + + + Show + + + + + + Hide + + SourceInfoWidget @@ -1354,45 +1142,73 @@ For more information, please see http://gettomahawk.com/legal - + New Additions - + My recent activity - + Recent activity from %1 + + SourceItem + + + Collection + + + + + Latest Additions + + + + + Recently Played + + + + + Loved Tracks + + + + + SuperCollection + + + SourceTreeView - + &Copy Link - + &Delete %1 - + &Export Playlist - + Save XSPF - + Playlists (*.xspf) @@ -1400,25 +1216,113 @@ For more information, please see http://gettomahawk.com/legal SourcesModel - + + Group + + + + Collection - + Playlist - + Automatic Playlist - + Station + + + Browse + + + + + Search History + + + + + My Music + + + + + SuperCollection + + + + + Top Loved Tracks + + + + + Dashboard + + + + + Charts + + + + + Friends + + + + + SpotifyConfig + + + Form + + + + + Configure your Spotify credentials + + + + + Username: + + + + + placeholderUsername + + + + + Password: + + + + + placeholderPw + + + + + High Quality Streaming + + + + + This product uses SPOTIFY(R) CORE but is not endorsed, certified or otherwise approved in any way by Spotify. Spotify is the registered trade mark of the Spotify Group. + + StackedSettingsDialog @@ -1428,33 +1332,17 @@ For more information, please see http://gettomahawk.com/legal - - Accounts - - - - - Connect to your friends with Google Chat, Twitter, and more. - - - - - - ... - - - - + Local Music Information - + Path to scan for music files: - + The Echo Nest supports keeping track of your catalog metadata and using it to craft personalized radios. Enabling this option will allow you (and all your friends) to create automatic playlists @@ -1462,144 +1350,390 @@ For more information, please see http://gettomahawk.com/legal - + Upload collection list to The Echo Nest to enable user radio - + Watch for changes - + Time between scans, in seconds: - - Now Playing Information + + Internet Services - - Applications to update with currently playing track: + + Install from file... - - Adium + + Filter by capability: - - Scrobble tracks to Last.fm - - - - - Username: - - - - - Password: - - - - - Test Login - - - - - Script Resolvers - - - - - Script resolvers search for a given track to make it playable. - - - - - Get more resolvers... - - - - + Advanced Network Settings - + If you're having difficulty connecting to peers, try setting this to your external IP address/host name and a port number (default 50210). Make sure to forward that port to this machine! - + Static Host Name: - + Static Port: - + Always use static host name/port? (Overrides UPnP discovery/port forwarding) - + Proxy Settings... - + Send reports after Tomahawk crashed - + Playdar HTTP API - + Use UPnP to establish port forward + + Tomahawk::Accounts::AccountDelegate + + + Add Account + + + + + Remove Account + + + + + %1 downloads + + + + + Online + + + + + Connecting... + + + + + Offline + + + + + Tomahawk::Accounts::GoogleWrapper + + + Configure this Google Account + + + + + Google Address + + + + + Enter your Google login to connect with your friends using Tomahawk! + + + + + username@gmail.com + + + + + Tomahawk::Accounts::GoogleWrapperFactory + + + Connect to Google Talk to find your friends + + + + + Tomahawk::Accounts::GoogleWrapperSip + + + Add Friend + + + + + Enter Google Address: + + + + + Tomahawk::Accounts::LastFmAccountFactory + + + Scrobble your tracks to last.fm, and find freely downloadable tracks to play + + + + + Tomahawk::Accounts::LastFmConfig + + + + Failed + + + + + Success + + + + + Could not contact server + + + + + Tomahawk::Accounts::SpotifyAccountFactory + + + Play music from and sync your playlists with Spotify + + + + + Tomahawk::Accounts::TwitterAccountFactory + + + Connect to your Twitter followers. + + + + + Tomahawk::Accounts::TwitterConfigWidget + + + + + Tweet! + + + + + + Status: No saved credentials + + + + + + + Authenticate + + + + + + Status: Credentials saved for %1 + + + + + + De-authenticate + + + + + + + + + + + Tweetin' Error + + + + + The credentials could not be verified. +You may wish to try re-authenticating. + + + + + Status: Error validating credentials + + + + + Global Tweet + + + + + Direct Message + + + + + Send Message! + + + + + @Mention + + + + + Send Mention! + + + + + You must enter a user name for this type of tweet. + + + + + Your saved credentials could not be loaded. +You may wish to try re-authenticating. + + + + + Your saved credentials could not be verified. +You may wish to try re-authenticating. + + + + + + There was an error posting your status -- sorry! + + + + + + Tweeted! + + + + + Your tweet has been posted! + + + + + There was an error posting your direct message -- sorry! + + + + + Your message has been posted! + + + + + Tomahawk::Accounts::XmppAccountFactory + + + Log on to your Jabber/XMPP account to connect to your friends + + + + + Tomahawk::Accounts::ZeroconfFactory + + + Automatically connect to Tomahawks on the local network + + + Tomahawk::ContextMenu - - - + &Play - - - + + + Add to &Queue - - Copy Track &Link + + + &Love - + + &Copy Track Link + + + + + Show &Album page + + + + + Show &Artist page + + + + + Un-&Love + + + + &Delete Items - + &Delete Item @@ -1607,32 +1741,32 @@ For more information, please see http://gettomahawk.com/legal Tomahawk::CustomPlaylistView - + Top Loved Tracks - + Your loved tracks - + %1's loved tracks - + The most loved tracks from all your friends - + All of your loved tracks - + All of %1's loved tracks @@ -1661,15 +1795,15 @@ For more information, please see http://gettomahawk.com/legal Tomahawk::DynamicModel - - + + Could not find a playable track. Please change the filters or try again. - + Failed to generate preview with the desired filters @@ -1705,269 +1839,279 @@ Please change the filters or try again. + + Tomahawk::DynamicWidget + + + Station ran out of tracks! + +Try tweaking the filters for a new set of songs to play. + + + Tomahawk::EchonestControl - - - - - - + + + + + + is - + from user - - + + No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings - + similar to - - - - - - - + + + + + + + Less - - - - - - - + + + + + + + More - + 0 BPM - + 500 BPM - + 0 secs - + 3600 secs - + -100 dB - + 100 dB - + Major - + Minor - + C - + C Sharp - + D - + E Flat - + E - + F - + F Sharp - + G - + A Flat - + A - + B Flat - + B - + Ascending - + Descending - + Tempo - + Duration - + Loudness - + Artist Familiarity - + Artist Hotttnesss - + Song Hotttnesss - + Latitude - + Longitude - + Mode - + Key - + Energy - + Danceability - + only by ~%1 - + similar to ~%1 - + with genre ~%1 - - + + from no one - + My Collection - + from %1 radio - + with %1 %2 - + about %1 BPM - + about %n minute(s) long about %n minute long @@ -1975,37 +2119,37 @@ Please change the filters or try again. - + about %1 dB - + at around %1%2 %3 - + in %1 - + in a %1 key - + sorted in %1 %2 order - + with a %1 mood - + in a %1 style @@ -2108,25 +2252,33 @@ Please change the filters or try again. + + Tomahawk::GroovesharkParser + + + Error fetching Grooveshark information from the network! + + + Tomahawk::InfoSystem::ChartsPlugin - + Top Overall - + Artists - + Albums - + Tracks @@ -2134,31 +2286,39 @@ Please change the filters or try again. Tomahawk::InfoSystem::LastFmPlugin - + Top Tracks - + Loved Tracks - + Hyped Tracks - + Top Artists - + Hyped Artists + + Tomahawk::ItunesParser + + + Error fetching iTunes information from the network! + + + Tomahawk::JSPFLoader @@ -2195,50 +2355,122 @@ Please change the filters or try again. - - + + &Listen Along + + Tomahawk::Query + + + and + + + + + You + + + + + you + + + + + and + + + + + %n other(s) + + %n other + %n others + + + + and %1%n other(s)%2 + + and %1%n other%2 + and %1%n others%2 + + + + + %1 people + + + + + loved this track + + + + + Tomahawk::RdioParser + + + Error fetching Rdio information from the network! + + + + + Tomahawk::ShortenedLinkParser + + + Network error parsing shortened link! + + + Tomahawk::Source - - + + Scanning (%L1 tracks) - + Scanning - + Checking - + Fetching - + Parsing - + Saving (%1%) + + Tomahawk::SpotifyParser + + + Error fetching Spotify information from the network! + + + TomahawkApp - + My Collection @@ -2246,12 +2478,12 @@ Please change the filters or try again. TomahawkOAuthTwitter - + Twitter PIN - + After authenticating on Twitter's web site, enter the displayed PIN number here: @@ -2261,27 +2493,27 @@ enter the displayed PIN number here: TomahawkTrayIcon - + Hide Tomahawk Window - + Show Tomahawk Window - + Currently not playing. - + Play - + Pause @@ -2425,7 +2657,7 @@ enter the displayed PIN number here: - + Play @@ -2445,134 +2677,128 @@ enter the displayed PIN number here: - + Global Search... - - + + Check For Updates... - - - + + + Connect To Peer - + Enter peer address: - + Enter peer port: - + Enter peer key: - + XSPF Error - + This is not a valid XSPF playlist. - + Failed to save tracks - + Some tracks in the playlist do not contain an artist and a title. They will be ignored. - - - Playback Error + + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. - - Sorry, there is a problem accessing your audio device. Make sure you have a suitable Phonon backend and required plugins installed. + + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. - - Sorry, there is a problem accessing your audio device. - - - - + Create New Station - + Name: - + New Station - + New Playlist - + Pause - + Go &offline - + Go &online - + Authentication Error - + %1 by %2 track, artist name - + %1 - %2 current track, some window title - + About Tomahawk - - <h2><b>Tomahawk %1<br/>(%2)</h2>Copyright 2010, 2011<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + <h2><b>Tomahawk %1<br/>(%2)</h2>Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson @@ -2650,65 +2876,70 @@ enter the displayed PIN number here: TrackModel - + Artist - + Title - + Album - + Track - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + Score + + + Composer + + TrackView - + Sorry, your filter '%1' did not match any results. @@ -2729,7 +2960,7 @@ enter the displayed PIN number here: TreeItemDelegate - + Unknown @@ -2737,54 +2968,59 @@ enter the displayed PIN number here: TreeModel - + Name - + Duration - + Bitrate - + Age - + Year - + Size - + Origin - + + Composer + + + + All Artists - - + + My Collection - - + + Collection of %1 @@ -2792,34 +3028,32 @@ enter the displayed PIN number here: TwitterConfigWidget - + Configure this Twitter account - + The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - - - + Status: No saved credentials - + Authenticate with Twitter - + Twitter Connections - + If you only want to post tweets, you're done. @@ -2829,158 +3063,50 @@ You can re-send a sync message at any time simply by sending another tweet using - + Select the kind of tweet you would like, then press the button to post it: - - + Global Tweet - - + @Mention - - + Direct Message - + e.g. @tomahawk - + Send Message - - - - - Tweet! - - - - - - - Authenticate - - - - - - Status: Credentials saved for %1 - - - - - - De-authenticate - - - - - - - - - - - Tweetin' Error - - - - - The credentials could not be verified. -You may wish to try re-authenticating. - - - - - Status: Error validating credentials - - - - - Send Message! - - - - - Send Mention! - - - - - You must enter a user name for this type of tweet. - - - - - Your saved credentials could not be loaded. -You may wish to try re-authenticating. - - - - - Your saved credentials could not be verified. -You may wish to try re-authenticating. - - - - - - There was an error posting your status -- sorry! - - - - - - Tweeted! - - - - - Your tweet has been posted! - - - - - There was an error posting your direct message -- sorry! - - - - - Your message has been posted! - - - - - TwitterPlugin - - - Twitter - - ViewManager - - All available tracks + + SuperCollection - + + Combined libraries of all your online friends + + + + All available albums @@ -3003,7 +3129,7 @@ You may wish to try re-authenticating. - + No recently created playlists in your network. @@ -3016,7 +3142,7 @@ You may wish to try re-authenticating. WhatsHotWidget - + Charts @@ -3070,7 +3196,22 @@ Lyrics for "%1" by %2: XSPFLoader - + + Failed to parse contents of XSPF playlist + + + + + Some playlist entries were found without artist and track name, they will be omitted + + + + + Failed to fetch the desired playlist from the network, or the desired file does not exist + + + + New Playlist @@ -3078,101 +3219,247 @@ Lyrics for "%1" by %2: XmlConsole - + Xml stream console - - + + Filter - + Save log - + Disabled - + By JID - + By namespace uri - + By all attributes - + Visible stanzas - + Information query - + Message - + Presence - + Custom - + Close - + Save XMPP log to file - + OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) + + XmppConfigWidget + + + Xmpp Configuration + + + + + Configure this Xmpp account + + + + + Enter your Xmpp login to connect with your friends using Tomahawk! + + + + + Login Information + + + + + Xmpp ID: + + + + + e.g. user@example.com + + + + + Password: + + + + + An account with this name already exists! + + + + + Advanced Xmpp Settings + + + + + Server: + + + + + Port: + + + + + XmppSipPlugin + + + User Interaction + + + + + Host is unknown + + + + + Item not found + + + + + Authorization Error + + + + + Remote Stream Error + + + + + Remote Connection failed + + + + + Internal Server Error + + + + + System shutdown + + + + + Conflict + + + + + Unknown + + + + + Add Friend + + + + + Enter Xmpp ID: + + + + + Add Friend... + + + + + XML Console... + + + + + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! + + + + + Authorize User + + + + + Do you want to grant <b>%1</b> access to your Collection? + + + ZeroconfConfig - + Form - + Local Network configuration - + This plugin will automatically find other users running Tomahawk on your local network - + Connect automatically when Tomahawk starts diff --git a/resources.qrc b/resources.qrc index d3072599e..c5a771a28 100644 --- a/resources.qrc +++ b/resources.qrc @@ -138,5 +138,6 @@ data/images/spotifycore-logo.png data/sql/dbmigrate-27_to_28.sql data/images/process-stop.png + data/icons/tomahawk-icon-128x128-grayscale.png diff --git a/src/LoadXSPFDialog.ui b/src/LoadXSPFDialog.ui index 90350a425..7057d87fe 100644 --- a/src/LoadXSPFDialog.ui +++ b/src/LoadXSPFDialog.ui @@ -19,7 +19,7 @@ - Playlist Url + Playlist URL diff --git a/src/accounts/lastfm/lastfmplugin.cpp b/src/accounts/lastfm/lastfmplugin.cpp index 992cf7a36..2af69cf41 100644 --- a/src/accounts/lastfm/lastfmplugin.cpp +++ b/src/accounts/lastfm/lastfmplugin.cpp @@ -456,7 +456,7 @@ LastFmPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) ); imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) ); imgurl.addQueryItem( "autocorrect", QString::number( 1 ) ); - imgurl.addQueryItem( "size", "large" ); + imgurl.addQueryItem( "size", "largesquare" ); imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" ); QNetworkRequest req( imgurl ); @@ -475,7 +475,7 @@ LastFmPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy imgurl.addQueryItem( "method", "artist.imageredirect" ); imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) ); imgurl.addQueryItem( "autocorrect", QString::number( 1 ) ); - imgurl.addQueryItem( "size", "large" ); + imgurl.addQueryItem( "size", "largesquare" ); imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" ); QNetworkRequest req( imgurl ); diff --git a/src/accounts/spotify/SpotifyAccount.h b/src/accounts/spotify/SpotifyAccount.h index 5725337e9..2086c17f8 100644 --- a/src/accounts/spotify/SpotifyAccount.h +++ b/src/accounts/spotify/SpotifyAccount.h @@ -51,7 +51,7 @@ public: SpotifyAccountFactory() {} virtual Account* createAccount( const QString& accountId = QString() ); - virtual QString description() const { return tr( "Play music from and sync your playlists with Spotify" ); } + virtual QString description() const { return tr( "Play music from and sync your playlists with Spotify Premium" ); } virtual QString factoryId() const { return "spotifyaccount"; } virtual QString prettyName() const { return "Spotify"; } diff --git a/src/accounts/xmpp/googlewrapper/googlewrapper.h b/src/accounts/xmpp/googlewrapper/googlewrapper.h index 833cf3be2..24e677f7f 100644 --- a/src/accounts/xmpp/googlewrapper/googlewrapper.h +++ b/src/accounts/xmpp/googlewrapper/googlewrapper.h @@ -38,7 +38,7 @@ public: virtual QString prettyName() const { return "Google"; } virtual QString factoryId() const { return "googleaccount"; } - QString description() const { return tr( "Connect to GChat to find your friends" ); } + QString description() const { return tr( "Connect to Google Talk to find your friends" ); } virtual QPixmap icon() const; virtual Account* createAccount( const QString& pluginId ); }; diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index 95c079e0c..070686cdd 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -252,7 +252,7 @@ void AudioControls::onCoverUpdated() { Query* query = qobject_cast< Query* >( sender() ); - if ( !query || query != m_currentTrack->toQuery().data() ) + if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() ) return; setCover(); @@ -277,7 +277,7 @@ void AudioControls::onSocialActionsLoaded() { Query* query = qobject_cast< Query* >( sender() ); - if ( !query || query != m_currentTrack->toQuery().data() ) + if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() ) return; setSocialActions(); diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 52d714ad2..5e845fa2a 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -77,6 +77,10 @@ set( libGuiSources playlist/artistview.cpp playlist/customplaylistview.cpp playlist/ViewHeader.cpp + playlist/RecentlyAddedModel.cpp + playlist/RecentlyPlayedModel.cpp + playlist/PlaylistLargeItemDelegate.cpp + playlist/PlaylistChartItemDelegate.cpp playlist/dynamic/DynamicPlaylist.cpp playlist/dynamic/DynamicView.cpp diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 53b04d961..450ecf506 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -30,6 +30,7 @@ using namespace Tomahawk; using namespace Accounts; #define ACCOUNTMODEL_DEBUG 0 + AccountModel::AccountModel( QObject* parent ) : QAbstractListModel( parent ) { diff --git a/src/libtomahawk/accounts/AccountModelNode.h b/src/libtomahawk/accounts/AccountModelNode.h index 28a3a5625..857d57402 100644 --- a/src/libtomahawk/accounts/AccountModelNode.h +++ b/src/libtomahawk/accounts/AccountModelNode.h @@ -26,6 +26,8 @@ #include +#define ACCOUNTMODELNODE_DEBUG 0 + namespace Tomahawk { namespace Accounts { @@ -87,7 +89,9 @@ struct AccountModelNode { { if ( AccountManager::instance()->factoryForAccount( acct ) == fac ) { -// qDebug() << "Found account for factory:" << acct->accountFriendlyName(); +#if ACCOUNTMODELNODE_DEBUG + qDebug() << "Found account for factory:" << acct->accountFriendlyName(); +#endif accounts.append( acct ); } } @@ -98,15 +102,24 @@ struct AccountModelNode { init(); atticaContent = cnt; -// qDebug() << "Creating attica model node for resolver:" << cnt.id(); - +#if ACCOUNTMODELNODE_DEBUG + qDebug() << "Creating attica model node for resolver:" << cnt.id(); +#endif foreach ( Account* acct, AccountManager::instance()->accounts( Accounts::ResolverType ) ) { +#if ACCOUNTMODELNODE_DEBUG + qDebug() << "Checking account:" << acct->accountFriendlyName() << qobject_cast< AtticaResolverAccount* >( acct ); +#endif if ( AtticaResolverAccount* resolver = qobject_cast< AtticaResolverAccount* >( acct ) ) { +#if ACCOUNTMODELNODE_DEBUG + qDebug() << "With attica id:" << resolver->atticaId(); +#endif if ( resolver->atticaId() == atticaContent.id() ) { -// qDebug() << "found atticaaccount :" << resolver->accountFriendlyName(); +#if ACCOUNTMODELNODE_DEBUG + qDebug() << "found atticaaccount :" << resolver->accountFriendlyName(); +#endif atticaAccount = resolver; break; } diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 801477fd2..885530bc7 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -102,6 +102,8 @@ ResolverAccount::ResolverAccount( const QString& accountId, const QString& path setAccountFriendlyName( m_resolver.data()->name() ); setTypes( AccountType( ResolverType ) ); + + sync(); } @@ -225,6 +227,7 @@ AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QS TomahawkSettings::instance()->setValue( QString( "accounts/%1/atticaresolver" ).arg( accountId ), true ); loadIcon(); + sync(); } diff --git a/src/libtomahawk/album.cpp b/src/libtomahawk/album.cpp index 16dfc5ca4..417880d5e 100644 --- a/src/libtomahawk/album.cpp +++ b/src/libtomahawk/album.cpp @@ -31,7 +31,9 @@ using namespace Tomahawk; Album::~Album() { +#ifndef ENABLE_HEADLESS delete m_cover; +#endif } @@ -74,8 +76,10 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& , m_id( id ) , m_name( name ) , m_artist( artist ) - , m_cover( 0 ) , m_infoLoaded( false ) +#ifndef ENABLE_HEADLESS + , m_cover( 0 ) +#endif { connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), diff --git a/src/libtomahawk/album.h b/src/libtomahawk/album.h index 1e886c47c..9ecacf900 100644 --- a/src/libtomahawk/album.h +++ b/src/libtomahawk/album.h @@ -73,11 +73,13 @@ private: QString m_name; artist_ptr m_artist; QByteArray m_coverBuffer; - mutable QPixmap* m_cover; bool m_infoLoaded; mutable QString m_uuid; +#ifndef ENABLE_HEADLESS + mutable QPixmap* m_cover; mutable QHash< int, QPixmap > m_coverCache; +#endif Tomahawk::playlistinterface_ptr m_playlistInterface; }; diff --git a/src/libtomahawk/artist.cpp b/src/libtomahawk/artist.cpp index 0171ffa23..e90ca835a 100644 --- a/src/libtomahawk/artist.cpp +++ b/src/libtomahawk/artist.cpp @@ -31,7 +31,9 @@ using namespace Tomahawk; Artist::~Artist() { +#ifndef ENABLE_HEADLESS delete m_cover; +#endif } @@ -73,8 +75,10 @@ Artist::Artist( unsigned int id, const QString& name ) : QObject() , m_id( id ) , m_name( name ) - , m_cover( 0 ) , m_infoLoaded( false ) +#ifndef ENABLE_HEADLESS + , m_cover( 0 ) +#endif { m_sortname = DatabaseImpl::sortname( name, true ); diff --git a/src/libtomahawk/artist.h b/src/libtomahawk/artist.h index a9f9a5b7c..0c656bfa6 100644 --- a/src/libtomahawk/artist.h +++ b/src/libtomahawk/artist.h @@ -72,11 +72,13 @@ private: QString m_name; QString m_sortname; QByteArray m_coverBuffer; - mutable QPixmap* m_cover; bool m_infoLoaded; mutable QString m_uuid; +#ifndef ENABLE_HEADLESS + mutable QPixmap* m_cover; mutable QHash< int, QPixmap > m_coverCache; +#endif Tomahawk::playlistinterface_ptr m_playlistInterface; }; diff --git a/src/libtomahawk/database/databasecommand_loadsocialactions.cpp b/src/libtomahawk/database/databasecommand_loadsocialactions.cpp index efb5a9d50..bd2474752 100644 --- a/src/libtomahawk/database/databasecommand_loadsocialactions.cpp +++ b/src/libtomahawk/database/databasecommand_loadsocialactions.cpp @@ -65,9 +65,10 @@ DatabaseCommand_LoadSocialActions::exec( DatabaseImpl* dbi ) action.action = query.value( 0 ); // action action.value = query.value( 1 ); // comment action.timestamp = query.value( 2 ); // timestamp - action.source = query.value( 3 ); // source - - allSocialActions.append( action ); + action.source = SourceList::instance()->get( query.value( 3 ).toInt() ); // source + + if ( !action.source.isNull() ) + allSocialActions.append( action ); } m_query->setAllSocialActions( allSocialActions ); diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 38149e83d..9d0e4199c 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -55,9 +55,6 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint(); Tomahawk::result_ptr result = lib->resultFromHint( m_query ); - /* qDebug() << "Result null:" << result.isNull(); - * qDebug() << "Collection null:" << result->collection().isNull(); - * qDebug() << "Source null:" << result->collection()->source().isNull();*/ if ( !result.isNull() && !result->collection().isNull() && result->collection()->source()->isOnline() ) { QList res; @@ -137,7 +134,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) else { s = SourceList::instance()->get( files_query.value( 16 ).toUInt() ); - if( s.isNull() ) + if ( s.isNull() ) { qDebug() << "Could not find source" << files_query.value( 16 ).toUInt(); continue; @@ -146,13 +143,18 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) url = QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url ); } + bool cached = Tomahawk::Result::isCached( url ); Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - Tomahawk::artist_ptr artist = - Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); - Tomahawk::album_ptr album = - Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); - Tomahawk::artist_ptr composer = - Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); + if ( cached ) + { + qDebug() << "Result already cached:" << result->toString(); + res << result; + continue; + } + + Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); + Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); + Tomahawk::artist_ptr composer = Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); result->setModificationTime( files_query.value( 1 ).toUInt() ); result->setSize( files_query.value( 2 ).toUInt() ); @@ -181,6 +183,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) result->setAttributes( attr ); result->setCollection( s->collection() ); + res << result; } @@ -270,7 +273,7 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) else { s = SourceList::instance()->get( files_query.value( 16 ).toUInt() ); - if( s.isNull() ) + if ( s.isNull() ) { qDebug() << "Could not find source" << files_query.value( 16 ).toUInt(); continue; @@ -279,13 +282,18 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) url = QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url ); } + bool cached = Tomahawk::Result::isCached( url ); Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - Tomahawk::artist_ptr artist = - Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); - Tomahawk::album_ptr album = - Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); - Tomahawk::artist_ptr composer = - Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); + if ( cached ) + { + qDebug() << "Result already cached:" << result->toString(); + res << result; + continue; + } + + Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); + Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); + Tomahawk::artist_ptr composer = Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); result->setModificationTime( files_query.value( 1 ).toUInt() ); result->setSize( files_query.value( 2 ).toUInt() ); @@ -322,8 +330,8 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) } result->setAttributes( attr ); - result->setCollection( s->collection() ); + res << result; } diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp index 54e3e993f..8eb193441 100644 --- a/src/libtomahawk/database/databaseimpl.cpp +++ b/src/libtomahawk/database/databaseimpl.cpp @@ -482,7 +482,7 @@ DatabaseImpl::sortname( const QString& str, bool replaceArticle ) if ( replaceArticle && s.startsWith( "the " ) ) { - s = s.right( s.length() - 4 ); + s = s.mid( 4 ); } return s; diff --git a/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp new file mode 100644 index 000000000..3449230f1 --- /dev/null +++ b/src/libtomahawk/playlist/PlaylistChartItemDelegate.cpp @@ -0,0 +1,254 @@ +/* === 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 "PlaylistChartItemDelegate.h" + +#include +#include + +#include "query.h" +#include "result.h" +#include "artist.h" +#include "source.h" +#include "sourcelist.h" + +#include "trackmodel.h" +#include "trackmodelitem.h" +#include "trackproxymodel.h" +#include "trackview.h" +#include "trackheader.h" + +#include "utils/tomahawkutilsgui.h" +#include "utils/logger.h" + +using namespace Tomahawk; + + +PlaylistChartItemDelegate::PlaylistChartItemDelegate( TrackView* parent, TrackProxyModel* proxy ) + : QStyledItemDelegate( (QObject*)parent ) + , m_view( parent ) + , m_model( proxy ) +{ + m_topOption = QTextOption( Qt::AlignTop ); + m_topOption.setWrapMode( QTextOption::NoWrap ); + + m_centerOption = QTextOption( Qt::AlignCenter ); + m_centerOption.setWrapMode( QTextOption::NoWrap ); + + m_centerRightOption = QTextOption( Qt::AlignVCenter | Qt::AlignRight ); + m_centerRightOption.setWrapMode( QTextOption::NoWrap ); + + m_bottomOption = QTextOption( Qt::AlignBottom ); + m_bottomOption.setWrapMode( QTextOption::NoWrap ); +} + + +QSize +PlaylistChartItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QSize size = QStyledItemDelegate::sizeHint( option, index ); + + int stretch = 0; + switch ( index.row() ) + { + case 0: + stretch = 6; + break; + case 1: + stretch = 5; + break; + case 2: + stretch = 4; + break; + + default: + if ( index.row() < 10 ) + stretch = 3; + else + stretch = 2; + } + + if ( index.isValid() ) + { + int rowHeight = option.fontMetrics.height() + 8; + size.setHeight( rowHeight * stretch ); + } + + return size; +} + + +QWidget* +PlaylistChartItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + Q_UNUSED( parent ); + Q_UNUSED( option ); + Q_UNUSED( index ); + return 0; +} + + +void +PlaylistChartItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, TrackModelItem* item ) const +{ + initStyleOption( option, index ); + + if ( item->isPlaying() ) + { + option->palette.setColor( QPalette::Highlight, option->palette.color( QPalette::Mid ) ); + option->state |= QStyle::State_Selected; + } + + if ( option->state & QStyle::State_Selected ) + { + option->palette.setColor( QPalette::Text, option->palette.color( QPalette::HighlightedText ) ); + } + else + { + float opacity = 0.0; + if ( item->query()->results().count() ) + opacity = item->query()->results().first()->score(); + + opacity = qMax( (float)0.3, opacity ); + QColor textColor = TomahawkUtils::alphaBlend( option->palette.color( QPalette::Text ), option->palette.color( QPalette::BrightText ), opacity ); + + option->palette.setColor( QPalette::Text, textColor ); + } +} + + +void +PlaylistChartItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + TrackModelItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) ); + Q_ASSERT( item ); + + QStyleOptionViewItemV4 opt = option; + prepareStyleOption( &opt, index, item ); + opt.text.clear(); + + qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter ); + + if ( m_view->header()->visualIndex( index.column() ) > 0 ) + return; + + QPixmap pixmap, avatar; + QString artist, track, upperText, lowerText; + unsigned int duration = 0; + + if ( item->query()->results().count() ) + { + artist = item->query()->results().first()->artist()->name(); + track = item->query()->results().first()->track(); + duration = item->query()->results().first()->duration(); + } + else + { + artist = item->query()->artist(); + track = item->query()->track(); + } + + painter->save(); + { + QRect r = opt.rect.adjusted( 3, 6, 0, -6 ); + + // Paint Now Playing Speaker Icon + if ( item->isPlaying() ) + { + QPixmap nowPlayingIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker ); + QRect npr = r.adjusted( 3, r.height() / 2 - nowPlayingIcon.height() / 2, 18 - r.width(), -r.height() / 2 + nowPlayingIcon.height() / 2 ); + nowPlayingIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker, TomahawkUtils::Original, npr.size() ); + painter->drawPixmap( npr, nowPlayingIcon ); + r.adjust( 22, 0, 0, 0 ); + } + + QFont figureFont = opt.font; + figureFont.setPixelSize( 18 ); + figureFont.setWeight( 99 ); + + QFont boldFont = opt.font; + boldFont.setPixelSize( 15 ); + boldFont.setWeight( 99 ); + + QFont smallBoldFont = opt.font; + smallBoldFont.setPixelSize( 12 ); + smallBoldFont.setWeight( 80 ); + + QFont durationFont = opt.font; + durationFont.setPixelSize( 12 ); + durationFont.setWeight( 80 ); + + if ( index.row() == 0 ) + { + figureFont.setPixelSize( 36 ); + boldFont.setPixelSize( 26 ); + smallBoldFont.setPixelSize( 22 ); + } + else if ( index.row() == 1 ) + { + figureFont.setPixelSize( 30 ); + boldFont.setPixelSize( 22 ); + smallBoldFont.setPixelSize( 18 ); + } + else if ( index.row() == 2 ) + { + figureFont.setPixelSize( 24 ); + boldFont.setPixelSize( 18 ); + smallBoldFont.setPixelSize( 14 ); + } + else if ( index.row() >= 10 ) + { + boldFont.setPixelSize( 12 ); + smallBoldFont.setPixelSize( 11 ); + } + + QRect figureRect = r.adjusted( 0, 0, -option.rect.width() + 60 - 6 + r.left(), 0 ); + painter->setFont( figureFont ); + painter->setPen( option.palette.text().color().lighter( 450 ) ); + painter->drawText( figureRect, QString::number( index.row() + 1 ), m_centerOption ); + painter->setPen( opt.palette.text().color() ); + + QRect pixmapRect = r.adjusted( figureRect.width() + 6, 0, -option.rect.width() + figureRect.width() + option.rect.height() - 6 + r.left(), 0 ); + pixmap = item->query()->cover( pixmapRect.size(), false ); + if ( !pixmap ) + { + pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultTrackImage, TomahawkUtils::ScaledCover, pixmapRect.size() ); + } + painter->drawPixmap( pixmapRect, pixmap ); + + r.adjust( pixmapRect.width() + figureRect.width() + 18, 1, -28, 0 ); + QRect leftRect = r.adjusted( 0, 0, -48, 0 ); + QRect rightRect = r.adjusted( r.width() - 40, 0, 0, 0 ); + + painter->setFont( boldFont ); + QString text = painter->fontMetrics().elidedText( artist, Qt::ElideRight, leftRect.width() ); + painter->drawText( leftRect, text, m_topOption ); + + painter->setFont( smallBoldFont ); + text = painter->fontMetrics().elidedText( track, Qt::ElideRight, leftRect.width() ); + painter->drawText( index.row() >= 10 ? leftRect : leftRect.adjusted( 0, painter->fontMetrics().height() + 6, 0, 0 ), text, index.row() >= 10 ? m_bottomOption : m_topOption ); + + if ( duration > 0 ) + { + painter->setFont( durationFont ); + text = painter->fontMetrics().elidedText( TomahawkUtils::timeToString( duration ), Qt::ElideRight, rightRect.width() ); + painter->drawText( rightRect, text, m_centerRightOption ); + } + } + painter->restore(); +} diff --git a/src/libtomahawk/playlist/PlaylistChartItemDelegate.h b/src/libtomahawk/playlist/PlaylistChartItemDelegate.h new file mode 100644 index 000000000..1819be8a0 --- /dev/null +++ b/src/libtomahawk/playlist/PlaylistChartItemDelegate.h @@ -0,0 +1,56 @@ +/* === 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 . + */ + +#ifndef PLAYLISTCHARTITEMDELEGATE_H +#define PLAYLISTCHARTITEMDELEGATE_H + +#include +#include + +#include "dllmacro.h" + +class TrackModel; +class TrackModelItem; +class TrackProxyModel; +class TrackView; + +class DLLEXPORT PlaylistChartItemDelegate : public QStyledItemDelegate +{ +Q_OBJECT + +public: + PlaylistChartItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 ); + +protected: + void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; + QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + +private: + void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, TrackModelItem* item ) const; + + QTextOption m_topOption; + QTextOption m_centerOption; + QTextOption m_centerRightOption; + QTextOption m_bottomOption; + + TrackView* m_view; + TrackProxyModel* m_model; +}; + +#endif // PLAYLISTCHARTITEMDELEGATE_H diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp new file mode 100644 index 000000000..f1c036456 --- /dev/null +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -0,0 +1,263 @@ +/* === 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 "PlaylistLargeItemDelegate.h" + +#include +#include +#include + +#include "query.h" +#include "result.h" +#include "artist.h" +#include "source.h" +#include "sourcelist.h" + +#include "trackmodel.h" +#include "trackmodelitem.h" +#include "trackproxymodel.h" +#include "trackview.h" +#include "trackheader.h" + +#include "utils/tomahawkutilsgui.h" +#include "utils/logger.h" + +using namespace Tomahawk; + + +PlaylistLargeItemDelegate::PlaylistLargeItemDelegate( TrackView* parent, TrackProxyModel* proxy ) + : QStyledItemDelegate( (QObject*)parent ) + , m_view( parent ) + , m_model( proxy ) +{ + m_topOption = QTextOption( Qt::AlignTop ); + m_topOption.setWrapMode( QTextOption::NoWrap ); + + m_centerRightOption = QTextOption( Qt::AlignVCenter | Qt::AlignRight ); + m_centerRightOption.setWrapMode( QTextOption::NoWrap ); + + m_bottomOption = QTextOption( Qt::AlignBottom ); + m_bottomOption.setWrapMode( QTextOption::NoWrap ); +} + + +QSize +PlaylistLargeItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QSize size = QStyledItemDelegate::sizeHint( option, index ); + + if ( index.isValid() ) + { + int rowHeight = option.fontMetrics.height() + 8; + size.setHeight( rowHeight * 3 ); + } + + return size; +} + + +QWidget* +PlaylistLargeItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + Q_UNUSED( parent ); + Q_UNUSED( option ); + Q_UNUSED( index ); + return 0; +} + + +void +PlaylistLargeItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, TrackModelItem* item ) const +{ + initStyleOption( option, index ); + + if ( item->isPlaying() ) + { + option->palette.setColor( QPalette::Highlight, option->palette.color( QPalette::Mid ) ); + option->state |= QStyle::State_Selected; + } + + if ( option->state & QStyle::State_Selected ) + { + option->palette.setColor( QPalette::Text, option->palette.color( QPalette::HighlightedText ) ); + } + else + { + float opacity = 0.0; + if ( item->query()->results().count() ) + opacity = item->query()->results().first()->score(); + + opacity = qMax( (float)0.3, opacity ); + QColor textColor = TomahawkUtils::alphaBlend( option->palette.color( QPalette::Text ), option->palette.color( QPalette::BrightText ), opacity ); + + option->palette.setColor( QPalette::Text, textColor ); + } +} + + +void +PlaylistLargeItemDelegate::drawRichText( QPainter* painter, const QRect& rect, int flags, QTextDocument& text ) const +{ + text.setPageSize( QSize( rect.width(), QWIDGETSIZE_MAX ) ); + QAbstractTextDocumentLayout* layout = text.documentLayout(); + + const int height = qRound( layout->documentSize().height() ); + int y = rect.y(); + if ( flags & Qt::AlignBottom ) + y += ( rect.height() - height ); + else if ( flags & Qt::AlignVCenter ) + y += ( rect.height() - height ) / 2; + + QAbstractTextDocumentLayout::PaintContext context; + context.palette.setColor( QPalette::Text, painter->pen().color() ); + + painter->save(); + painter->translate( rect.x(), y ); + layout->draw( painter, context ); + painter->restore(); +} + + +void +PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + TrackModelItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) ); + Q_ASSERT( item ); + + QStyleOptionViewItemV4 opt = option; + prepareStyleOption( &opt, index, item ); + opt.text.clear(); + + qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter ); + + if ( m_view->header()->visualIndex( index.column() ) > 0 ) + return; + + QPixmap pixmap, avatar; + QString artist, track, upperText, lowerText; + source_ptr source = item->query()->playedBy().first; + unsigned int duration = 0; + + if ( item->query()->results().count() ) + { + artist = item->query()->results().first()->artist()->name(); + track = item->query()->results().first()->track(); + duration = item->query()->results().first()->duration(); + } + else + { + artist = item->query()->artist(); + track = item->query()->track(); + } + + lowerText = item->query()->socialActionDescription( "Love", Query::Detailed ); + + if ( source.isNull() ) + { + } + else + { + upperText = QString( "%1 - %2" ).arg( artist ).arg( track ); + QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->playedBy().second ), true ); + + if ( source == SourceList::instance()->getLocal() ) + lowerText = QString( tr( "played %1 by you" ) ).arg( playtime ); + else + lowerText = QString( tr( "played %1 by %2" ) ).arg( playtime ).arg( source->friendlyName() ); + } + + painter->save(); + { + QRect r = opt.rect.adjusted( 3, 6, 0, -6 ); + + // Paint Now Playing Speaker Icon + if ( item->isPlaying() ) + { + QPixmap nowPlayingIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker ); + QRect npr = r.adjusted( 3, r.height() / 2 - nowPlayingIcon.height() / 2, 18 - r.width(), -r.height() / 2 + nowPlayingIcon.height() / 2 ); + nowPlayingIcon = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeaker, TomahawkUtils::Original, npr.size() ); + painter->drawPixmap( npr, nowPlayingIcon ); + r.adjust( 22, 0, 0, 0 ); + } + + painter->setPen( opt.palette.text().color() ); + + QSize avatarSize( 32, 32 ); + QRect pixmapRect = r.adjusted( 6, 0, -option.rect.width() + option.rect.height() - 6 + r.left(), 0 ); + QRect avatarRect = r.adjusted( option.rect.width() - r.left() - 12 - avatarSize.width(), ( option.rect.height() - avatarSize.height() ) / 2 - 5, 0, 0 ); + avatarRect.setSize( avatarSize ); + + if ( source ) + avatar = source->avatar( Source::FancyStyle, avatarRect.size() ); + + pixmap = item->query()->cover( pixmapRect.size(), false ); + if ( !pixmap ) + { + pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultTrackImage, TomahawkUtils::ScaledCover, pixmapRect.size() ); + } + + painter->drawPixmap( pixmapRect, pixmap ); + + if ( !avatar.isNull() ) + painter->drawPixmap( avatarRect, avatar ); + + QFont boldFont = opt.font; + boldFont.setPixelSize( 15 ); + boldFont.setWeight( 99 ); + + QFont smallBoldFont = opt.font; + smallBoldFont.setPixelSize( 12 ); + smallBoldFont.setBold( true ); + smallBoldFont.setWeight( 80 ); + + QFont smallFont = opt.font; + smallFont.setPixelSize( 10 ); + + r.adjust( pixmapRect.width() + 12, 1, -28 - avatar.width(), 0 ); + QRect leftRect = r.adjusted( 0, 0, -48, 0 ); + QRect rightRect = r.adjusted( r.width() - 40, 0, 0, 0 ); + + painter->setFont( boldFont ); + QString text = painter->fontMetrics().elidedText( artist, Qt::ElideRight, leftRect.width() ); + painter->drawText( leftRect, text, m_topOption ); + + painter->setFont( smallBoldFont ); + text = painter->fontMetrics().elidedText( track, Qt::ElideRight, leftRect.width() ); + painter->drawText( leftRect.adjusted( 0, 19, 0, 0 ), text, m_topOption ); + + painter->setFont( smallFont ); + QTextDocument textDoc; + textDoc.setHtml( lowerText ); + textDoc.setDocumentMargin( 0 ); + textDoc.setDefaultFont( painter->font() ); + textDoc.setDefaultTextOption( m_bottomOption ); + + if ( textDoc.idealWidth() > leftRect.width() ) + textDoc.setHtml( item->query()->socialActionDescription( "Love", Query::Short ) ); + + drawRichText( painter, leftRect, Qt::AlignBottom, textDoc ); + + if ( duration > 0 ) + { + painter->setFont( smallBoldFont ); + text = painter->fontMetrics().elidedText( TomahawkUtils::timeToString( duration ), Qt::ElideRight, rightRect.width() ); + painter->drawText( rightRect, text, m_centerRightOption ); + } + } + painter->restore(); +} diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h new file mode 100644 index 000000000..56ea64a57 --- /dev/null +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h @@ -0,0 +1,57 @@ +/* === 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 . + */ + +#ifndef PLAYLISTLARGEITEMDELEGATE_H +#define PLAYLISTLARGEITEMDELEGATE_H + +#include +#include +#include + +#include "dllmacro.h" + +class TrackModel; +class TrackModelItem; +class TrackProxyModel; +class TrackView; + +class DLLEXPORT PlaylistLargeItemDelegate : public QStyledItemDelegate +{ +Q_OBJECT + +public: + PlaylistLargeItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 ); + +protected: + void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; + QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const; + +private: + void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, TrackModelItem* item ) const; + void drawRichText( QPainter* painter, const QRect& rect, int flags, QTextDocument& text ) const; + + QTextOption m_topOption; + QTextOption m_centerRightOption; + QTextOption m_bottomOption; + + TrackView* m_view; + TrackProxyModel* m_model; +}; + +#endif // PLAYLISTLARGEITEMDELEGATE_H diff --git a/src/libtomahawk/playlist/RecentlyAddedModel.cpp b/src/libtomahawk/playlist/RecentlyAddedModel.cpp new file mode 100644 index 000000000..e5adacc67 --- /dev/null +++ b/src/libtomahawk/playlist/RecentlyAddedModel.cpp @@ -0,0 +1,102 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, 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 "RecentlyAddedModel.h" + +#include +#include + +#include "source.h" +#include "sourcelist.h" +#include "database/database.h" +#include "database/databasecommand_alltracks.h" +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#define LATEST_TRACK_ITEMS 250 + +using namespace Tomahawk; + + +RecentlyAddedModel::RecentlyAddedModel( const source_ptr& source, QObject* parent ) + : TrackModel( parent ) + , m_source( source ) + , m_limit( LATEST_TRACK_ITEMS ) +{ + if ( source.isNull() ) + { + connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); + connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); + } + else + { + onSourceAdded( source ); + loadHistory(); + } +} + + +RecentlyAddedModel::~RecentlyAddedModel() +{ +} + + +void +RecentlyAddedModel::loadHistory() +{ + if ( rowCount( QModelIndex() ) ) + { + clear(); + } + + DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_source->collection() ); + cmd->setLimit( m_limit ); + cmd->setSortOrder( DatabaseCommand_AllTracks::ModificationTime ); + cmd->setSortDescending( true ); + + connect( cmd, SIGNAL( tracks( QList, QVariant ) ), + SLOT( append( QList ) ), Qt::QueuedConnection ); + + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + + +void +RecentlyAddedModel::onSourcesReady() +{ + Q_ASSERT( m_source.isNull() ); + + loadHistory(); + + foreach ( const source_ptr& source, SourceList::instance()->sources() ) + onSourceAdded( source ); +} + + +void +RecentlyAddedModel::onSourceAdded( const Tomahawk::source_ptr& source ) +{ + connect( source->collection().data(), SIGNAL( changed() ), SLOT( loadHistory() ) ); +} + + +bool +RecentlyAddedModel::isTemporary() const +{ + return true; +} diff --git a/src/libtomahawk/playlist/RecentlyAddedModel.h b/src/libtomahawk/playlist/RecentlyAddedModel.h new file mode 100644 index 000000000..53d113f43 --- /dev/null +++ b/src/libtomahawk/playlist/RecentlyAddedModel.h @@ -0,0 +1,54 @@ +/* === 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 . + */ + +#ifndef RECENTLYADDEDMODEL_H +#define RECENTLYADDEDMODEL_H + +#include +#include + +#include "typedefs.h" +#include "trackmodel.h" + +#include "dllmacro.h" + +class DLLEXPORT RecentlyAddedModel : public TrackModel +{ +Q_OBJECT + +public: + explicit RecentlyAddedModel( const Tomahawk::source_ptr& source, QObject* parent = 0 ); + ~RecentlyAddedModel(); + + unsigned int limit() const { return m_limit; } + void setLimit( unsigned int limit ) { m_limit = limit; } + + bool isTemporary() const; + +private slots: + void onSourcesReady(); + void onSourceAdded( const Tomahawk::source_ptr& source ); + + void loadHistory(); + +private: + Tomahawk::source_ptr m_source; + unsigned int m_limit; +}; + +#endif // RECENTLYADDEDMODEL_H diff --git a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp new file mode 100644 index 000000000..db41f2766 --- /dev/null +++ b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp @@ -0,0 +1,140 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, 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 "RecentlyPlayedModel.h" + +#include +#include + +#include "source.h" +#include "sourcelist.h" +#include "database/database.h" +#include "database/databasecommand_playbackhistory.h" +#include "utils/tomahawkutils.h" +#include "utils/logger.h" + +#define HISTORY_TRACK_ITEMS 25 + +using namespace Tomahawk; + + +RecentlyPlayedModel::RecentlyPlayedModel( const source_ptr& source, QObject* parent ) + : PlaylistModel( parent ) + , m_source( source ) + , m_limit( HISTORY_TRACK_ITEMS ) +{ + if ( source.isNull() ) + { + connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); + connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); + } + else + { + onSourceAdded( source ); + loadHistory(); + } +} + + +RecentlyPlayedModel::~RecentlyPlayedModel() +{ +} + + +void +RecentlyPlayedModel::loadHistory() +{ + if ( rowCount( QModelIndex() ) ) + { + clear(); + } + + DatabaseCommand_PlaybackHistory* cmd = new DatabaseCommand_PlaybackHistory( m_source ); + cmd->setLimit( m_limit ); + + connect( cmd, SIGNAL( tracks( QList ) ), + SLOT( append( QList ) ), Qt::QueuedConnection ); + + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + + +void +RecentlyPlayedModel::onSourcesReady() +{ + Q_ASSERT( m_source.isNull() ); + + loadHistory(); + + foreach ( const source_ptr& source, SourceList::instance()->sources() ) + onSourceAdded( source ); +} + + +void +RecentlyPlayedModel::onSourceAdded( const Tomahawk::source_ptr& source ) +{ + connect( source.data(), SIGNAL( playbackFinished( Tomahawk::query_ptr ) ), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::UniqueConnection ); +} + + +void +RecentlyPlayedModel::onPlaybackFinished( const Tomahawk::query_ptr& query ) +{ + int count = trackCount(); + unsigned int playtime = query->playedBy().second; + + if ( count ) + { + TrackModelItem* oldestItem = itemFromIndex( index( count - 1, 0, QModelIndex() ) ); + if ( oldestItem->query()->playedBy().second >= playtime ) + return; + + TrackModelItem* youngestItem = itemFromIndex( index( 0, 0, QModelIndex() ) ); + if ( youngestItem->query()->playedBy().second <= playtime ) + insert( query, 0 ); + else + { + for ( int i = 0; i < count - 1; i++ ) + { + TrackModelItem* item1 = itemFromIndex( index( i, 0, QModelIndex() ) ); + TrackModelItem* item2 = itemFromIndex( index( i + 1, 0, QModelIndex() ) ); + + if ( item1->query()->playedBy().second >= playtime && item2->query()->playedBy().second <= playtime ) + { + insert( query, i + 1 ); + break; + } + } + } + } + else + insert( query, 0 ); + + if ( trackCount() > (int)m_limit ) + remove( m_limit ); + + ensureResolved(); +} + + +bool +RecentlyPlayedModel::isTemporary() const +{ + return true; +} diff --git a/src/libtomahawk/playlist/RecentlyPlayedModel.h b/src/libtomahawk/playlist/RecentlyPlayedModel.h new file mode 100644 index 000000000..748535905 --- /dev/null +++ b/src/libtomahawk/playlist/RecentlyPlayedModel.h @@ -0,0 +1,55 @@ +/* === 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 . + */ + +#ifndef RECENTLYPLAYEDMODEL_H +#define RECENTLYPLAYEDMODEL_H + +#include +#include + +#include "typedefs.h" +#include "playlistmodel.h" + +#include "dllmacro.h" + +class DLLEXPORT RecentlyPlayedModel : public PlaylistModel +{ +Q_OBJECT + +public: + explicit RecentlyPlayedModel( const Tomahawk::source_ptr& source, QObject* parent = 0 ); + ~RecentlyPlayedModel(); + + unsigned int limit() const { return m_limit; } + void setLimit( unsigned int limit ) { m_limit = limit; } + + bool isTemporary() const; + +private slots: + void onSourcesReady(); + void onSourceAdded( const Tomahawk::source_ptr& source ); + + void onPlaybackFinished( const Tomahawk::query_ptr& query ); + void loadHistory(); + +private: + Tomahawk::source_ptr m_source; + unsigned int m_limit; +}; + +#endif // RECENTLYPLAYEDMODEL_H diff --git a/src/libtomahawk/playlist/collectionflatmodel.cpp b/src/libtomahawk/playlist/collectionflatmodel.cpp index 7d94ba023..7265cb27b 100644 --- a/src/libtomahawk/playlist/collectionflatmodel.cpp +++ b/src/libtomahawk/playlist/collectionflatmodel.cpp @@ -138,13 +138,3 @@ CollectionFlatModel::onTracksRemoved( const QList& tracks ) } } } - - -void -CollectionFlatModel::onDataChanged() -{ - TrackModelItem* p = (TrackModelItem*)sender(); - - if ( p ) - emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) ); -} diff --git a/src/libtomahawk/playlist/collectionflatmodel.h b/src/libtomahawk/playlist/collectionflatmodel.h index 0d2784b44..b5982974f 100644 --- a/src/libtomahawk/playlist/collectionflatmodel.h +++ b/src/libtomahawk/playlist/collectionflatmodel.h @@ -58,8 +58,6 @@ signals: void trackCountChanged( unsigned int tracks ); private slots: - void onDataChanged(); - void onTracksAdded( const QList& tracks ); void onTracksRemoved( const QList& tracks ); diff --git a/src/libtomahawk/playlist/customplaylistview.cpp b/src/libtomahawk/playlist/customplaylistview.cpp index b3b2c2ba5..8c6341447 100644 --- a/src/libtomahawk/playlist/customplaylistview.cpp +++ b/src/libtomahawk/playlist/customplaylistview.cpp @@ -37,6 +37,7 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c setFrameShape( QFrame::NoFrame ); setAttribute( Qt::WA_MacShowFocusRect, 0 ); + m_model->setStyle( TrackModel::Large ); setPlaylistModel( m_model ); generateTracks(); diff --git a/src/libtomahawk/playlist/playlistmodel.cpp b/src/libtomahawk/playlist/playlistmodel.cpp index 4cd5a2b59..080af747e 100644 --- a/src/libtomahawk/playlist/playlistmodel.cpp +++ b/src/libtomahawk/playlist/playlistmodel.cpp @@ -86,26 +86,6 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn } -void -PlaylistModel::loadHistory( const Tomahawk::source_ptr& source, unsigned int amount ) -{ - if ( rowCount( QModelIndex() ) ) - { - clear(); - } - - m_playlist.clear(); - - DatabaseCommand_PlaybackHistory* cmd = new DatabaseCommand_PlaybackHistory( source ); - cmd->setLimit( amount ); - - connect( cmd, SIGNAL( tracks( QList ) ), - SLOT( append( QList ) ), Qt::QueuedConnection ); - - Database::instance()->enqueue( QSharedPointer( cmd ) ); -} - - void PlaylistModel::clear() { @@ -277,15 +257,6 @@ PlaylistModel::trackResolved( bool ) } -void -PlaylistModel::onDataChanged() -{ - TrackModelItem* p = (TrackModelItem*)sender(); - if ( p && p->index.isValid() ) - emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount() - 1 ) ); -} - - void PlaylistModel::onRevisionLoaded( Tomahawk::PlaylistRevision revision ) { diff --git a/src/libtomahawk/playlist/playlistmodel.h b/src/libtomahawk/playlist/playlistmodel.h index 95d4dddaf..01c3ff3b3 100644 --- a/src/libtomahawk/playlist/playlistmodel.h +++ b/src/libtomahawk/playlist/playlistmodel.h @@ -47,14 +47,12 @@ public: explicit PlaylistModel( QObject* parent = 0 ); ~PlaylistModel(); - virtual QMimeData* mimeData ( const QModelIndexList& indexes ) const; + virtual QMimeData* mimeData( const QModelIndexList& indexes ) const; virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ); Tomahawk::playlist_ptr playlist() const { return m_playlist; } virtual void loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEntries = true ); - void loadHistory( const Tomahawk::source_ptr& source, unsigned int amount = 50 ); - bool isTemporary() const; public slots: @@ -86,7 +84,6 @@ protected: void removeFromWaitList( const QString& revisionguid ) { m_waitForRevision.removeAll( revisionguid ); } private slots: - void onDataChanged(); void onRevisionLoaded( Tomahawk::PlaylistRevision revision ); void parsedDroppedTracks( QList ); void trackResolved( bool ); diff --git a/src/libtomahawk/playlist/trackmodel.cpp b/src/libtomahawk/playlist/trackmodel.cpp index e31885612..1d7f6ffcc 100644 --- a/src/libtomahawk/playlist/trackmodel.cpp +++ b/src/libtomahawk/playlist/trackmodel.cpp @@ -88,6 +88,7 @@ TrackModel::columnCount( const QModelIndex& parent ) const { case Short: case ShortWithAvatars: + case Large: return 1; break; @@ -259,14 +260,24 @@ TrackModel::headerData( int section, Qt::Orientation orientation, int role ) con void -TrackModel::getCover( const QModelIndex& index ) +TrackModel::updateDetailedInfo( const QModelIndex& index ) { - if ( style() != TrackModel::Short ) + if ( style() != TrackModel::Short && style() != TrackModel::Large ) + return; + + TrackModelItem* item = itemFromIndex( index ); + if ( item->query().isNull() ) return; - TrackModelItem* item = itemFromIndex( index ); - if ( !item->query().isNull() ) + if ( style() == TrackModel::Short || style() == TrackModel::Large ) + { item->query()->cover( QSize( 0, 0 ) ); + } + + if ( style() == TrackModel::Large ) + { + item->query()->loadSocialActions(); + } } @@ -584,3 +595,12 @@ TrackModel::columnAlignment( int column ) const return Qt::AlignLeft; } } + + +void +TrackModel::onDataChanged() +{ + TrackModelItem* p = (TrackModelItem*)sender(); + if ( p && p->index.isValid() ) + emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount() - 1 ) ); +} diff --git a/src/libtomahawk/playlist/trackmodel.h b/src/libtomahawk/playlist/trackmodel.h index a368c508b..6d76e6aaf 100644 --- a/src/libtomahawk/playlist/trackmodel.h +++ b/src/libtomahawk/playlist/trackmodel.h @@ -36,7 +36,7 @@ Q_OBJECT public: enum TrackItemStyle - { Detailed = 0, Short = 1, ShortWithAvatars = 2 }; + { Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3 }; enum TrackModelRole { StyleRole = Qt::UserRole + 1 }; @@ -98,7 +98,7 @@ public: /// Returns a flat list of all tracks in this model QList< Tomahawk::query_ptr > queries() const; - void getCover( const QModelIndex& index ); + void updateDetailedInfo( const QModelIndex& index ); signals: void repeatModeChanged( Tomahawk::PlaylistInterface::RepeatMode mode ); @@ -134,6 +134,8 @@ protected: TrackModelItem* rootItem() const { return m_rootItem; } private slots: + void onDataChanged(); + void onPlaybackStarted( const Tomahawk::result_ptr& result ); void onPlaybackStopped(); diff --git a/src/libtomahawk/playlist/trackmodelitem.cpp b/src/libtomahawk/playlist/trackmodelitem.cpp index b6e1ce452..18f0c5126 100644 --- a/src/libtomahawk/playlist/trackmodelitem.cpp +++ b/src/libtomahawk/playlist/trackmodelitem.cpp @@ -1,3 +1,4 @@ + /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser @@ -115,4 +116,5 @@ TrackModelItem::setupItem( const Tomahawk::query_ptr& query, TrackModelItem* par connect( query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ), SIGNAL( dataChanged() ) ); connect( query.data(), SIGNAL( resultsChanged() ), SIGNAL( dataChanged() ) ); connect( query.data(), SIGNAL( updated() ), SIGNAL( dataChanged() ) ); + connect( query.data(), SIGNAL( socialActionsLoaded() ), SIGNAL( dataChanged() ) ); } diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index e87f04931..913183044 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -147,15 +147,18 @@ TrackView::setTrackModel( TrackModel* model ) setAcceptDrops( true ); - if ( model->style() == TrackModel::Short || model->style() == TrackModel::ShortWithAvatars ) + switch( model->style() ) { - setHeaderHidden( true ); - setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); - } - else - { - setHeaderHidden( false ); - setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); + case TrackModel::Short: + case TrackModel::ShortWithAvatars: + case TrackModel::Large: + setHeaderHidden( true ); + setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + break; + + default: + setHeaderHidden( false ); + setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); } } @@ -163,7 +166,7 @@ TrackView::setTrackModel( TrackModel* model ) void TrackView::onViewChanged() { - if ( m_model->style() != TrackModel::Short ) // eventual FIXME? + if ( m_model->style() != TrackModel::Short && m_model->style() != TrackModel::Large ) // eventual FIXME? return; if ( m_timer.isActive() ) @@ -196,7 +199,7 @@ TrackView::onScrollTimeout() for ( int i = left.row(); i <= max; i++ ) { - m_model->getCover( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) ); + m_model->updateDetailedInfo( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) ); } } @@ -519,7 +522,7 @@ TrackView::updateHoverIndex( const QPoint& pos ) repaint(); } - if ( !m_model || m_model->style() == TrackModel::Short || m_model->style() == TrackModel::ShortWithAvatars ) + if ( !m_model || m_model->style() != TrackModel::Detailed ) return; if ( idx.column() == TrackModel::Artist || idx.column() == TrackModel::Album ) diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 7b94e4167..60f5a1ea6 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -521,7 +521,7 @@ Query::setAllSocialActions( const QList< SocialAction >& socialActions ) QList< SocialAction > -Query::allSocialActions() +Query::allSocialActions() const { return m_allSocialActions; } @@ -537,7 +537,7 @@ Query::parseSocialActions() { Tomahawk::SocialAction socialAction; socialAction = it.next(); - if ( socialAction.timestamp.toUInt() > highestTimestamp && socialAction.source.toInt() == SourceList::instance()->getLocal()->id() ) + if ( socialAction.timestamp.toUInt() > highestTimestamp && socialAction.source->id() == SourceList::instance()->getLocal()->id() ) { m_currentSocialActions[ socialAction.action.toString() ] = socialAction.value.toBool(); } @@ -584,6 +584,71 @@ Query::setLoved( bool loved ) } +QString +Query::socialActionDescription( const QString& action, DescriptionMode mode ) const +{ + QString desc; + QList< Tomahawk::SocialAction > socialActions = allSocialActions(); + + QStringList actionSources; + int loveTotal = 0; + foreach ( const Tomahawk::SocialAction& sa, socialActions ) + { + if ( sa.action == action ) + { + if ( actionSources.contains( sa.source->friendlyName() ) ) + continue; + actionSources << sa.source->friendlyName(); + loveTotal++; + } + } + + actionSources.clear(); + int loveCounter = 0; + foreach ( const Tomahawk::SocialAction& sa, socialActions ) + { + if ( sa.action == action ) + { + if ( actionSources.contains( sa.source->friendlyName() ) ) + continue; + actionSources << sa.source->friendlyName(); + + if ( ++loveCounter > 3 ) + continue; + else if ( loveCounter > 1 ) + { + if ( loveCounter == loveTotal ) + desc += tr( " and " ); + else + desc += ", "; + } + + if ( sa.source->isLocal() ) + { + if ( loveCounter == 1 ) + desc += "" + tr( "You" ) + ""; + else + desc += "" + tr( "you" ) + ""; + } + else + desc += "" + sa.source->friendlyName() + ""; + } + } + if ( loveCounter > 0 ) + { + if ( loveCounter > 3 ) + desc += " " + tr( "and" ) + " " + tr( "%n other(s)", "", loveCounter - 3 ) + ""; + + if ( mode == Short ) + desc = "" + tr( "%1 people" ).arg( loveCounter ) + ""; + + desc += " " + tr( "loved this track" ); //FIXME: more action descs required + } + + return desc; +} + + #ifndef ENABLE_HEADLESS QPixmap Query::cover( const QSize& size, bool forceLoad ) const diff --git a/src/libtomahawk/query.h b/src/libtomahawk/query.h index 8f4b64194..f4e2c1b74 100644 --- a/src/libtomahawk/query.h +++ b/src/libtomahawk/query.h @@ -48,6 +48,9 @@ friend class ::DatabaseCommand_LoadPlaylistEntries; friend class Pipeline; public: + enum DescriptionMode + { Detailed = 0, Short = 1 }; + static query_ptr get( const QString& artist, const QString& track, const QString& album, const QID& qid = QString(), bool autoResolve = true ); static query_ptr get( const QString& query, const QID& qid ); @@ -114,8 +117,9 @@ public: bool loved(); void loadSocialActions(); - QList< Tomahawk::SocialAction > allSocialActions(); + QList< Tomahawk::SocialAction > allSocialActions() const; void setAllSocialActions( const QList< Tomahawk::SocialAction >& socialActions ); + QString socialActionDescription( const QString& action, DescriptionMode mode ) const; QWeakPointer< Tomahawk::Query > weakRef() { return m_ownRef; } void setWeakRef( QWeakPointer< Tomahawk::Query > weakRef ) { m_ownRef = weakRef; } diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp index 43dad0afd..8f2f267a5 100644 --- a/src/libtomahawk/result.cpp +++ b/src/libtomahawk/result.cpp @@ -43,13 +43,21 @@ Result::get( const QString& url ) return s_results.value( url ); } - result_ptr r = result_ptr( new Result( url ), &QObject::deleteLater ); + result_ptr r = result_ptr( new Result( url ), &Result::deleteLater ); s_results.insert( url, r ); return r; } +bool +Result::isCached( const QString& url ) +{ + QMutexLocker lock( &s_mutex ); + return ( s_results.contains( url ) ); +} + + Result::Result( const QString& url ) : QObject() , m_url( url ) @@ -68,12 +76,21 @@ Result::Result( const QString& url ) Result::~Result() +{ +} + + +void +Result::deleteLater() { QMutexLocker lock( &s_mutex ); + if ( s_results.contains( m_url ) ) { s_results.remove( m_url ); } + + QObject::deleteLater(); } diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h index 2d743e4dd..c2b566269 100644 --- a/src/libtomahawk/result.h +++ b/src/libtomahawk/result.h @@ -41,7 +41,7 @@ struct SocialAction QVariant action; QVariant value; QVariant timestamp; - QVariant source; + Tomahawk::source_ptr source; }; @@ -56,6 +56,7 @@ friend class ::DatabaseCommand_LoadFile; public: static Tomahawk::result_ptr get( const QString& url ); + static bool isCached( const QString& url ); virtual ~Result(); QVariant toVariant() const; @@ -108,6 +109,9 @@ public: unsigned int trackId() const { return m_trackId; } unsigned int fileId() const { return m_fileId; } +public slots: + void deleteLater(); + signals: // emitted when the collection this result comes from is going offline/online: void statusChanged(); @@ -115,7 +119,7 @@ signals: private slots: void onOffline(); void onOnline(); - + private: // private constructor explicit Result( const QString& url ); diff --git a/src/libtomahawk/thirdparty/Qocoa/qsearchfield.cpp b/src/libtomahawk/thirdparty/Qocoa/qsearchfield.cpp index a1da7af8c..ffd45acef 100644 --- a/src/libtomahawk/thirdparty/Qocoa/qsearchfield.cpp +++ b/src/libtomahawk/thirdparty/Qocoa/qsearchfield.cpp @@ -52,14 +52,13 @@ QSearchField::QSearchField(QWidget *parent) : QWidget(parent) setContentsMargins(0, 0, 0, 0); lineEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; }" ); + lineEdit->setMinimumHeight(27); + setFixedHeight(27); #ifdef Q_WS_MAC lineEdit->setContentsMargins(0, 0, 0, 0); - lineEdit->setMinimumHeight(27); - setFixedHeight(27); #else lineEdit->setContentsMargins(2, 2, 2, 2); - lineEdit->setMinimumHeight(27); #endif } diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index ef8008773..10b8e968e 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -41,6 +41,7 @@ #include "tomahawksettings.h" #include "customplaylistview.h" +#include "PlaylistLargeItemDelegate.h" #include "dynamic/widgets/DynamicWidget.h" #include "widgets/welcomewidget.h" @@ -437,7 +438,12 @@ Tomahawk::ViewPage* ViewManager::showTopLovedPage() { if ( !m_topLovedWidget ) - m_topLovedWidget = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget ); + { + CustomPlaylistView* view = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget ); + view->setItemDelegate( new PlaylistLargeItemDelegate( view, view->proxyModel() ) ); + + m_topLovedWidget = view; + } return show( m_topLovedWidget ); } diff --git a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp index 6f133872e..4514bdd85 100644 --- a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.cpp @@ -24,10 +24,10 @@ #include "playlist/albummodel.h" #include "playlist/collectionflatmodel.h" -#include "playlist/playlistmodel.h" +#include "playlist/RecentlyAddedModel.h" +#include "playlist/RecentlyPlayedModel.h" #include "database/database.h" -#include "database/databasecommand_alltracks.h" #include "database/databasecommand_allalbums.h" #include "utils/tomahawkutils.h" @@ -61,24 +61,21 @@ SourceInfoWidget::SourceInfoWidget( const Tomahawk::source_ptr& source, QWidget* ui->historyView->overlay()->setEnabled( false ); - m_recentCollectionModel = new CollectionFlatModel( ui->recentCollectionView ); - m_recentCollectionModel->setStyle( TrackModel::Short ); - ui->recentCollectionView->setTrackModel( m_recentCollectionModel ); + m_recentTracksModel = new RecentlyAddedModel( source, ui->recentCollectionView ); + m_recentTracksModel->setStyle( TrackModel::Short ); + ui->recentCollectionView->setTrackModel( m_recentTracksModel ); ui->recentCollectionView->sortByColumn( TrackModel::Age, Qt::DescendingOrder ); - m_historyModel = new PlaylistModel( ui->historyView ); + m_historyModel = new RecentlyPlayedModel( source, ui->historyView ); m_historyModel->setStyle( TrackModel::Short ); ui->historyView->setPlaylistModel( m_historyModel ); - m_historyModel->loadHistory( source, 25 ); m_recentAlbumModel = new AlbumModel( ui->recentAlbumView ); ui->recentAlbumView->setAlbumModel( m_recentAlbumModel ); ui->recentAlbumView->proxyModel()->sort( -1 ); onCollectionChanged(); - connect( source->collection().data(), SIGNAL( changed() ), SLOT( onCollectionChanged() ) ); - connect( source.data(), SIGNAL( playbackFinished( Tomahawk::query_ptr ) ), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ) ); m_title = tr( "New Additions" ); if ( source->isLocal() ) @@ -103,7 +100,6 @@ SourceInfoWidget::~SourceInfoWidget() void SourceInfoWidget::onCollectionChanged() { - loadTracks(); loadRecentAdditions(); } @@ -115,36 +111,6 @@ SourceInfoWidget::loadRecentAdditions() } -void -SourceInfoWidget::loadTracks() -{ - DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_source->collection() ); - cmd->setLimit( 250 ); - cmd->setSortOrder( DatabaseCommand_AllTracks::ModificationTime ); - cmd->setSortDescending( true ); - - connect( cmd, SIGNAL( tracks( QList, QVariant ) ), - SLOT( onLoadedTrackHistory( QList ) ), Qt::QueuedConnection ); - - Database::instance()->enqueue( QSharedPointer( cmd ) ); -} - - -void -SourceInfoWidget::onLoadedTrackHistory( const QList& queries ) -{ - m_recentCollectionModel->clear(); - m_recentCollectionModel->append( queries ); -} - - -void -SourceInfoWidget::onPlaybackFinished( const Tomahawk::query_ptr& query ) -{ - m_historyModel->insert( query, 0 ); -} - - void SourceInfoWidget::changeEvent( QEvent* e ) { diff --git a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h index eb1817aba..73b8fa9eb 100644 --- a/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h +++ b/src/libtomahawk/widgets/infowidgets/sourceinfowidget.h @@ -28,7 +28,8 @@ class AlbumModel; class CollectionFlatModel; -class PlaylistModel; +class RecentlyAddedModel; +class RecentlyPlayedModel; namespace Ui { @@ -58,18 +59,15 @@ protected: void changeEvent( QEvent* e ); private slots: - void loadTracks(); void loadRecentAdditions(); void onCollectionChanged(); - void onPlaybackFinished( const Tomahawk::query_ptr& query ); - void onLoadedTrackHistory( const QList& queries ); private: Ui::SourceInfoWidget *ui; - CollectionFlatModel* m_recentCollectionModel; - PlaylistModel* m_historyModel; + RecentlyAddedModel* m_recentTracksModel; + RecentlyPlayedModel* m_historyModel; AlbumModel* m_recentAlbumModel; Tomahawk::source_ptr m_source; diff --git a/src/libtomahawk/widgets/welcomewidget.cpp b/src/libtomahawk/widgets/welcomewidget.cpp index 145771d1c..928524d86 100644 --- a/src/libtomahawk/widgets/welcomewidget.cpp +++ b/src/libtomahawk/widgets/welcomewidget.cpp @@ -29,16 +29,14 @@ #include "audio/audioengine.h" #include "playlist/albummodel.h" -#include "playlist/playlistmodel.h" +#include "playlist/RecentlyPlayedModel.h" #include "widgets/overlaywidget.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" #include "dynamic/GeneratorInterface.h" #include "RecentlyPlayedPlaylistsModel.h" -#define HISTORY_TRACK_ITEMS 25 #define HISTORY_PLAYLIST_ITEMS 10 -#define HISTORY_RESOLVING_TIMEOUT 2500 using namespace Tomahawk; @@ -72,7 +70,7 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->playlistWidget->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); updatePlaylists(); - m_tracksModel = new PlaylistModel( ui->tracksView ); + m_tracksModel = new RecentlyPlayedModel( source_ptr(), ui->tracksView ); m_tracksModel->setStyle( TrackModel::ShortWithAvatars ); ui->tracksView->overlay()->setEnabled( false ); ui->tracksView->setPlaylistModel( m_tracksModel ); @@ -81,9 +79,6 @@ WelcomeWidget::WelcomeWidget( QWidget* parent ) ui->additionsView->setAlbumModel( m_recentAlbumsModel ); ui->additionsView->proxyModel()->sort( -1 ); - m_timer = new QTimer( this ); - connect( m_timer, SIGNAL( timeout() ), SLOT( checkQueries() ) ); - connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); connect( ui->playlistWidget, SIGNAL( activated( QModelIndex ) ), SLOT( onPlaylistActivated( QModelIndex ) ) ); @@ -100,7 +95,6 @@ WelcomeWidget::~WelcomeWidget() void WelcomeWidget::loadData() { - m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true ); } @@ -129,13 +123,18 @@ WelcomeWidget::isBeingPlayed() const void WelcomeWidget::onSourcesReady() { - m_tracksModel->loadHistory( Tomahawk::source_ptr(), HISTORY_TRACK_ITEMS ); - foreach ( const source_ptr& source, SourceList::instance()->sources() ) onSourceAdded( source ); } +void +WelcomeWidget::onSourceAdded( const Tomahawk::source_ptr& source ) +{ + connect( source->collection().data(), SIGNAL( changed() ), SLOT( updateRecentAdditions() ), Qt::UniqueConnection ); +} + + void WelcomeWidget::updateRecentAdditions() { @@ -157,66 +156,6 @@ WelcomeWidget::updatePlaylists() } -void -WelcomeWidget::onSourceAdded( const Tomahawk::source_ptr& source ) -{ - connect( source->collection().data(), SIGNAL( changed() ), SLOT( updateRecentAdditions() ), Qt::UniqueConnection ); - connect( source.data(), SIGNAL( playbackFinished( Tomahawk::query_ptr ) ), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::UniqueConnection ); -} - - -void -WelcomeWidget::checkQueries() -{ - if ( m_timer->isActive() ) - m_timer->stop(); - - m_tracksModel->ensureResolved(); -} - - -void -WelcomeWidget::onPlaybackFinished( const Tomahawk::query_ptr& query ) -{ - int count = m_tracksModel->trackCount(); - unsigned int playtime = query->playedBy().second; - - if ( count ) - { - TrackModelItem* oldestItem = m_tracksModel->itemFromIndex( m_tracksModel->index( count - 1, 0, QModelIndex() ) ); - if ( oldestItem->query()->playedBy().second >= playtime ) - return; - - TrackModelItem* youngestItem = m_tracksModel->itemFromIndex( m_tracksModel->index( 0, 0, QModelIndex() ) ); - if ( youngestItem->query()->playedBy().second <= playtime ) - m_tracksModel->insert( query, 0 ); - else - { - for ( int i = 0; i < count - 1; i++ ) - { - TrackModelItem* item1 = m_tracksModel->itemFromIndex( m_tracksModel->index( i, 0, QModelIndex() ) ); - TrackModelItem* item2 = m_tracksModel->itemFromIndex( m_tracksModel->index( i + 1, 0, QModelIndex() ) ); - - if ( item1->query()->playedBy().second >= playtime && item2->query()->playedBy().second <= playtime ) - { - m_tracksModel->insert( query, i + 1 ); - break; - } - } - } - } - else - m_tracksModel->insert( query, 0 ); - - if ( m_tracksModel->trackCount() > HISTORY_TRACK_ITEMS ) - m_tracksModel->remove( HISTORY_TRACK_ITEMS ); - - if ( m_timer->isActive() ) - m_timer->stop(); - m_timer->start( HISTORY_RESOLVING_TIMEOUT ); -} - - void WelcomeWidget::onPlaylistActivated( const QModelIndex& item ) { diff --git a/src/libtomahawk/widgets/welcomewidget.h b/src/libtomahawk/widgets/welcomewidget.h index dc4e9250c..6b5c7a929 100644 --- a/src/libtomahawk/widgets/welcomewidget.h +++ b/src/libtomahawk/widgets/welcomewidget.h @@ -34,7 +34,7 @@ #include "dllmacro.h" class AlbumModel; -class PlaylistModel; +class RecentlyPlayedModel; class OverlayWidget; namespace Ui @@ -106,21 +106,17 @@ public slots: void updateRecentAdditions(); void loadData(); + private slots: void onSourcesReady(); void onSourceAdded( const Tomahawk::source_ptr& source ); void onPlaylistActivated( const QModelIndex& ); - void onPlaybackFinished( const Tomahawk::query_ptr& query ); - - void checkQueries(); private: Ui::WelcomeWidget *ui; - PlaylistModel* m_tracksModel; + RecentlyPlayedModel* m_tracksModel; AlbumModel* m_recentAlbumsModel; - - QTimer* m_timer; }; #endif // WELCOMEWIDGET_H diff --git a/src/libtomahawk/widgets/whatshotwidget.cpp b/src/libtomahawk/widgets/whatshotwidget.cpp index c4c9ecfb4..b116aaea0 100644 --- a/src/libtomahawk/widgets/whatshotwidget.cpp +++ b/src/libtomahawk/widgets/whatshotwidget.cpp @@ -35,6 +35,7 @@ #include "dynamic/GeneratorInterface.h" #include "playlist/playlistmodel.h" #include "playlist/treeproxymodel.h" +#include "playlist/PlaylistChartItemDelegate.h" #include "widgets/overlaywidget.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" @@ -81,6 +82,8 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent ) ui->tracksViewLeft->overlay()->setEnabled( false ); ui->tracksViewLeft->setHeaderHidden( true ); ui->tracksViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + ui->tracksViewLeft->setItemDelegate( new PlaylistChartItemDelegate( ui->tracksViewLeft, ui->tracksViewLeft->proxyModel() ) ); + ui->tracksViewLeft->setUniformRowHeights( false ); TreeProxyModel* artistsProxy = new TreeProxyModel( ui->artistsViewLeft ); artistsProxy->setFilterCaseSensitivity( Qt::CaseInsensitive ); @@ -289,7 +292,7 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat connect( loader, SIGNAL( tracks( Tomahawk::ChartDataLoader*, QList< Tomahawk::query_ptr > ) ), this, SLOT( chartTracksLoaded( Tomahawk::ChartDataLoader*, QList< Tomahawk::query_ptr > ) ) ); PlaylistModel* trackModel = new PlaylistModel( ui->tracksViewLeft ); - trackModel->setStyle( TrackModel::Short ); + trackModel->setStyle( TrackModel::Large ); m_trackModels[ chartId ] = trackModel; diff --git a/src/sourcetree/items/sourceitem.cpp b/src/sourcetree/items/sourceitem.cpp index 82a977f7c..d6a9a37f1 100644 --- a/src/sourcetree/items/sourceitem.cpp +++ b/src/sourcetree/items/sourceitem.cpp @@ -27,6 +27,11 @@ #include "utils/logger.h" #include "widgets/SocialPlaylistWidget.h" #include "playlist/customplaylistview.h" +#include "playlist/collectionview.h" +#include "playlist/playlistview.h" +#include "playlist/RecentlyAddedModel.h" +#include "playlist/RecentlyPlayedModel.h" +#include "playlist/PlaylistLargeItemDelegate.h" #include "source.h" #include "sourcelist.h" @@ -40,12 +45,14 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw , m_playlists( 0 ) , m_stations( 0 ) , m_latchedOn( false ) - , m_sourceInfoItem( 0 ) + , m_sourceInfoItem( 0 ) , m_coolPlaylistsItem( 0 ) , m_collectionPage( 0 ) , m_sourceInfoPage( 0 ) , m_coolPlaylistsPage( 0 ) , m_lovedTracksPage( 0 ) + , m_latestAdditionsPage( 0 ) + , m_recentPlaysPage( 0 ) , m_whatsHotPage( 0 ) { if ( m_source.isNull() ) @@ -54,20 +61,31 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw return; } - m_lovedTracksItem = new GenericPageItem( model(), this, tr( "Loved Tracks" ), QIcon( RESPATH "images/loved_playlist.png" ), - boost::bind( &SourceItem::lovedTracksClicked, this ), - boost::bind( &SourceItem::getLovedTracksPage, this ) ); - m_lovedTracksItem->setSortValue( -250 ); - m_collectionItem = new GenericPageItem( model(), this, tr( "Collection" ), QIcon( RESPATH "images/drop-song.png" ), //FIXME different icon boost::bind( &SourceItem::collectionClicked, this ), boost::bind( &SourceItem::getCollectionPage, this ) ); - m_collectionItem->setSortValue( -350 ); - m_sourceInfoItem = new GenericPageItem( model(), this, tr( "New Additions" ), QIcon( RESPATH "images/new-additions.png" ), +/* m_sourceInfoItem = new GenericPageItem( model(), this, tr( "New Additions" ), QIcon( RESPATH "images/new-additions.png" ), boost::bind( &SourceItem::sourceInfoClicked, this ), - boost::bind( &SourceItem::getSourceInfoPage, this ) ); - m_sourceInfoItem->setSortValue( -300 ); + boost::bind( &SourceItem::getSourceInfoPage, this ) );*/ + + m_latestAdditionsItem = new GenericPageItem( model(), this, tr( "Latest Additions" ), QIcon( RESPATH "images/new-additions.png" ), + boost::bind( &SourceItem::latestAdditionsClicked, this ), + boost::bind( &SourceItem::getLatestAdditionsPage, this ) ); + + m_recentPlaysItem = new GenericPageItem( model(), this, tr( "Recently Played" ), QIcon( RESPATH "images/new-additions.png" ), + boost::bind( &SourceItem::recentPlaysClicked, this ), + boost::bind( &SourceItem::getRecentPlaysPage, this ) ); + + m_lovedTracksItem = new GenericPageItem( model(), this, tr( "Loved Tracks" ), QIcon( RESPATH "images/loved_playlist.png" ), + boost::bind( &SourceItem::lovedTracksClicked, this ), + boost::bind( &SourceItem::getLovedTracksPage, this ) ); + + m_collectionItem->setSortValue( -350 ); +// m_sourceInfoItem->setSortValue( -300 ); + m_latestAdditionsItem->setSortValue( -250 ); + m_recentPlaysItem->setSortValue( -200 ); + m_lovedTracksItem->setSortValue( -150 ); // create category items if there are playlists to show, or stations to show QList< playlist_ptr > playlists = source->collection()->playlists(); @@ -86,7 +104,7 @@ SourceItem::SourceItem( SourcesModel* mdl, SourceTreeItem* parent, const Tomahaw onStationsAdded( stations ); } - if( ViewManager::instance()->pageForCollection( source->collection() ) ) + if ( ViewManager::instance()->pageForCollection( source->collection() ) ) model()->linkSourceItemToPage( this, ViewManager::instance()->pageForCollection( source->collection() ) ); m_defaultAvatar = TomahawkUtils::createAvatarFrame( QPixmap( RESPATH "images/user-avatar.png" ) ); @@ -284,7 +302,7 @@ SourceItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p ) for( int i = 0; i < curCount; i++ ) { PlaylistItem* pl = qobject_cast< PlaylistItem* >( parent->children().at( i ) ); - if( pl && pl->playlist() == p ) + if ( pl && pl->playlist() == p ) { parent->beginRowsRemoved( i, i ); parent->removeChild( pl ); @@ -295,20 +313,20 @@ SourceItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p ) } } - if( ( parent == m_playlists || parent == m_stations ) && + if ( ( parent == m_playlists || parent == m_stations ) && parent->children().isEmpty() && parent->parent() ) // Don't leave an empty Playlist or Station category { int idx = parent->parent()->children().indexOf( parent ); - if( idx < 0 ) + if ( idx < 0 ) return; parent->parent()->beginRowsRemoved( idx, idx ); parent->parent()->removeChild( parent ); parent->parent()->endRowsRemoved(); - if( parent == m_playlists ) + if ( parent == m_playlists ) m_playlists = 0; - else if( parent == m_stations ) + else if ( parent == m_stations ) m_stations = 0; delete parent; } @@ -318,12 +336,10 @@ SourceItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p ) void SourceItem::onPlaylistsAdded( const QList< playlist_ptr >& playlists ) { -// qDebug() << Q_FUNC_INFO << m_source->friendlyName() << playlists.count(); - - if( playlists.isEmpty() ) + if ( playlists.isEmpty() ) return; - if( !m_playlists ) + if ( !m_playlists ) { // add the category too int cur = children().count(); @@ -337,19 +353,18 @@ SourceItem::onPlaylistsAdded( const QList< playlist_ptr >& playlists ) int from = m_playlists->children().count() - addOffset; m_playlists->beginRowsAdded( from, from + playlists.count() - 1 ); - foreach( const playlist_ptr& p, playlists ) + foreach ( const playlist_ptr& p, playlists ) { PlaylistItem* plItem = new PlaylistItem( model(), m_playlists, p, m_playlists->children().count() - addOffset ); -// qDebug() << "Playlist added:" << p->title() << p->creator() << p->info(); p->loadRevision(); items << plItem; - if( m_source->isLocal() ) + if ( m_source->isLocal() ) connect( p.data(), SIGNAL( aboutToBeDeleted( Tomahawk::playlist_ptr ) ), - SLOT( onPlaylistDeleted( Tomahawk::playlist_ptr ) ), Qt::QueuedConnection ); + SLOT( onPlaylistDeleted( Tomahawk::playlist_ptr ) ), Qt::QueuedConnection ); else connect( p.data(), SIGNAL( deleted( Tomahawk::playlist_ptr ) ), - SLOT( onPlaylistDeleted( Tomahawk::playlist_ptr ) ), Qt::QueuedConnection ); + SLOT( onPlaylistDeleted( Tomahawk::playlist_ptr ) ), Qt::QueuedConnection ); } m_playlists->endRowsAdded(); @@ -357,7 +372,7 @@ SourceItem::onPlaylistsAdded( const QList< playlist_ptr >& playlists ) void -SourceItem::onPlaylistDeleted( const playlist_ptr& playlist ) +SourceItem::onPlaylistDeleted( const playlist_ptr& playlist ) { playlistDeletedInternal( m_playlists, playlist ); } @@ -366,10 +381,10 @@ SourceItem::onPlaylistDeleted( const playlist_ptr& playlist ) void SourceItem::onAutoPlaylistsAdded( const QList< dynplaylist_ptr >& playlists ) { - if( playlists.isEmpty() ) + if ( playlists.isEmpty() ) return; - if( !m_playlists ) + if ( !m_playlists ) { // add the category too int cur = children().count(); @@ -385,8 +400,8 @@ SourceItem::onAutoPlaylistsAdded( const QList< dynplaylist_ptr >& playlists ) void SourceItem::onAutoPlaylistDeleted( const dynplaylist_ptr& playlist ) { - if( !m_playlists ) - qDebug() << "NO playlist category item for a deleting playlist.."; + if ( !m_playlists ) + qDebug() << "NO playlist category item for a deleting playlist..."; playlistDeletedInternal( m_playlists, playlist ); } @@ -395,10 +410,10 @@ SourceItem::onAutoPlaylistDeleted( const dynplaylist_ptr& playlist ) void SourceItem::onStationsAdded( const QList< dynplaylist_ptr >& stations ) { - if( stations.isEmpty() ) + if ( stations.isEmpty() ) return; - if( !m_stations ) + if ( !m_stations ) { // add the category too int cur = children().count(); @@ -428,7 +443,7 @@ SourceItem::requestExpanding() ViewPage* SourceItem::sourceInfoClicked() { - if( m_source.isNull() ) + if ( m_source.isNull() ) return 0; m_sourceInfoPage = ViewManager::instance()->show( m_source ); @@ -446,7 +461,7 @@ SourceItem::getSourceInfoPage() const ViewPage* SourceItem::collectionClicked() { - if( m_source.isNull() ) + if ( m_source.isNull() ) return 0; m_collectionPage = ViewManager::instance()->show( m_source->collection() ); @@ -486,7 +501,12 @@ ViewPage* SourceItem::lovedTracksClicked() { if ( !m_lovedTracksPage ) - m_lovedTracksPage = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::TopLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() ); + { + CustomPlaylistView* view = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::TopLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() ); + view->setItemDelegate( new PlaylistLargeItemDelegate( view, view->proxyModel() ) ); + + m_lovedTracksPage = view; + } ViewManager::instance()->show( m_lovedTracksPage ); return m_lovedTracksPage; @@ -498,3 +518,64 @@ SourceItem::getLovedTracksPage() const { return m_lovedTracksPage; } + + +ViewPage* +SourceItem::latestAdditionsClicked() +{ + if ( !m_latestAdditionsPage ) + { + CollectionView* cv = new CollectionView( ViewManager::instance()->widget() ); + cv->setFrameShape( QFrame::NoFrame ); + cv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + RecentlyAddedModel* raModel = new RecentlyAddedModel( m_source, cv ); + raModel->setStyle( TrackModel::Large ); + + cv->setItemDelegate( new PlaylistLargeItemDelegate( cv, cv->proxyModel() ) ); + cv->setTrackModel( raModel ); + cv->sortByColumn( TrackModel::Age, Qt::DescendingOrder ); + + m_latestAdditionsPage = cv; + } + + ViewManager::instance()->show( m_latestAdditionsPage ); + return m_latestAdditionsPage; +} + + +ViewPage* +SourceItem::getLatestAdditionsPage() const +{ + return m_latestAdditionsPage; +} + + +ViewPage* +SourceItem::recentPlaysClicked() +{ + if ( !m_recentPlaysPage ) + { + PlaylistView* pv = new PlaylistView( ViewManager::instance()->widget() ); + pv->setFrameShape( QFrame::NoFrame ); + pv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + RecentlyPlayedModel* raModel = new RecentlyPlayedModel( m_source, pv ); + raModel->setStyle( TrackModel::Large ); + + pv->setItemDelegate( new PlaylistLargeItemDelegate( pv, pv->proxyModel() ) ); + pv->setPlaylistModel( raModel ); + + m_recentPlaysPage = pv; + } + + ViewManager::instance()->show( m_recentPlaysPage ); + return m_recentPlaysPage; +} + + +ViewPage* +SourceItem::getRecentPlaysPage() const +{ + return m_recentPlaysPage; +} diff --git a/src/sourcetree/items/sourceitem.h b/src/sourcetree/items/sourceitem.h index 4aa84443d..cc9c82a2d 100644 --- a/src/sourcetree/items/sourceitem.h +++ b/src/sourcetree/items/sourceitem.h @@ -80,6 +80,12 @@ private slots: Tomahawk::ViewPage* lovedTracksClicked(); Tomahawk::ViewPage* getLovedTracksPage() const; + Tomahawk::ViewPage* latestAdditionsClicked(); + Tomahawk::ViewPage* getLatestAdditionsPage() const; + + Tomahawk::ViewPage* recentPlaysClicked(); + Tomahawk::ViewPage* getRecentPlaysPage() const; + private: void playlistsAddedInternal( SourceTreeItem* parent, const QList< Tomahawk::dynplaylist_ptr >& playlists ); template< typename T > @@ -97,11 +103,15 @@ private: GenericPageItem* m_sourceInfoItem; GenericPageItem* m_coolPlaylistsItem; GenericPageItem* m_lovedTracksItem; + GenericPageItem* m_latestAdditionsItem; + GenericPageItem* m_recentPlaysItem; Tomahawk::ViewPage* m_collectionPage; Tomahawk::ViewPage* m_sourceInfoPage; Tomahawk::ViewPage* m_coolPlaylistsPage; Tomahawk::ViewPage* m_lovedTracksPage; + Tomahawk::ViewPage* m_latestAdditionsPage; + Tomahawk::ViewPage* m_recentPlaysPage; Tomahawk::ViewPage* m_whatsHotPage; }; diff --git a/src/tomahawktrayicon.cpp b/src/tomahawktrayicon.cpp index b8d927ec2..2ef75067c 100644 --- a/src/tomahawktrayicon.cpp +++ b/src/tomahawktrayicon.cpp @@ -35,7 +35,7 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent ) , m_currentAnimationFrame( 0 ) , m_showWindowAction( 0 ) { - QIcon icon( RESPATH "icons/tomahawk-icon-128x128.png" ); + QIcon icon( RESPATH "icons/tomahawk-icon-128x128-grayscale.png" ); setIcon( icon ); refreshToolTip();