Amarok – versatile and easy to use audio player
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/osd.cpp

1016 lines
32 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.
*
* osd.cpp: Shows some text in a pretty way independent to the WM
* begin: Fre Sep 26 2003
* copyright: (C) 2004 Christian Muehlhaeuser <chris@chris.de>
* (C) 2004-2006 Seb Ruiz <me@sebruiz.net>
* (C) 2004, 2005 Max Howell
* (C) 2005 Gábor Lehel <illissius@gmail.com>
*/
#include "amarok.h"
#include "amarokconfig.h"
#include "collectiondb.h" //for albumCover location
#include "debug.h"
#include "enginecontroller.h"
#include "osd.h"
#include "playlist.h" //if osdUsePlaylistColumns()
#include "playlistitem.h" //ditto
#include "podcastbundle.h"
#include "qstringx.h"
#include "starmanager.h"
#include <kapplication.h>
#include <kpixmap.h>
#include <kpixmapeffect.h>
#include <kstandarddirs.h> //locate
#include <tqbitmap.h>
#include <tqpainter.h>
#include <tqpixmap.h>
#include <tqregexp.h>
#include <tqtimer.h>
#include <tqvaluevector.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
namespace ShadowEngine
{
TQImage makeShadow( const TQPixmap &textPixmap, const TQColor &bgColor );
}
#define MOODBAR_HEIGHT 20
OSDWidget::OSDWidget( TQWidget *parent, const char *name )
: TQWidget( parent, name, WType_TopLevel | WNoAutoErase | WStyle_Customize | WX11BypassWM | WStyle_StaysOnTop )
, m_duration( 2000 )
, m_timer( new TQTimer( this ) )
, m_tqalignment( Middle )
, m_screen( 0 )
, m_y( MARGIN )
, m_drawShadow( false )
, m_translucency( false )
, m_rating( 0 )
, m_volume( false )
{
setFocusPolicy( TQ_NoFocus );
setBackgroundMode( NoBackground );
unsetColors();
connect( m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(hide()) );
connect( CollectionDB::instance(), TQT_SIGNAL( ratingChanged( const TQString&, int ) ),
this, TQT_SLOT( ratingChanged( const TQString&, int ) ) );
//or crashes, KWin bug I think, crashes in TQWidget::icon()
kapp->setTopWidget( this );
}
void
OSDWidget::show( const TQString &text, TQImage newImage )
{
#ifdef TQ_WS_X11
m_text = text;
if ( !newImage.isNull() )
{
m_cover = newImage;
int w = m_scaledCover.width();
int h = m_scaledCover.height();
m_scaledCover = m_cover.smoothScale(w, h);
}
show();
#else
Q_UNUSED( text );
Q_UNUSED( newImage );
#endif
}
void
OSDWidget::ratingChanged( const short rating )
{
//m_text = '\n' + i18n( "Rating changed" );
setRating( rating ); //Checks isEnabled() before doing anything
if( useMoodbar() )
OSDWidget::setMoodbar( EngineController::instance()->bundle() );
if( isShown() )
show();
}
void
OSDWidget::ratingChanged( const TQString& path, int rating )
{
const MetaBundle &currentTrack = EngineController::instance()->bundle();
if( currentTrack.isFile() && currentTrack.url().path() == path )
ratingChanged( rating );
}
void
OSDWidget::volChanged( unsigned char volume )
{
if ( isEnabled() )
{
m_volume = true;
m_newvolume = volume;
m_text = m_newvolume ? i18n("Volume: %1%").tqarg( m_newvolume ) : i18n("Mute");
show();
}
}
void
OSDWidget::show() //virtual
{
#ifdef TQ_WS_X11
if ( !isEnabled() || m_text.isEmpty() )
return;
const uint M = fontMetrics().width( 'x' );
const TQRect oldGeometry = TQRect( pos(), size() );
const TQRect newGeometry = determineMetrics( M );
if( m_translucency && !isShown() || !newGeometry.intersects( oldGeometry ) )
m_screenshot = TQPixmap(TQPixmap::grabWindow( qt_xrootwin(),
newGeometry.x(), newGeometry.y(),
newGeometry.width(), newGeometry.height() ));
else if ( m_translucency )
{
const TQRect unite = oldGeometry.unite( newGeometry );
KPixmap pix = TQPixmap(TQPixmap::grabWindow( qt_xrootwin(), unite.x(), unite.y(), unite.width(), unite.height() ));
TQPoint p = oldGeometry.topLeft() - unite.topLeft();
bitBlt( &pix, p, &m_screenshot );
m_screenshot.resize( newGeometry.size() );
p = newGeometry.topLeft() - unite.topLeft();
if (!kapp->isX11CompositionAvailable())
bitBlt( &m_screenshot, 0, 0, &pix, p.x(), p.y() );
}
if( newGeometry.width() > 0 && newGeometry.height() > 0 )
{
render( M, newGeometry.size() );
setGeometry( newGeometry );
TQWidget::show();
paintMe();
if( m_duration ) //duration 0 -> stay forever
m_timer->start( m_duration, true ); //calls hide()
}
else
warning() << "Attempted to make an invalid sized OSD\n";
#endif
}
TQRect
OSDWidget::determineMetrics( const uint M )
{
// sometimes we only have a tiddly cover
const TQSize minImageSize = m_cover.size().boundedTo( TQSize(100,100) );
// determine a sensible maximum size, don't cover the whole desktop or cross the screen
const TQSize margin( (M + MARGIN) * 2, (M + MARGIN) * 2 ); //margins
const TQSize image = m_cover.isNull() ? TQSize( 0, 0 ) : minImageSize;
const TQSize max = TQApplication::desktop()->screen( m_screen )->size() - margin;
// If we don't do that, the boundingRect() might not be suitable for drawText() (TQt issue N67674)
m_text.replace( TQRegExp(" +\n"), "\n" );
// remove consecutive line breaks
m_text.replace( TQRegExp("\n+"), "\n" );
// The osd cannot be larger than the screen
TQRect rect = fontMetrics().boundingRect( 0, 0,
max.width() - image.width(), max.height(),
AlignCenter | WordBreak, m_text );
if( m_volume )
{
static const TQString tmp = TQString ("******").insert( 3,
( i18n("Volume: 100%").length() >= i18n("Mute").length() )?
i18n("Volume: 100%") : i18n("Mute") );
TQRect tmpRect = fontMetrics().boundingRect( 0, 0,
max.width() - image.width(), max.height() - fontMetrics().height(),
AlignCenter | WordBreak, tmp );
tmpRect.setHeight( tmpRect.height() + fontMetrics().height() / 2 );
rect = tmpRect;
}
if( m_rating )
{
TQPixmap* star = StarManager::instance()->getStar( 1, true );
if( rect.width() < star->width() * 5 )
rect.setWidth( star->width() * 5 ); //changes right edge position
rect.setHeight( rect.height() + star->height() + M ); //changes bottom edge pos
}
if( useMoodbar() )
rect.setHeight( rect.height() + MOODBAR_HEIGHT + M );
if( !m_cover.isNull() )
{
const int availableWidth = max.width() - rect.width() - M; //WILL be >= (minImageSize.width() - M)
m_scaledCover = m_cover.smoothScale(
TQMIN( availableWidth, m_cover.width() ),
TQMIN( rect.height(), m_cover.height() ),
TQ_ScaleMin ); //this will force us to be with our bounds
int shadowWidth = 0;
if( m_drawShadow && !m_scaledCover.hasAlpha() &&
( m_scaledCover.width() > 22 || m_scaledCover.height() > 22 ) )
shadowWidth = static_cast<uint>( m_scaledCover.width() / 100.0 * 6.0 );
const int widthIncludingImage = rect.width()
+ m_scaledCover.width()
+ shadowWidth
+ M; //margin between text + image
rect.setWidth( widthIncludingImage );
}
// expand in all directions by M
rect.addCoords( -M, -M, M, M );
const TQSize newSize = rect.size();
const TQRect screen = TQApplication::desktop()->screenGeometry( m_screen );
TQPoint newPos( MARGIN, m_y );
switch( m_tqalignment )
{
case Left:
break;
case Right:
newPos.rx() = screen.width() - MARGIN - newSize.width();
break;
case Center:
newPos.ry() = (screen.height() - newSize.height()) / 2;
//FALL THROUGH
case Middle:
newPos.rx() = (screen.width() - newSize.width()) / 2;
break;
}
//ensure we don't dip below the screen
if ( newPos.y() + newSize.height() > screen.height() - MARGIN )
newPos.ry() = screen.height() - MARGIN - newSize.height();
// correct for screen position
newPos += screen.topLeft();
return TQRect( newPos, rect.size() );
}
void
OSDWidget::render( const uint M, const TQSize &size )
{
/// render with margin/spacing @param M and @param size
TQPoint point;
TQRect rect( point, size );
// From qt sources
const uint xround = (M * 200) / size.width();
const uint yround = (M * 200) / size.height();
{ /// apply the mask
static TQBitmap mask;
mask.resize( size );
mask.fill( TQt::black );
TQPainter p( &mask );
p.setBrush( TQt::white );
p.drawRoundRect( rect, xround, yround );
setMask( mask );
}
TQColor shadowColor;
{
int h,s,v;
foregroundColor().getHsv( &h, &s, &v );
shadowColor = v > 128 ? TQt::black : TQt::white;
}
int align = TQt::AlignCenter | WordBreak;
m_buffer.resize( rect.size() );
TQPainter p( &m_buffer );
if (( m_translucency ) && (!kapp->isX11CompositionAvailable()))
{
KPixmap background( m_screenshot );
KPixmapEffect::fade( background, 0.80, backgroundColor() );
p.drawPixmap( 0, 0, background );
}
else if (( m_translucency ) && (kapp->isX11CompositionAvailable()))
{
// Make the background semi-transparent
TQPixmap background( m_screenshot.width(), m_screenshot.height(), 32 );
TQRgb blend_color = tqRgba(backgroundColor().red(), backgroundColor().green(), backgroundColor().blue(), 204); // RGBA
float alpha = tqAlpha(blend_color) / 255.0;
int pixel = tqAlpha(blend_color) << 24 | int(tqRed(blend_color) * alpha) << 16 | int(tqGreen(blend_color) * alpha) << 8 | int(tqBlue(blend_color) * alpha);
background.fill(TQColor(blend_color, pixel));
bitBlt( &m_buffer, 0, 0, &background );
}
else
p.fillRect( rect, backgroundColor() );
p.setPen( backgroundColor().dark() );
p.drawRoundRect( rect, xround, yround );
rect.addCoords( M, M, -M, -M );
if( !m_cover.isNull() )
{
TQRect r( rect );
r.setTop( (size.height() - m_scaledCover.height()) / 2 );
r.setSize( m_scaledCover.size() );
if( !m_scaledCover.hasAlpha() && m_drawShadow &&
( m_scaledCover.width() > 22 || m_scaledCover.height() > 22 ) ) {
// don't draw a shadow for eg, the Amarok icon
TQImage shadow;
const uint shadowSize = static_cast<uint>( m_scaledCover.width() / 100.0 * 6.0 );
const TQString folder = Amarok::saveLocation( "covershadow-cache/" );
const TQString file = TQString( "shadow_albumcover%1x%2.png" ).tqarg( m_scaledCover.width() + shadowSize )
.tqarg( m_scaledCover.height() + shadowSize );
if ( TQFile::exists( folder + file ) )
shadow.load( folder + file );
else {
shadow.load( locate( "data", "amarok/images/shadow_albumcover.png" ) );
shadow = shadow.smoothScale( m_scaledCover.width() + shadowSize, m_scaledCover.height() + shadowSize );
shadow.save( folder + file, "PNG" );
}
TQPixmap target;
target.convertFromImage( shadow ); //FIXME slow
copyBlt( &target, 0, 0, &m_scaledCover );
m_scaledCover = target;
r.setTop( (size.height() - m_scaledCover.height()) / 2 );
r.setSize( m_scaledCover.size() );
}
p.drawPixmap( r.topLeft(), m_scaledCover );
rect.rLeft() += m_scaledCover.width() + M;
}
if( m_volume )
{
TQPixmap vol;
vol = TQPixmap( rect.width(), rect.height() + fontMetrics().height() / 4 );
TQPixmap buf( vol.size() );
TQRect r( rect );
r.setLeft( rect.left() + rect.width() / 2 - vol.width() / 2 );
r.setTop( size.height() / 2 - vol.height() / 2);
KPixmap pixmapGradient;
{ // gradient
TQBitmap mask;
mask.resize( vol.size() );
mask.fill( TQt::black );
TQPainter p( &mask );
p.setBrush( TQt::white );
p.drawRoundRect ( 3, 3, vol.width() - 6, vol.height() - 6,
M * 300 / vol.width(), 99 );
p.end();
pixmapGradient = TQPixmap( vol.size() );
KPixmapEffect::gradient( pixmapGradient, tqcolorGroup().background(),
tqcolorGroup().highlight(), KPixmapEffect::EllipticGradient );
pixmapGradient.setMask( mask );
}
if (( m_translucency ) && (!kapp->isX11CompositionAvailable()))
{
KPixmap background( m_screenshot );
KPixmapEffect::fade( background, 0.80, backgroundColor() );
bitBlt( &vol, -r.left(), -r.top(), &background );
}
else if (( m_translucency ) && (kapp->isX11CompositionAvailable()))
{
// Make the background semi-transparent
TQPixmap background( m_screenshot.width(), m_screenshot.height(), 32 );
TQRgb blend_color = tqRgba(backgroundColor().red(), backgroundColor().green(), backgroundColor().blue(), 204); // RGBA
float alpha = tqAlpha(blend_color) / 255.0;
int pixel = tqAlpha(blend_color) << 24 | int(tqRed(blend_color) * alpha) << 16 | int(tqGreen(blend_color) * alpha) << 8 | int(tqBlue(blend_color) * alpha);
background.fill(TQColor(blend_color, pixel));
bitBlt( &vol, -r.left(), -r.top(), &background );
}
else
vol.fill( backgroundColor() );
{ // vol ( bg-alpha )
static TQBitmap mask;
mask.resize( vol.size() );
mask.fill( TQt::white );
TQPainter p( &mask );
p.setBrush( TQt::black );
p.drawRoundRect ( 1, 1, rect.width()-2, rect.height() + fontMetrics().height() / 4 - 2,
M * 300 / vol.width(), 99 );
p.setBrush( TQt::white );
p.drawRoundRect ( 3, 3, vol.width() - 6, vol.height() - 6,
M * 300 / vol.width(), 99 );
p.end();
vol.setMask( mask );
}
buf.fill( backgroundColor().dark() );
const int offset = int( double( vol.width() * m_newvolume ) / 100 );
bitBlt( &buf, 0, 0, &vol ); // bg
bitBlt( &buf, 0, 0, &pixmapGradient, 0, 0, offset );
p.drawPixmap( r.left(), r.top(), buf );
m_volume = false;
}
TQPixmap* star = StarManager::instance()->getStar( m_rating/2, true );
int graphicsHeight = 0;
if( useMoodbar() )
{
TQPixmap moodbar
= m_moodbarBundle.moodbar().draw( rect.width(), MOODBAR_HEIGHT );
TQRect r( rect );
r.setTop( rect.bottom() - moodbar.height()
- (m_rating ? star->height() + M : 0) );
graphicsHeight += moodbar.height() + M;
p.drawPixmap( r.left(), r.top(), moodbar );
m_moodbarBundle = MetaBundle();
}
if( m_rating > 0 )
{
TQRect r( rect );
//Align to center...
r.setLeft(( rect.left() + rect.width() / 2 ) - star->width() * m_rating / 4 );
r.setTop( rect.bottom() - star->height() );
graphicsHeight += star->height() + M;
bool half = m_rating%2;
if( half )
{
TQPixmap* halfStar = StarManager::instance()->getHalfStar( m_rating/2 + 1, true );
p.drawPixmap( r.left() + star->width() * ( m_rating / 2 ), r.top(), *halfStar );
star = StarManager::instance()->getStar( m_rating/2 + 1, true );
}
for( int i = 0; i < m_rating/2; i++ )
{
p.drawPixmap( r.left() + i * star->width(), r.top(), *star );
}
m_rating = 0;
}
rect.setBottom( rect.bottom() - graphicsHeight );
if( m_drawShadow )
{
TQPixmap pixmap( rect.size() + TQSize(10,10) );
pixmap.fill( TQt::black );
pixmap.setMask( pixmap.createHeuristicMask( true ) );
TQPainter p2( &pixmap );
p2.setFont( font() );
p2.setPen( TQt::white );
p2.setBrush( TQt::white );
p2.drawText( TQRect(TQPoint(5,5), rect.size()), align , m_text );
p2.end();
p.drawImage( rect.topLeft() - TQPoint(5,5), ShadowEngine::makeShadow( pixmap, shadowColor ) );
}
p.setPen( foregroundColor() );
p.setFont( font() );
p.drawText( rect, align, m_text );
p.end();
}
void
OSDWidget::paintMe()
{
if ((m_translucency) && (kapp->isX11CompositionAvailable())) {
// We have true composition support, so make the OSD truly transparent
TQImage blendedImage = m_buffer.convertToImage();
blendedImage = blendedImage.convertDepth(32);
blendedImage.setAlphaBuffer(true);
// Convert the ARGB pixmap to an ARGB image
// NOTE 1: TQPixmap::convertToImage() always converts an ARGB pixmap into an RGB image
// NOTE 2: This should eventually make its way into kdelibs or Qt itself,
// as it would also be useful in applications other than Amarok
int w = blendedImage.width();
int h = blendedImage.height();
Pixmap rawpixmap = m_buffer.handle();
XImage *image;
image = XGetImage (qt_xdisplay(), rawpixmap, 0, 0, w, h, AllPlanes, XYPixmap);
for (int y = 0; y < h; ++y) {
TQRgb *ls = (TQRgb *)blendedImage.scanLine( y );
for (int x = 0; x < w; ++x) {
unsigned int rawpixel = XGetPixel(image, x, y);
int r = int( (rawpixel & 0x00ff0000) >> 16 );
int g = int( (rawpixel & 0x0000ff00) >> 8 );
int b = int( (rawpixel & 0x000000ff) );
int a = int( (rawpixel & 0xff000000) >> 24 );
ls[x] = tqRgba( r, g, b, a );
}
}
XFree (image);
// Finally, paint it
TQPainter p1;
p1.begin( this );
blendedImage.setAlphaBuffer(false);
p1.drawImage( 0, 0, blendedImage );
p1.end();
}
else {
bitBlt( this, 0, 0, &m_buffer );
}
}
bool
OSDWidget::event( TQEvent *e )
{
switch( e->type() )
{
case TQEvent::ApplicationPaletteChange:
if( !AmarokConfig::osdUseCustomColors() )
unsetColors(); //use new palette's colours
return true;
case TQEvent::Paint:
paintMe();
return true;
default:
return TQWidget::event( e );
}
}
void
OSDWidget::mousePressEvent( TQMouseEvent* )
{
hide();
}
void
OSDWidget::unsetColors()
{
const TQColorGroup c = TQApplication::tqpalette().active();
setPaletteForegroundColor( c.highlightedText() );
setPaletteBackgroundColor( c.highlight() );
}
void
OSDWidget::setScreen( int screen )
{
const int n = TQApplication::desktop()->numScreens();
m_screen = (screen >= n) ? n-1 : screen;
}
bool
OSDWidget::useMoodbar( void )
{
return (m_moodbarBundle.moodbar().state() == Moodbar::Loaded &&
AmarokConfig::showMoodbar() );
}
////// OSDPreviewWidget below /////////////////////
#include <kcursor.h>
#include <kiconloader.h>
#include <klocale.h>
namespace Amarok
{
TQImage icon() { return TQImage( KIconLoader().iconPath( "amarok", -KIcon::SizeHuge ) ); }
}
OSDPreviewWidget::OSDPreviewWidget( TQWidget *parent )
: OSDWidget( parent, "osdpreview" )
, m_dragging( false )
{
m_text = i18n( "OSD Preview - drag to reposition" );
m_duration = 0;
m_cover = Amarok::icon();
}
void OSDPreviewWidget::mousePressEvent( TQMouseEvent *event )
{
m_dragOffset = event->pos();
if( event->button() == Qt::LeftButton && !m_dragging ) {
grabMouse( KCursor::sizeAllCursor() );
m_dragging = true;
}
}
void OSDPreviewWidget::mouseReleaseEvent( TQMouseEvent * /*event*/ )
{
if( m_dragging )
{
m_dragging = false;
releaseMouse();
// compute current Position && offset
TQDesktopWidget *desktop = TQApplication::desktop();
int currentScreen = desktop->screenNumber( pos() );
if( currentScreen != -1 ) {
// set new data
m_screen = currentScreen;
m_y = TQWidget::y();
emit positionChanged();
}
}
}
void OSDPreviewWidget::mouseMoveEvent( TQMouseEvent *e )
{
if( m_dragging && this == mouseGrabber() )
{
// Here we implement a "snap-to-grid" like positioning system for the preview widget
const TQRect screen = TQApplication::desktop()->screenGeometry( m_screen );
const uint hcenter = screen.width() / 2;
const uint eGlobalPosX = e->globalPos().x() - screen.left();
const uint snapZone = screen.width() / 24;
TQPoint destination = e->globalPos() - m_dragOffset - screen.topLeft();
int maxY = screen.height() - height() - MARGIN;
if( destination.y() < MARGIN ) destination.ry() = MARGIN;
if( destination.y() > maxY ) destination.ry() = maxY;
if( eGlobalPosX < (hcenter-snapZone) ) {
m_tqalignment = Left;
destination.rx() = MARGIN;
}
else if( eGlobalPosX > (hcenter+snapZone) ) {
m_tqalignment = Right;
destination.rx() = screen.width() - MARGIN - width();
}
else {
const uint eGlobalPosY = e->globalPos().y() - screen.top();
const uint vcenter = screen.height()/2;
destination.rx() = hcenter - width()/2;
if( eGlobalPosY >= (vcenter-snapZone) && eGlobalPosY <= (vcenter+snapZone) )
{
m_tqalignment = Center;
destination.ry() = vcenter - height()/2;
}
else m_tqalignment = Middle;
}
destination += screen.topLeft();
move( destination );
}
}
////// Amarok::OSD below /////////////////////
#include "enginecontroller.h"
#include "metabundle.h"
#include <tqregexp.h>
Amarok::OSD::OSD(): OSDWidget( 0 )
{
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& ) ) );
}
void
Amarok::OSD::show( const MetaBundle &bundle ) //slot
{
#ifdef TQ_WS_X11
TQString text = "";
if( bundle.url().isEmpty() )
text = i18n( "No track playing" );
else
{
TQValueVector<TQString> tags;
tags.append(bundle.prettyTitle());
for( int i = 0; i < PlaylistItem::NUM_COLUMNS; ++i )
tags.append(bundle.prettyText( i ));
if( bundle.length() <= 0 )
tags[PlaylistItem::Length+1] = TQString();
if( AmarokConfig::osdUsePlaylistColumns() )
{
TQString tag;
TQValueVector<int> availableTags; //eg, ones that aren't empty
static const TQValueList<int> parens = //display these in parentheses
TQValueList<int>() << PlaylistItem::PlayCount << PlaylistItem::Year << PlaylistItem::Comment
<< PlaylistItem::Genre << PlaylistItem::Length << PlaylistItem::Bitrate
<< PlaylistItem::LastPlayed << PlaylistItem::Score << PlaylistItem::Filesize;
OSDWidget::setMoodbar();
OSDWidget::setRating( 0 );
for( int i = 0, n = Playlist::instance()->numVisibleColumns(); i < n; ++i )
{
const int column = Playlist::instance()->mapToLogicalColumn( i );
if( !tags.at( column + 1 ).isEmpty() && column != PlaylistItem::Rating )
availableTags.append(column);
if( column == PlaylistItem::Rating )
OSDWidget::setRating( bundle.rating() );
else if( column == PlaylistItem::Mood )
OSDWidget::setMoodbar( bundle );
}
for( int n = availableTags.count(), i = 0; i < n; ++i )
{
const int column = availableTags.at( i );
TQString append = ( i == 0 ) ? ""
: ( n > 1 && i == n / 2 ) ? "\n"
: ( parens.contains( column ) || parens.contains( availableTags.at( i - 1 ) ) ) ? " "
: i18n(" - ");
append += ( parens.contains( column ) ? "(%1)" : "%1" );
text += append.tqarg( tags.at( column + 1 ) );
}
}
else
{
TQMap<TQString, TQString> args;
args["prettytitle"] = bundle.prettyTitle();
for( int i = 0; i < PlaylistItem::NUM_COLUMNS; ++i )
args[bundle.exactColumnName( i ).lower()] = bundle.prettyText( i );
if( bundle.length() <= 0 )
args["length"] = TQString();