You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amarok/amarok/src/tracktooltip.cpp

352 lines
12 KiB

/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
/*
tracktooltip.cpp
begin: Tue 10 Feb 2004
copyright: (C) 2004 by Christian Muehlhaeuser
email: chris@chris.de
copyright: (C) 2005 by Gábor Lehel
email: illissius@gmail.com
*/
#include "amarok.h"
#include "app.h"
#include "amarokconfig.h"
#include "debug.h"
#include "metabundle.h"
#include "moodbar.h"
#include "collectiondb.h"
#include "playlist.h"
#include "playlistitem.h"
#include "podcastbundle.h"
#include <tqapplication.h>
#include <kstandarddirs.h>
#include "tracktooltip.h"
TrackToolTip *TrackToolTip::instance()
{
static TrackToolTip tip;
return &tip;
}
TrackToolTip::TrackToolTip(): m_haspos( false )
{
connect( CollectionDB::instance(), TQT_SIGNAL( coverChanged( const TQString &, const TQString & ) ),
this, TQT_SLOT( slotCoverChanged( const TQString &, const TQString & ) ) );
connect( CollectionDB::instance(), TQT_SIGNAL( imageFetched( const TQString & ) ),
this, TQT_SLOT( slotImageChanged( const TQString & ) ) );
connect( Playlist::instance(), TQT_SIGNAL( columnsChanged() ), this, TQT_SLOT( slotUpdate() ) );
connect( CollectionDB::instance(), TQT_SIGNAL( scoreChanged( const TQString&, float ) ),
this, TQT_SLOT( slotUpdate( const TQString& ) ) );
connect( CollectionDB::instance(), TQT_SIGNAL( ratingChanged( const TQString&, int ) ),
this, TQT_SLOT( slotUpdate( const TQString& ) ) );
// Only connect this once -- m_tags exists for the lifetime of this instance
connect( &m_tags.moodbar(), TQT_SIGNAL( jobEvent( int ) ),
TQT_SLOT( slotMoodbarEvent() ) );
// This is so the moodbar can be re-rendered when AlterMood is changed
connect( App::instance(), TQT_SIGNAL( moodbarPrefs( bool, bool, int, bool ) ),
TQT_SLOT( slotMoodbarEvent() ) );
clear();
}
void TrackToolTip::addToWidget( TQWidget *widget )
{
if( widget && !m_widgets.containsRef( widget ) )
{
m_widgets.append( widget );
Amarok::ToolTip::add( this, widget );
}
}
void TrackToolTip::removeFromWidget( TQWidget *widget )
{
if( widget && m_widgets.containsRef( widget ) )
{
Amarok::ToolTip::remove( widget );
m_widgets.removeRef( widget );
}
}
#define MOODBAR_WIDTH 150
void TrackToolTip::setTrack( const MetaBundle &tags, bool force )
{
if( force || m_tags != tags || m_tags.url() != tags.url() )
{
m_haspos = false;
m_tooltip = TQString();
TQStringList left, right;
const TQString tableRow = "<tr><td width=70 align=right>%1:</td><td align=left>%2</td></tr>";
TQString filename = "", title = ""; //special case these, put the first one encountered on top
Playlist *playlist = Playlist::instance();
const int n = playlist->numVisibleColumns();
for( int i = 0; i < n; ++i )
{
const int column = playlist->mapToLogicalColumn( i );
if( column == PlaylistItem::Score )
{
const float score = CollectionDB::instance()->getSongPercentage( tags.url().path() );
if( score > 0.f )
{
right << TQString::number( score, 'f', 2 ); // 2 digits after decimal point
left << playlist->columnText( column );
}
}
else if( column == PlaylistItem::Rating )
{
const int rating = CollectionDB::instance()->getSongRating( tags.url().path() );
if( rating > 0 )
{
TQString s;
for( int i = 0; i < rating / 2; ++i )
s += TQString( "<img src=\"%1\" height=\"%2\" width=\"%3\">" )
.tqarg( locate( "data", "amarok/images/star.png" ) )
.tqarg( TQFontMetrics( TQToolTip::font() ).height() )
.tqarg( TQFontMetrics( TQToolTip::font() ).height() );
if( rating % 2 )
s += TQString( "<img src=\"%1\" height=\"%2\" width=\"%3\">" )
.tqarg( locate( "data", "amarok/images/smallstar.png" ) )
.tqarg( TQFontMetrics( TQToolTip::font() ).height() )
.tqarg( TQFontMetrics( TQToolTip::font() ).height() );
right << s;
left << playlist->columnText( column );
}
}
else if( column == PlaylistItem::Mood )
{
if( !AmarokConfig::showMoodbar() )
continue;
m_tags.moodbar().load();
switch( tags.moodbar_const().state() )
{
case Moodbar::JobQueued:
case Moodbar::JobRunning:
right << tags.prettyText( column );
left << playlist->columnText( column );
break;
case Moodbar::Loaded:
{
// Ok so this is a hack, but it works quite well.
// Save an image in the user's home directory just so
// it can be referenced in an <img> tag. Store which
// moodbar is saved in m_moodbarURL so we don't have
// to re-save it every second.
left << playlist->columnText( column );
TQString filename = ::locateLocal( "data",
"amarok/mood_tooltip.png" );
int height = TQFontMetrics( TQToolTip::font() ).height() - 2;
if( m_moodbarURL != tags.url().url() )
{
TQPixmap moodbar
= const_cast<MetaBundle&>( tags ).moodbar().draw(
MOODBAR_WIDTH, height );
moodbar.save( filename, "PNG", 100 );
m_moodbarURL = tags.url().url();
}
right << TQString( "<img src=\"%1\" height=\"%2\" width=\"%3\">" )
.tqarg( filename ).tqarg( height ).tqarg( MOODBAR_WIDTH );
}
break;
default:
// no tag
break;
}
}
else if( column == PlaylistItem::PlayCount )
{
const int count = CollectionDB::instance()->getPlayCount( tags.url().path() );
if( count > 0 )
{
right << TQString::number( count );
left << playlist->columnText( column );
}
}
else if( column == PlaylistItem::LastPlayed )
{
const uint lastPlayed = CollectionDB::instance()->getLastPlay( tags.url().path() ).toTime_t();
right << Amarok::verboseTimeSince( lastPlayed );
left << playlist->columnText( column );
}
else if( column == PlaylistItem::Filename && title.isEmpty() )
filename = tags.prettyText( column );
else if( column == PlaylistItem::Title && filename.isEmpty() )
title = tags.prettyText( column );
else if( column != PlaylistItem::Length )
{
const TQString tag = tags.prettyText( column );
if( !tag.isEmpty() )
{
right << tag;
left << playlist->columnText( column );
}
}
}
if( !filename.isEmpty() )
{
right.prepend( filename );
left.prepend( playlist->columnText( PlaylistItem::Filename ) );
}
else if( !title.isEmpty() )
{
right.prepend( title );
left.prepend( playlist->columnText( PlaylistItem::Title ) );
}
if( tags.length() > 0 ) //special case this too, always on the bottom
{
m_haspos = true;
right << "%9 / " + tags.prettyLength();
left << playlist->columnText( PlaylistItem::Length );
}
//NOTE it seems to be necessary to <center> each element indivdually
m_tooltip += "<center><b>Amarok</b></center><table cellpadding='2' cellspacing='2' align='center'><tr>";
m_tooltip += "%1"; //the cover gets substituted in, in tooltip()
m_cover = CollectionDB::instance()->podcastImage( tags, true );
if( m_cover.isEmpty() || m_cover.contains( "nocover" ) != -1 )
{
m_cover = CollectionDB::instance()->albumImage( tags, true, 150 );
if ( m_cover == CollectionDB::instance()->notAvailCover() )
m_cover = TQString();
}
m_tooltip += "<td><table cellpadding='0' cellspacing='0'>";
if (tags.title().isEmpty() || tags.artist().isEmpty())
// no title or no artist, so we add prettyTitle
m_tooltip += TQString ("<tr><td align=center colspan='2'>%1</td></tr>")
.tqarg(tags.veryNiceTitle());
for( uint x = 0; x < left.count(); ++x )
if ( !right[x].isEmpty() )
m_tooltip += tableRow.tqarg( left[x] ).tqarg( right[x] );
m_tooltip += "</table></td>";
m_tooltip += "</tr></table></center>";
m_tags = tags;
updateWidgets();
}
}
void TrackToolTip::setPos( int pos )
{
if( m_pos != pos )
{
m_pos = pos;
updateWidgets();
}
}
void TrackToolTip::clear()
{
m_pos = 0;
m_cover = TQString();
m_tooltip = i18n( "Amarok - rediscover your music" );
m_tags = MetaBundle();
m_tags.setUrl( KURL() );
updateWidgets();
}
TQPair<TQString, TQRect> TrackToolTip::toolTipText( TQWidget*, const TQPoint& ) const
{
return TQPair<TQString, TQRect>( tooltip(), TQRect() );
}
void TrackToolTip::slotCoverChanged( const TQString &artist, const TQString &album )
{
if( artist == m_tags.artist() && album == m_tags.album() )
{
m_cover = CollectionDB::instance()->albumImage( m_tags, true, 150 );
if( m_cover == CollectionDB::instance()->notAvailCover() )
m_cover = TQString();
updateWidgets();
}
}
void TrackToolTip::slotImageChanged( const TQString &remoteURL )
{
PodcastEpisodeBundle peb;
if( CollectionDB::instance()->getPodcastEpisodeBundle( m_tags.url().url(), &peb ) )
{
PodcastChannelBundle pcb;
if( CollectionDB::instance()->getPodcastChannelBundle( peb.parent().url(), &pcb ) )
{
if( pcb.imageURL().url() == remoteURL )
{
m_cover = CollectionDB::instance()->podcastImage( remoteURL );
if( m_cover == CollectionDB::instance()->notAvailCover() )
m_cover = TQString();
updateWidgets();
}
}
}
}
void TrackToolTip::slotUpdate( const TQString &url )
{
if( url.isNull() || url == m_tags.url().path() )
setTrack( m_tags, true );
}
void
TrackToolTip::slotMoodbarEvent( void )
{
// Clear this so the moodbar gets redrawn
m_moodbarURL = TQString();
// Reset the moodbar in case AlterMood has changed
m_tags.moodbar().reset();
setTrack( m_tags, true );
}
TQString TrackToolTip::tooltip() const
{
TQString tip = m_tooltip;;
if( !m_tags.isEmpty() )
{
if( !m_cover.isEmpty() )
tip = tip.tqarg( TQString( "<td><table cellpadding='0' cellspacing='0'><tr><td>"
"<img src='%1'>"
"</td></tr></table></td>" ).tqarg( m_cover ) );
else
tip = tip.tqarg("");
if( m_haspos )
tip = tip.tqarg( MetaBundle::prettyLength( m_pos / 1000, true ) );
}
return tip;
}
void TrackToolTip::updateWidgets()
{
Amarok::ToolTip::updateTip();
}
#include "tracktooltip.moc"