No longer fetch images by default in Meta::Album::image()
[amarok/test.git] / src / playlist / PlaylistGraphicsItem.cpp
blob60013fccef8fe411ef2f21cd8373b514489b7029
1 /***************************************************************************
2 * copyright : (C) 2007 Ian Monroe <ian@monroe.nu>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
22 #include "debug.h"
23 #include "meta/MetaUtility.h"
24 #include "AmarokMimeData.h"
25 #include "PlaylistGraphicsItem.h"
26 #include "PlaylistGraphicsView.h"
27 #include "PlaylistDropVis.h"
28 #include "PlaylistModel.h"
29 #include "PlaylistTextItem.h"
30 #include "TheInstances.h"
31 #include "CoverManager.h"
33 #include "KStandardDirs"
35 #include <QBrush>
36 #include <QDrag>
37 #include <QFontMetricsF>
38 #include <QGraphicsScene>
39 #include <QGraphicsTextItem>
40 #include <QGraphicsPixmapItem>
41 #include <QGraphicsRectItem>
42 #include <QGraphicsSceneMouseEvent>
43 #include <QGraphicsView>
44 #include <QMimeData>
45 #include <QPen>
46 #include <QPixmapCache>
47 #include <QRadialGradient>
48 #include <QScrollBar>
49 #include <QStyleOptionGraphicsItem>
51 #include <KLocale>
53 struct Playlist::GraphicsItem::ActiveItems
55 ActiveItems()
56 : foreground( 0 )
57 , bottomLeftText( 0 )
58 , bottomRightText( 0 )
59 , topLeftText( 0 )
60 , topRightText( 0 )
61 , lastWidth( -5 )
62 , groupedTracks ( 0 )
63 , collapsible( true )
64 { }
66 ~ActiveItems()
68 delete bottomLeftText;
69 delete bottomRightText;
70 delete foreground;
71 delete topLeftText;
72 delete topRightText;
76 QGraphicsPixmapItem* foreground;
77 Playlist::TextItem* bottomLeftText;
78 Playlist::TextItem* bottomRightText;
79 Playlist::TextItem* topLeftText;
80 Playlist::TextItem* topRightText;
82 QColor overlayGradientStart;
83 QColor overlayGradientEnd;
85 int lastWidth;
86 int groupedTracks;
87 bool collapsible;
89 QRectF preDragLocation;
90 Meta::TrackPtr track;
94 const qreal Playlist::GraphicsItem::ALBUM_WIDTH = 50.0;
95 const qreal Playlist::GraphicsItem::MARGIN = 4.0;
96 QFontMetricsF* Playlist::GraphicsItem::s_fm = 0;
97 QSvgRenderer * Playlist::GraphicsItem::s_svgRenderer = 0;
100 Playlist::GraphicsItem::GraphicsItem()
101 : QGraphicsItem()
102 , m_items( 0 )
103 , m_height( -1 )
104 , m_groupMode( -1 )
105 , m_groupModeChanged ( false )
106 , m_collapsible ( true )
107 , m_dataChanged( false )
109 setZValue( 1.0 );
110 if( !s_fm )
112 s_fm = new QFontMetricsF( QFont() );
113 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + 2 * MARGIN;
116 if ( !s_svgRenderer ) {
117 s_svgRenderer = new QSvgRenderer( KStandardDirs::locate( "data","amarok/images/playlist_items.svg" ));
118 if ( ! s_svgRenderer->isValid() )
119 debug() << "svg is kaputski";
122 setFlag( QGraphicsItem::ItemIsSelectable );
123 setFlag( QGraphicsItem::ItemIsMovable );
124 setAcceptDrops( true );
125 // setHandlesChildEvents( true ); // don't let drops etc hit the text items, doing stupid things
128 Playlist::GraphicsItem::~GraphicsItem()
130 delete m_items;
133 void
134 Playlist::GraphicsItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget )
136 // ::paint RULES:
137 // 1) You do not talk about ::paint method
138 // 2) You DO NOT talk about ::paint method
139 // 3) Do not show or hide item that are already shown or hidden, respectively
140 // 4) Do not setBrush without making sure its hasn't already been set to that brush().
141 // 5) If this is your first night at ::paint method, you HAVE to paint.
142 Q_UNUSED( painter ); Q_UNUSED( widget );
144 //debug() << "painting row: " << m_currentRow;
145 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
147 if( m_dataChanged || !m_items || ( option->rect.width() != m_items->lastWidth ) || m_groupModeChanged )
150 if( !m_items )
152 const Meta::TrackPtr track = index.data( ItemRole ).value< Playlist::Item* >()->track();
153 m_items = new Playlist::GraphicsItem::ActiveItems();
154 m_items->track = track;
155 init( track );
157 m_groupModeChanged = false;
158 resize( m_items->track, option->rect.width() );
162 if ( m_groupMode == Collapsed ) {
163 // just make sure text items are hidden and then get the heck out of here...
164 // whoops... this has got to be moved here below the check for (!m_items) or
165 // it will evetually crasah....
166 if( m_items->topRightText->isVisible() )
167 m_items->topRightText->hide();
168 if( m_items->topLeftText->isVisible() )
169 m_items->topLeftText->hide();
170 if( m_items->bottomRightText->isVisible() )
171 m_items->bottomRightText->hide();
172 if( m_items->bottomLeftText->isVisible() )
173 m_items->bottomLeftText->hide();
175 return;
178 // paint item background:
179 QRectF trackRect;
180 QRectF headRect;
181 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
183 //make the album group header stand out
184 //painter->fillRect( option->rect, QBrush( Qt::darkCyan ) );
185 trackRect = QRectF( option->rect.x(), ALBUM_WIDTH + 2 * MARGIN, option->rect.width(), s_fm->height() /*+ MARGIN*/ );
186 if (m_groupMode == Head )
187 headRect = option->rect;
188 else
189 headRect = QRectF( option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height() - 2 );
191 else
193 trackRect = option->rect;
195 if ( ( m_groupMode != Body) && !( ( m_groupMode == Head ) ) )
196 trackRect.setHeight( trackRect.height() - 2 ); // add a little space between items
200 if ( m_groupMode == None )
202 QString key = QString("track:%1x%2").arg(trackRect.width()).arg(trackRect.height());
203 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
204 background.fill( Qt::transparent );
207 if (!QPixmapCache::find(key, background)) {
208 QPainter pt( &background );
209 s_svgRenderer->render( &pt, "track", trackRect );
210 QPixmapCache::insert(key, background);
212 painter->drawPixmap( 0, 0, background );
214 else if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) )
216 QString svgName;
217 if ( m_groupMode == Head )
218 svgName = "head";
219 else
220 svgName = "collapsed_head";
222 QString key = QString("%1:%2x%3").arg( svgName ).arg( headRect.width() ).arg( headRect.height() );
223 QPixmap background( (int)headRect.width(), (int)headRect.height() );
224 background.fill( Qt::transparent );
226 if ( !QPixmapCache::find( key, background ) )
228 QPainter pt( &background );
229 s_svgRenderer->render( &pt, svgName, headRect );
230 QPixmapCache::insert( key, background );
232 painter->drawPixmap( 0, 0, background );
234 //"Just for fun" stuff below this point
236 //ask if we are allowed to collapse thid group:
237 //m_collapsible = index.data( GroupedCollapsibleRole ).toBool();
239 QString collapseString;
240 if ( m_groupMode == Head )
242 if ( m_collapsible )
243 collapseString = "collapse_button";
244 else
245 collapseString = "collapse_button_grayed_out";
247 else
248 collapseString = "expand_button";
251 key = QString("%1:%2x%3").arg( collapseString ).arg( 16 ).arg( 16 );
252 QPixmap collapsePixmap( 16, 16 );
253 collapsePixmap.fill( Qt::transparent );
255 if( !QPixmapCache::find(key, collapsePixmap) )
257 QPainter pt2( &collapsePixmap );
258 s_svgRenderer->render( &pt2, collapseString, QRectF( 0, 0, 16, 16 ) );
259 QPixmapCache::insert(key, collapsePixmap);
262 painter->drawPixmap( (int)( option->rect.width() - ( 16 + MARGIN ) ), (int)MARGIN, collapsePixmap );
264 else if( m_groupMode == Body )
266 QString key = QString("body:%1x%2").arg(trackRect.width()).arg(trackRect.height());
267 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
268 background.fill( Qt::transparent );
270 if(!QPixmapCache::find(key, background))
272 QPainter pt( &background );
273 s_svgRenderer->render( &pt, "body", trackRect );
274 QPixmapCache::insert(key, background);
276 painter->drawPixmap( 0, 0, background );
278 else if ( m_groupMode == End )
280 QString key = QString( "tail:%1x%2" ).arg( trackRect.width() ).arg(trackRect.height()) ;
281 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
282 background.fill( Qt::transparent );
284 if( !QPixmapCache::find(key, background) )
286 QPainter pt( &background );
287 s_svgRenderer->render( &pt, "tail", trackRect );
288 QPixmapCache::insert(key, background);
290 painter->drawPixmap( 0, 0, background );
293 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) || ( m_groupMode == Body ) || ( m_groupMode == End ) )
295 if ( index.data( GroupedAlternateRole ).toBool() )
297 QString key = QString( "alternate:%1x%2" ).arg( trackRect.width() - 10 ).arg(trackRect.height() );
298 QPixmap background( (int)( trackRect.width() - 10 ), (int)( trackRect.height() ) );
300 QRectF tempRect = trackRect;
301 tempRect.setWidth( tempRect.width() - 10 );
302 if ( m_groupMode == End )
303 tempRect.setHeight( tempRect.height() - 4 );
305 if (!QPixmapCache::find( key, background ) )
307 background.fill( Qt::transparent );
308 QPainter pt( &background );
309 s_svgRenderer->render( &pt, "body_background", tempRect );
310 QPixmapCache::insert( key, background );
313 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ))
314 painter->drawPixmap( 5, (int)( MARGIN + ALBUM_WIDTH + 2 ), background );
315 else
316 painter->drawPixmap( 5, 0, background );
321 if ( m_groupMode < Body )
323 //if we are not grouped, or are the head of a group, paint cover:
324 QPixmap albumPixmap;
325 if( m_items->track->album() )
327 if( !m_items->track->album()->hasImage( int( ALBUM_WIDTH ) ) )
329 The::coverFetcher()->queueAlbum( m_items->track->album() );
331 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
333 painter->drawPixmap( imageLocation(), albumPixmap, QRectF( albumPixmap.rect() ) );
334 //and make sure the top text elements are shown
335 if( !m_items->topRightText->isVisible() )
336 m_items->topRightText->show();
337 if( !m_items->topLeftText->isVisible() )
338 m_items->topLeftText->show();
341 else
343 //if not, make sure that the top text items are not shown
344 if( m_items->topRightText->isVisible() )
345 m_items->topRightText->hide();
346 if( m_items->topLeftText->isVisible() )
347 m_items->topLeftText->hide();
348 if( !m_items->bottomRightText->isVisible() )
349 m_items->bottomRightText->show();
350 if( !m_items->bottomLeftText->isVisible() )
351 m_items->bottomLeftText->show();
355 //set selection marker if needed
356 if( option->state & QStyle::State_Selected )
358 //painter->fillRect( trackRect, QBrush( QColor( 0, 0, 255, 128 ) ) );
360 QString key = QString("selection_left:%1x%2").arg( 40 ).arg(trackRect.height());
362 QPixmap leftMarker( 40 , (int)( trackRect.height() ) );
363 leftMarker.fill( Qt::transparent );
365 if( !QPixmapCache::find(key, leftMarker) )
367 QPainter pt( &leftMarker );
368 s_svgRenderer->render( &pt, "selection_left"/*, QRectF( 0, 0, 40, trackRect.height() )*/ );
369 QPixmapCache::insert(key, leftMarker);
371 if ( m_groupMode == Head )
372 painter->drawPixmap( 2, (int)trackRect.top() + 2, leftMarker );
373 else
374 painter->drawPixmap( 2, (int)trackRect.top(), leftMarker );
377 key = QString("selection_right:%1x%2").arg( 40 ).arg(trackRect.height());
378 QPixmap rightMarker( 40 , (int)( trackRect.height() ) );
379 rightMarker.fill( Qt::transparent );
381 if( !QPixmapCache::find(key, rightMarker) )
383 QPainter pt( &rightMarker );
384 s_svgRenderer->render( &pt, "selection_right", QRectF( 0, 0, 40, trackRect.height() ) );
385 QPixmapCache::insert(key, rightMarker);
388 if ( m_groupMode == Head )
389 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top() + 2, rightMarker );
390 else
391 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top(), rightMarker );
396 //set overlay if item is active:
397 if( index.data( ActiveTrackRole ).toBool() )
399 if( !m_items->foreground )
402 debug() << "Creating active track overlay";
403 m_items->foreground = new QGraphicsPixmapItem( this );
404 m_items->foreground->setPos( 0.0, trackRect.top() );
405 m_items->foreground->setZValue( 10.0 );
408 QString key = QString("active_overlay:%1x%2").arg(trackRect.width()).arg(trackRect.height());
409 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
410 background.fill( Qt::transparent );
412 if (!QPixmapCache::find(key, background)) {
413 QPainter pt( &background );
414 s_svgRenderer->render( &pt, "active_overlay", QRectF( 0, 0, trackRect.width(), trackRect.height() ) );
415 QPixmapCache::insert(key, background);
417 m_items->foreground->setPixmap( background );
418 m_items->foreground->show();
419 debug() << "Done";
422 /*QRadialGradient gradient(trackRect.width() / 2.0, trackRect.height() / 2.0, trackRect.width() / 2.0, 20 + trackRect.width() / 2.0, trackRect.height() / 2.0 );
423 m_items->overlayGradientStart = option->palette.highlightedText().color().light();
424 m_items->overlayGradientStart.setAlpha( 80 );
425 m_items->overlayGradientEnd = option->palette.highlightedText().color().dark();
426 m_items->overlayGradientEnd.setAlpha( 80 );
427 gradient.setColorAt( 0.0, m_items->overlayGradientStart );
428 gradient.setColorAt( 1.0, m_items->overlayGradientEnd );
429 QBrush brush( gradient );
430 m_items->foreground->setBrush( brush );
431 m_items->foreground->setPen( QPen( Qt::NoPen ) );*/
433 if( !m_items->foreground->isVisible() )
434 m_items->foreground->show();
436 else if( m_items->foreground && m_items->foreground->isVisible() )
437 m_items->foreground->hide();
440 void
441 Playlist::GraphicsItem::init( Meta::TrackPtr track )
443 Q_UNUSED( track );
444 QFont font;
445 font.setPointSize( font.pointSize() - 1 );
446 #define NewText( X ) \
447 X = new Playlist::TextItem( this ); \
448 X->setTextInteractionFlags( Qt::TextEditorInteraction ); \
449 X->setFont( font );
450 NewText( m_items->topLeftText )
451 NewText( m_items->bottomLeftText )
452 NewText( m_items->topRightText )
453 NewText( m_items->bottomRightText )
454 #undef NewText
457 void
458 Playlist::GraphicsItem::resize( Meta::TrackPtr track, int totalWidth )
460 if( totalWidth == -1 /*|| totalWidth == m_items->lastWidth */) //no change needed
461 return;
462 if( m_items->lastWidth != -5 ) //this isn't the first "resize"
463 prepareGeometryChange();
464 m_items->lastWidth = totalWidth;
466 QString prettyLength;
468 if ( m_groupMode == Head_Collapsed )
470 uint seconds = 0;
471 for( int i = m_currentRow; i < m_currentRow + m_items->groupedTracks; i++ )
472 seconds += The::playlistModel()->itemList()[ i ]->track()->length();
473 prettyLength = Meta::secToPrettyTime( seconds );
475 else
476 prettyLength = Meta::secToPrettyTime( track->length() );
478 QString album;
479 if( track->album() )
480 album = track->album()->name();
482 const qreal lineTwoY = m_height / 2 + MARGIN;
483 const qreal textWidth = ( ( qreal( totalWidth ) - ALBUM_WIDTH ) / 2.0 );
484 const qreal leftAlignX = ALBUM_WIDTH + MARGIN;
485 qreal topRightAlignX;
486 qreal bottomRightAlignX;
489 qreal middle = textWidth + ALBUM_WIDTH + ( MARGIN * 2.0 );
490 qreal rightWidth = totalWidth - qMax( s_fm->width( album )
491 , s_fm->width( prettyLength ) );
492 topRightAlignX = qMax( middle, rightWidth );
495 //lets use all the horizontal space we can get for now..
496 int lengthStringWidth = (int)(s_fm->width( prettyLength ));
497 bottomRightAlignX = ( totalWidth - 4 * MARGIN ) - lengthStringWidth ;
502 qreal spaceForTopLeft = totalWidth - ( totalWidth - topRightAlignX ) - leftAlignX;
503 qreal spaceForBottomLeft = totalWidth - ( totalWidth - bottomRightAlignX ) - leftAlignX;
505 if ( m_groupMode == Head_Collapsed ) {
507 m_items->bottomLeftText->setEditableText( QString("%1 tracks").arg( QString::number( m_items->groupedTracks ) ) , spaceForBottomLeft );
508 QFont f = m_items->bottomLeftText->font();
509 f.setItalic( true );
510 m_items->bottomLeftText->setFont( f );
511 m_items->bottomRightText->setEditableText( prettyLength, totalWidth - bottomRightAlignX );
513 } else {
514 m_items->bottomLeftText->setFont( m_items->bottomRightText->font() );
515 m_items->bottomLeftText->setEditableText( QString("%1 - %2").arg( QString::number( track->trackNumber() ), track->name() ) , spaceForBottomLeft );
516 m_items->bottomRightText->setEditableText( prettyLength, totalWidth - bottomRightAlignX );
518 if ( m_groupMode == None ) {
520 m_items->topRightText->setPos( topRightAlignX, MARGIN );
521 m_items->topRightText->setEditableText( album, totalWidth - topRightAlignX );
524 QString artist;
525 if( track->artist() )
526 artist = track->artist()->name();
527 m_items->topLeftText->setEditableText( artist, spaceForTopLeft );
528 m_items->topLeftText->setPos( leftAlignX, MARGIN );
531 m_items->bottomLeftText->setPos( leftAlignX, lineTwoY );
532 m_items->bottomRightText->setPos( bottomRightAlignX, lineTwoY );
533 } else if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
535 int headingCenter = (int)( MARGIN + ( ALBUM_WIDTH - s_fm->height()) / 2 );
537 m_items->topRightText->setPos( topRightAlignX, headingCenter );
538 m_items->topRightText->setEditableText( album, totalWidth - topRightAlignX );
541 QString artist;
542 //various artist handling:
543 //if the album has no albumartist, use Various Artists, otherwise use the albumartist's name
544 if( track->album()->albumArtist() )
545 artist = track->album()->albumArtist()->name();
546 else
548 artist = findArtistForCurrentAlbum();
549 if( artist.isEmpty() )
550 artist = i18n( "Various Artists" );
552 m_items->topLeftText->setEditableText( artist, spaceForTopLeft );
553 m_items->topLeftText->setPos( leftAlignX, headingCenter );
556 int underImageY = (int)( MARGIN + ALBUM_WIDTH + 6 );
558 m_items->bottomLeftText->setPos( MARGIN * 3, underImageY );
559 m_items->bottomRightText->setPos( bottomRightAlignX, underImageY );
561 } else {
562 m_items->bottomLeftText->setPos( MARGIN * 3, 0 );
563 m_items->bottomRightText->setPos( bottomRightAlignX, 0 );
566 //make sure the activ eitem overlay has the correct width
570 if( m_items->foreground )
573 QRectF trackRect;
574 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
575 trackRect = QRectF( 0, ALBUM_WIDTH + 2 * MARGIN, totalWidth, s_fm->height() /*+ MARGIN*/ );
576 } else {
577 trackRect = QRectF( 0, 0, totalWidth, m_height );
578 if ( ( m_groupMode != Body) && !( ( m_groupMode == Head ) ) )
579 trackRect.setHeight( trackRect.height() - 2 ); // add a little space between items
582 debug() << "Resizing active track overlay";
584 QString key = QString("active_overlay:%1x%2").arg(trackRect.width()).arg(trackRect.height());
586 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
587 background.fill( Qt::transparent );
590 if (!QPixmapCache::find(key, background)) {
591 QPainter pt( &background );
592 s_svgRenderer->render( &pt, "active_overlay", QRectF( 0, 0, trackRect.width(), trackRect.height() ) );
593 QPixmapCache::insert(key, background);
595 m_items->foreground->setPixmap( background );
596 m_items->foreground->setZValue( 10.0 );
598 debug() << "Done";
602 m_items->lastWidth = totalWidth;
605 QString
606 Playlist::GraphicsItem::findArtistForCurrentAlbum() const
608 if( !( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) )
609 return QString();
611 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
612 if( ! ( ( index.data( GroupRole ).toInt() == Head ) || ( index.data( GroupRole ).toInt() == Head_Collapsed ) ) )
614 return QString();
616 else
618 QString artist;
619 Meta::TrackPtr currentTrack = index.data( TrackRole ).value< Meta::TrackPtr >();
620 if( currentTrack->artist() )
621 artist = currentTrack->artist()->name();
622 else
623 return QString();
624 //it's an album group, and the current row is the head, so the next row is either Body or End
625 //that means we have to execute the loop at least once
626 QModelIndex idx;
627 int row = m_currentRow + 1;
630 idx = The::playlistModel()->index( row++, 0 );
631 Meta::TrackPtr track = idx.data( TrackRole ).value< Meta::TrackPtr >();
632 if( track->artist() )
634 if( artist != track->artist()->name() )
635 return QString();
637 else
639 return QString();
642 while( idx.data( GroupRole ).toInt() == Body );
644 return artist;
648 QRectF
649 Playlist::GraphicsItem::boundingRect() const
651 // the viewport()->size() takes scrollbars into account
652 return QRectF( 0.0, 0.0, The::playlistView()->viewport()->size().width(), m_height );
655 void
656 Playlist::GraphicsItem::play()
658 The::playlistModel()->play( m_currentRow );
661 void
662 Playlist::GraphicsItem::showImage() const
664 ( new CoverViewDialog( m_items->track->album(), The::playlistView() ) )->show();
667 void
668 Playlist::GraphicsItem::fetchImage()
670 CoverFetcher *fetcher = The::coverFetcher();
671 fetcher->manualFetch( m_items->track->album() );
674 void
675 Playlist::GraphicsItem::unsetImage()
677 m_items->track->album()->removeImage();
680 void
681 Playlist::GraphicsItem::dataChanged()
683 m_dataChanged = true;
686 const bool
687 Playlist::GraphicsItem::hasImage() const
689 return m_items->track->album()->hasImage();
692 void
693 Playlist::GraphicsItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event )
695 if( m_items )
697 event->accept();
698 play();
699 return;
701 QGraphicsItem::mouseDoubleClickEvent( event );
704 void
705 Playlist::GraphicsItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
707 if( event->buttons() & Qt::RightButton || !m_items )
709 event->ignore();
710 return;
712 m_items->preDragLocation = mapToScene( boundingRect() ).boundingRect();
714 //did we hit the collapse / expand button?
715 if( m_collapsible )
717 QRectF rect( boundingRect().width() - ( 16 + MARGIN ), MARGIN, 16, 16 );
718 if( rect.contains( event->pos() ) )
720 if ( m_groupMode == Head_Collapsed )
721 The::playlistModel()->setCollapsed( m_currentRow, false );
722 else if ( m_groupMode == Head )
723 The::playlistModel()->setCollapsed( m_currentRow, true );
727 QGraphicsItem::mousePressEvent( event );
730 // With help from QGraphicsView::mouseMoveEvent()
731 void
732 Playlist::GraphicsItem::mouseMoveEvent( QGraphicsSceneMouseEvent *event )
734 if( (event->buttons() & Qt::LeftButton) && ( flags() & QGraphicsItem::ItemIsMovable) && m_items )
736 QPointF scenePosition = event->scenePos();
738 if( scenePosition.y() < 0 )
739 return;
741 bool dragOverOriginalPosition = m_items->preDragLocation.contains( scenePosition );
743 //make sure item is drawn on top of other items
744 setZValue( 2.0 );
746 // Determine the list of selected items
747 QList<QGraphicsItem *> selectedItems = scene()->selectedItems();
748 if( !isSelected() )
749 selectedItems << this;
750 // Move all selected items
751 foreach( QGraphicsItem *item, selectedItems )
753 if( (item->flags() & QGraphicsItem::ItemIsMovable) && (!item->parentItem() || !item->parentItem()->isSelected()) )
755 Playlist::GraphicsItem *above = 0;
756 QPointF diff;
757 if( item == this && !dragOverOriginalPosition )
759 diff = event->scenePos() - event->lastScenePos();
760 QList<QGraphicsItem*> collisions = scene()->items( event->scenePos() );
761 foreach( QGraphicsItem *i, collisions )
763 Playlist::GraphicsItem *c = dynamic_cast<Playlist::GraphicsItem *>( i );
764 if( c && c != this )
766 above = c;
767 break;
771 else
773 diff = item->mapToParent( item->mapFromScene(event->scenePos()))
774 - item->mapToParent(item->mapFromScene(event->lastScenePos()));
777 item->moveBy( 0, diff.y() );
778 if( item->flags() & ItemIsSelectable )
779 item->setSelected( true );
781 if( dragOverOriginalPosition )
782 Playlist::DropVis::instance()->show( m_items->preDragLocation.y() );
783 else
784 Playlist::DropVis::instance()->show( above );
788 else
790 QGraphicsItem::mouseMoveEvent( event );
794 void
795 Playlist::GraphicsItem::dragEnterEvent( QGraphicsSceneDragDropEvent *event )
797 foreach( const QString &mime, The::playlistModel()->mimeTypes() )
799 if( event->mimeData()->hasFormat( mime ) )
801 event->accept();
802 Playlist::DropVis::instance()->show( this );
803 break;
808 void
809 Playlist::GraphicsItem::dropEvent( QGraphicsSceneDragDropEvent * event )
811 event->accept();
812 setZValue( 1.0 );
813 The::playlistModel()->dropMimeData( event->mimeData(), Qt::CopyAction, m_currentRow, 0, QModelIndex() );
814 Playlist::DropVis::instance()->hide();
817 void
818 Playlist::GraphicsItem::refresh()
820 QPixmap albumPixmap;
821 if( !m_items || !m_items->track )
822 return;
824 if( m_items->track->album() )
826 if( !m_items->track->album()->hasImage( int(ALBUM_WIDTH) ) )
828 The::coverFetcher()->queueAlbum( m_items->track->album() );
830 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
833 //m_items->albumArt->hide();
834 //delete ( m_items->albumArt );
835 //m_items->albumArt = new QGraphicsPixmapItem( albumPixmap, this );
836 //m_items->albumArt->setPos( 0.0, MARGIN );
839 void Playlist::GraphicsItem::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
841 bool dragOverOriginalPosition = m_items->preDragLocation.contains( event->scenePos() );
842 if( dragOverOriginalPosition )
844 setPos( m_items->preDragLocation.topLeft() );
845 Playlist::DropVis::instance()->hide();
846 return;
849 Playlist::GraphicsItem *above = 0;
850 QList<QGraphicsItem*> collisions = scene()->items( event->scenePos() );
851 foreach( QGraphicsItem *i, collisions )
853 Playlist::GraphicsItem *c = dynamic_cast<Playlist::GraphicsItem *>( i );
854 if( c && c != this )
856 above = c;
857 break;
860 // if we've dropped ourself ontop of another item, then we need to shuffle the tracks below down
861 if( above )
863 setPos( above->pos() );
864 The::playlistView()->moveItem( this, above );
865 } else {
866 //Don't just drop item into the void, make it the last item!
868 The::playlistView()->moveItem( this, 0 );
869 //setPos( above->pos() );
870 //The::playlistView()->moveItem( this, above );
874 //make sure item resets its z value
875 setZValue( 1.0 );
876 Playlist::DropVis::instance()->hide();
879 void Playlist::GraphicsItem::setRow(int row)
881 //DEBUG_BLOCK
882 m_currentRow = row;
884 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
886 //figure out our group state and set height accordingly
887 int currentGroupState = index.data( GroupRole ).toInt();
889 if ( currentGroupState != m_groupMode ) {
891 debug() << "Group changed for row " << row;
893 prepareGeometryChange();
896 m_groupMode = currentGroupState;
897 m_groupModeChanged = true;
899 switch ( m_groupMode ) {
901 case None:
902 debug() << "None";
903 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + 2 * MARGIN + 2;
904 break;
905 case Head:
906 debug() << "Head";
907 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + MARGIN + s_fm->height() + 6;
908 break;
909 case Head_Collapsed:
910 debug() << "Collapsed head";
911 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + MARGIN + s_fm->height() + 10;
912 if ( !m_items ) {
913 const Meta::TrackPtr track = index.data( ItemRole ).value< Playlist::Item* >()->track();
914 m_items = new Playlist::GraphicsItem::ActiveItems();
915 m_items->track = track;
916 init( track );
918 m_items->groupedTracks = index.data( GroupedTracksRole ).toInt();
919 break;
920 case Body:
921 debug() << "Body";
922 m_height = s_fm->height()/*+ 2 * MARGIN*/;
923 break;
924 case End:
925 debug() << "End";
926 m_height = s_fm->height() + 6 /*+ 2 * MARGIN*/;
927 break;
928 case Collapsed:
929 debug() << "Collapsed";
930 m_height = 0;
931 break;
932 default:
933 debug() << "ERROR!!??";
938 void Playlist::GraphicsItem::hoverEnterEvent( QGraphicsSceneHoverEvent *event )
940 Q_UNUSED( event );
941 //DEBUG_BLOCK
943 /*if ( m_groupMode == Head_Collapsed )
944 The::playlistModel()->setCollapsed( m_currentRow, false ); */