Make the active (playing) track marker look a bit better. It is now rendered from...
[amarok.git] / src / playlist / PlaylistGraphicsItem.cpp
blob53aa2f7ba1911780baf5d94a615a6adfbdf447be
1 /***************************************************************************
2 * copyright : (C) 2007 Ian Monroe <ian@monroe.nu> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License version 2 *
6 * as published by the Free Software Foundation. *
7 ***************************************************************************/
9 #include "debug.h"
10 #include "meta/MetaUtility.h"
11 #include "AmarokMimeData.h"
12 #include "PlaylistGraphicsItem.h"
13 #include "PlaylistGraphicsView.h"
14 #include "PlaylistDropVis.h"
15 #include "PlaylistModel.h"
16 #include "PlaylistTextItem.h"
17 #include "TheInstances.h"
19 #include "KStandardDirs"
21 #include <QBrush>
22 #include <QDrag>
23 #include <QFontMetricsF>
24 #include <QGraphicsScene>
25 #include <QGraphicsTextItem>
26 #include <QGraphicsPixmapItem>
27 #include <QGraphicsRectItem>
28 #include <QGraphicsSceneMouseEvent>
29 #include <QGraphicsView>
30 #include <QMimeData>
31 #include <QPen>
32 #include <QPixmapCache>
33 #include <QRadialGradient>
34 #include <QScrollBar>
35 #include <QStyleOptionGraphicsItem>
37 #include <KLocale>
39 struct Playlist::GraphicsItem::ActiveItems
41 ActiveItems()
42 : foreground( 0 )
43 , bottomLeftText( 0 )
44 , bottomRightText( 0 )
45 , topLeftText( 0 )
46 , topRightText( 0 )
47 , lastWidth( -5 )
48 , groupedTracks ( 0 )
49 , collapsible( true )
50 { }
51 ~ActiveItems()
53 delete bottomLeftText;
54 delete bottomRightText;
55 delete foreground;
56 delete topLeftText;
57 delete topRightText;
61 QGraphicsPixmapItem* foreground;
62 Playlist::TextItem* bottomLeftText;
63 Playlist::TextItem* bottomRightText;
64 Playlist::TextItem* topLeftText;
65 Playlist::TextItem* topRightText;
67 QColor overlayGradientStart;
68 QColor overlayGradientEnd;
70 int lastWidth;
71 int groupedTracks;
72 bool collapsible;
74 QRectF preDragLocation;
75 Meta::TrackPtr track;
79 const qreal Playlist::GraphicsItem::ALBUM_WIDTH = 50.0;
80 const qreal Playlist::GraphicsItem::MARGIN = 4.0;
81 QFontMetricsF* Playlist::GraphicsItem::s_fm = 0;
82 QSvgRenderer * Playlist::GraphicsItem::s_svgRenderer = 0;
84 Playlist::GraphicsItem::GraphicsItem()
85 : QGraphicsItem()
86 , m_items( 0 )
87 , m_height( -1 )
88 , m_groupMode( -1 )
89 , m_groupModeChanged ( false )
90 , m_collapsible ( true )
92 setZValue( 1.0 );
93 if( !s_fm )
95 s_fm = new QFontMetricsF( QFont() );
96 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + 2 * MARGIN;
99 if ( !s_svgRenderer ) {
100 s_svgRenderer = new QSvgRenderer( KStandardDirs::locate( "data","amarok/images/playlist_items.svg" ));
101 if ( ! s_svgRenderer->isValid() )
102 debug() << "svg is kaputski";
105 setFlag( QGraphicsItem::ItemIsSelectable );
106 setFlag( QGraphicsItem::ItemIsMovable );
107 setAcceptDrops( true );
108 // setHandlesChildEvents( true ); // don't let drops etc hit the text items, doing stupid things
111 Playlist::GraphicsItem::~GraphicsItem()
113 delete m_items;
116 void
117 Playlist::GraphicsItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget )
119 // ::paint RULES:
120 // 1) You do not talk about ::paint method
121 // 2) You DO NOT talk about ::paint method
122 // 3) Do not show or hide item that are already shown or hidden, respectively
123 // 4) Do not setBrush without making sure its hasn't already been set to that brush().
124 // 5) If this is your first night at ::paint method, you HAVE to paint.
125 Q_UNUSED( painter ); Q_UNUSED( widget );
127 //debug() << "painting row: " << m_currentRow;
128 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
130 if( !m_items || ( option->rect.width() != m_items->lastWidth ) || m_groupModeChanged )
133 if( !m_items )
135 const Meta::TrackPtr track = index.data( ItemRole ).value< Playlist::Item* >()->track();
136 m_items = new Playlist::GraphicsItem::ActiveItems();
137 m_items->track = track;
138 init( track );
140 m_groupModeChanged = false;
141 resize( m_items->track, option->rect.width() );
145 if ( m_groupMode == Collapsed ) {
146 // just make sure text items are hidden and then get the heck out of here...
147 // whoops... this has got to be moved here below the check for (!m_items) or
148 // it will evetually crasah....
149 if( m_items->topRightText->isVisible() )
150 m_items->topRightText->hide();
151 if( m_items->topLeftText->isVisible() )
152 m_items->topLeftText->hide();
153 if( m_items->bottomRightText->isVisible() )
154 m_items->bottomRightText->hide();
155 if( m_items->bottomLeftText->isVisible() )
156 m_items->bottomLeftText->hide();
158 return;
162 // paint item background:
163 QRectF trackRect;
164 QRectF headRect;
165 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
167 //make the album group header stand out
168 //painter->fillRect( option->rect, QBrush( Qt::darkCyan ) );
169 trackRect = QRectF( option->rect.x(), ALBUM_WIDTH + 2 * MARGIN, option->rect.width(), s_fm->height() /*+ MARGIN*/ );
170 if (m_groupMode == Head )
171 headRect = option->rect;
172 else
173 headRect = QRectF( option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height() - 2 );
175 } else {
176 trackRect = option->rect;
178 if ( ( m_groupMode != Body) && !( ( m_groupMode == Head ) ) )
179 trackRect.setHeight( trackRect.height() - 2 ); // add a little space between items
183 if ( m_groupMode == None ) {
185 QString key = QString("track:%1x%2").arg(trackRect.width()).arg(trackRect.height());
186 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
187 background.fill( Qt::transparent );
190 if (!QPixmapCache::find(key, background)) {
191 QPainter pt( &background );
192 s_svgRenderer->render( &pt, "track", trackRect );
193 QPixmapCache::insert(key, background);
195 painter->drawPixmap( 0, 0, background );
196 } else if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
198 QString svgName;
199 if ( m_groupMode == Head )
200 svgName = "head";
201 else
202 svgName = "collapsed_head";
204 QString key = QString("%1:%2x%3").arg( svgName ).arg( headRect.width() ).arg( headRect.height() );
205 QPixmap background( headRect.width(), headRect.height() );
206 background.fill( Qt::transparent );
208 if ( !QPixmapCache::find( key, background ) ) {
209 QPainter pt( &background );
210 s_svgRenderer->render( &pt, svgName, headRect );
211 QPixmapCache::insert( key, background );
213 painter->drawPixmap( 0, 0, background );
215 //"Just for fun" stuff below this point
217 //ask if we are allowed to collapse thid group:
218 //m_collapsible = index.data( GroupedCollapsibleRole ).toBool();
220 QString collapseString;
221 if ( m_groupMode == Head ) {
222 if ( m_collapsible )
223 collapseString = "collapse_button";
224 else
225 collapseString = "collapse_button_grayed_out";
226 } else
227 collapseString = "expand_button";
230 key = QString("%1:%2x%3").arg( collapseString ).arg( 16 ).arg( 16 );
231 QPixmap collapsePixmap( 16, 16 );
232 collapsePixmap.fill( Qt::transparent );
234 if (!QPixmapCache::find(key, collapsePixmap)) {
235 QPainter pt2( &collapsePixmap );
236 s_svgRenderer->render( &pt2, collapseString, QRectF( 0, 0, 16, 16 ) );
237 QPixmapCache::insert(key, collapsePixmap);
240 painter->drawPixmap( option->rect.width() - ( 16 + MARGIN ) , MARGIN, collapsePixmap );
244 } else if ( m_groupMode == Body ) {
246 QString key = QString("body:%1x%2").arg(trackRect.width()).arg(trackRect.height());
247 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
248 background.fill( Qt::transparent );
250 if (!QPixmapCache::find(key, background)) {
251 QPainter pt( &background );
252 s_svgRenderer->render( &pt, "body", trackRect );
253 QPixmapCache::insert(key, background);
255 painter->drawPixmap( 0, 0, background );
256 } else if ( m_groupMode == End ) {
258 QString key = QString( "tail:%1x%2" ).arg( trackRect.width() ).arg(trackRect.height()) ;
259 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
260 background.fill( Qt::transparent );
262 if (!QPixmapCache::find(key, background)) {
263 QPainter pt( &background );
264 s_svgRenderer->render( &pt, "tail", trackRect );
265 QPixmapCache::insert(key, background);
267 painter->drawPixmap( 0, 0, background );
273 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) || ( m_groupMode == Body ) || ( m_groupMode == End ) ) {
274 if ( index.data( GroupedAlternateRole ).toBool() ) {
276 QString key = QString( "alternate:%1x%2" ).arg( trackRect.width() - 10 ).arg(trackRect.height() );
277 QPixmap background( (int)( trackRect.width() - 10 ), (int)( trackRect.height() ) );
279 QRectF tempRect = trackRect;
280 tempRect.setWidth( tempRect.width() - 10 );
281 if ( m_groupMode == End )
282 tempRect.setHeight( tempRect.height() - 4 );
284 if (!QPixmapCache::find( key, background ) ) {
285 background.fill( Qt::transparent );
286 QPainter pt( &background );
287 s_svgRenderer->render( &pt, "body_background", tempRect );
288 QPixmapCache::insert( key, background );
291 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ))
292 painter->drawPixmap( 5, (int)( MARGIN + ALBUM_WIDTH + 2 ), background );
293 else
294 painter->drawPixmap( 5, 0, background );
301 if ( m_groupMode < Body ) {
302 //if we are not grouped, or are the head of a group, paint cover:
303 QPixmap albumPixmap;
304 if( m_items->track->album() )
305 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
306 painter->drawPixmap( (int)( MARGIN ), (int)( MARGIN ), albumPixmap );
307 //and make sure the top text elements are shown
308 if( !m_items->topRightText->isVisible() )
309 m_items->topRightText->show();
310 if( !m_items->topLeftText->isVisible() )
311 m_items->topLeftText->show();
313 } else {
314 //if not, make sure that the top text items are not shown
315 if( m_items->topRightText->isVisible() )
316 m_items->topRightText->hide();
317 if( m_items->topLeftText->isVisible() )
318 m_items->topLeftText->hide();
319 if( !m_items->bottomRightText->isVisible() )
320 m_items->bottomRightText->show();
321 if( !m_items->bottomLeftText->isVisible() )
322 m_items->bottomLeftText->show();
325 //set selection marker if needed
327 if( option->state & QStyle::State_Selected )
329 painter->fillRect( trackRect, QBrush( QColor( 0, 0, 255, 128 ) ) );
334 //set overlay if item is active:
335 if( index.data( ActiveTrackRole ).toBool() )
337 if( !m_items->foreground )
340 debug() << "Creating active track overlay";
341 m_items->foreground = new QGraphicsPixmapItem( this );
342 m_items->foreground->setPos( 0.0, trackRect.top() );
343 m_items->foreground->setZValue( 10.0 );
346 QString key = QString("active_overlay:%1x%2").arg(trackRect.width()).arg(trackRect.height());
347 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
348 background.fill( Qt::transparent );
350 debug() << "Key string: " << key;
352 if (!QPixmapCache::find(key, background)) {
353 QPainter pt( &background );
354 s_svgRenderer->render( &pt, "active_overlay", QRectF( 0, 0, trackRect.width(), trackRect.height() ) );
355 QPixmapCache::insert(key, background);
357 m_items->foreground->setPixmap( background );
358 m_items->foreground->show();
359 debug() << "Done";
362 /*QRadialGradient gradient(trackRect.width() / 2.0, trackRect.height() / 2.0, trackRect.width() / 2.0, 20 + trackRect.width() / 2.0, trackRect.height() / 2.0 );
363 m_items->overlayGradientStart = option->palette.highlightedText().color().light();
364 m_items->overlayGradientStart.setAlpha( 80 );
365 m_items->overlayGradientEnd = option->palette.highlightedText().color().dark();
366 m_items->overlayGradientEnd.setAlpha( 80 );
367 gradient.setColorAt( 0.0, m_items->overlayGradientStart );
368 gradient.setColorAt( 1.0, m_items->overlayGradientEnd );
369 QBrush brush( gradient );
370 m_items->foreground->setBrush( brush );
371 m_items->foreground->setPen( QPen( Qt::NoPen ) );*/
373 if( !m_items->foreground->isVisible() )
374 m_items->foreground->show();
375 } else if( m_items->foreground && m_items->foreground->isVisible() )
376 m_items->foreground->hide();
379 void
380 Playlist::GraphicsItem::init( Meta::TrackPtr track )
382 Q_UNUSED( track );
383 QFont font;
384 font.setPointSize( font.pointSize() - 1 );
385 #define NewText( X ) \
386 X = new Playlist::TextItem( this ); \
387 X->setTextInteractionFlags( Qt::TextEditorInteraction ); \
388 X->setFont( font );
389 NewText( m_items->topLeftText )
390 NewText( m_items->bottomLeftText )
391 NewText( m_items->topRightText )
392 NewText( m_items->bottomRightText )
393 #undef NewText
396 void
397 Playlist::GraphicsItem::resize( Meta::TrackPtr track, int totalWidth )
399 if( totalWidth == -1 /*|| totalWidth == m_items->lastWidth */) //no change needed
400 return;
401 if( m_items->lastWidth != -5 ) //this isn't the first "resize"
402 prepareGeometryChange();
403 m_items->lastWidth = totalWidth;
405 QString prettyLength;
407 if ( m_groupMode == Head_Collapsed ) {
408 uint seconds = 0;
409 for( uint i = m_currentRow; i < m_currentRow + m_items->groupedTracks; i++ )
410 seconds += The::playlistModel()->itemList()[ i ]->track()->length();
411 prettyLength = Meta::secToPrettyTime( seconds );
412 } else
413 prettyLength = Meta::secToPrettyTime( track->length() );
415 QString album;
416 if( track->album() )
417 album = track->album()->name();
419 const qreal lineTwoY = m_height / 2 + MARGIN;
420 const qreal textWidth = ( ( qreal( totalWidth ) - ALBUM_WIDTH ) / 2.0 );
421 const qreal leftAlignX = ALBUM_WIDTH + MARGIN;
422 qreal topRightAlignX;
423 qreal bottomRightAlignX;
426 qreal middle = textWidth + ALBUM_WIDTH + ( MARGIN * 2.0 );
427 qreal rightWidth = totalWidth - qMax( s_fm->width( album )
428 , s_fm->width( prettyLength ) );
429 topRightAlignX = qMax( middle, rightWidth );
432 //lets use all the horizontal space we can get for now..
433 int lengthStringWidth = (int)(s_fm->width( prettyLength ));
434 bottomRightAlignX = ( totalWidth - 4 * MARGIN ) - lengthStringWidth ;
439 qreal spaceForTopLeft = totalWidth - ( totalWidth - topRightAlignX ) - leftAlignX;
440 qreal spaceForBottomLeft = totalWidth - ( totalWidth - bottomRightAlignX ) - leftAlignX;
442 if ( m_groupMode == Head_Collapsed ) {
444 m_items->bottomLeftText->setEditableText( QString("%1 tracks").arg( QString::number( m_items->groupedTracks ) ) , spaceForBottomLeft );
445 QFont f = m_items->bottomLeftText->font();
446 f.setItalic( true );
447 m_items->bottomLeftText->setFont( f );
448 m_items->bottomRightText->setEditableText( prettyLength, totalWidth - bottomRightAlignX );
450 } else {
451 m_items->bottomLeftText->setFont( m_items->bottomRightText->font() );
452 m_items->bottomLeftText->setEditableText( QString("%1 - %2").arg( QString::number( track->trackNumber() ), track->name() ) , spaceForBottomLeft );
453 m_items->bottomRightText->setEditableText( prettyLength, totalWidth - bottomRightAlignX );
455 if ( m_groupMode == None ) {
457 m_items->topRightText->setPos( topRightAlignX, MARGIN );
458 m_items->topRightText->setEditableText( album, totalWidth - topRightAlignX );
461 QString artist;
462 if( track->artist() )
463 artist = track->artist()->name();
464 m_items->topLeftText->setEditableText( artist, spaceForTopLeft );
465 m_items->topLeftText->setPos( leftAlignX, MARGIN );
468 m_items->bottomLeftText->setPos( leftAlignX, lineTwoY );
469 m_items->bottomRightText->setPos( bottomRightAlignX, lineTwoY );
470 } else if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
472 int headingCenter = (int)( MARGIN + ( ALBUM_WIDTH - s_fm->height()) / 2 );
474 m_items->topRightText->setPos( topRightAlignX, headingCenter );
475 m_items->topRightText->setEditableText( album, totalWidth - topRightAlignX );
478 QString artist;
479 //various artist handling:
480 //if the album has no albumartist, use Various Artists, otherwise use the albumartist's name
481 if( track->album()->albumArtist() )
482 artist = track->album()->albumArtist()->name();
483 else
485 artist = findArtistForCurrentAlbum();
486 if( artist.isEmpty() )
487 artist = i18n( "Various Artists" );
489 m_items->topLeftText->setEditableText( artist, spaceForTopLeft );
490 m_items->topLeftText->setPos( leftAlignX, headingCenter );
493 int underImageY = (int)( MARGIN + ALBUM_WIDTH + 2 );
495 m_items->bottomLeftText->setPos( MARGIN * 3, underImageY );
496 m_items->bottomRightText->setPos( bottomRightAlignX, underImageY );
498 } else {
499 m_items->bottomLeftText->setPos( MARGIN * 3, 0 );
500 m_items->bottomRightText->setPos( bottomRightAlignX, 0 );
503 //make sure the activ eitem overlay has the correct width
507 if( m_items->foreground )
510 QRectF trackRect;
511 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
512 trackRect = QRectF( 0, ALBUM_WIDTH + 2 * MARGIN, totalWidth, s_fm->height() /*+ MARGIN*/ );
513 } else {
514 trackRect = QRectF( 0, 0, totalWidth, m_height );
515 if ( ( m_groupMode != Body) && !( ( m_groupMode == Head ) ) )
516 trackRect.setHeight( trackRect.height() - 2 ); // add a little space between items
519 debug() << "Resizing active track overlay";
521 QString key = QString("active_overlay:%1x%2").arg(trackRect.width()).arg(trackRect.height());
523 debug() << "Key string: " << key;
524 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
525 background.fill( Qt::transparent );
528 if (!QPixmapCache::find(key, background)) {
529 QPainter pt( &background );
530 s_svgRenderer->render( &pt, "active_overlay", trackRect );
531 QPixmapCache::insert(key, background);
533 m_items->foreground->setPixmap( background );
534 m_items->foreground->setZValue( 10.0 );
536 debug() << "Done";
540 m_items->lastWidth = totalWidth;
543 QString
544 Playlist::GraphicsItem::findArtistForCurrentAlbum() const
546 if( !( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) )
547 return QString();
549 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
550 if( ! ( ( index.data( GroupRole ).toInt() == Head ) || ( index.data( GroupRole ).toInt() == Head_Collapsed ) ) )
552 return QString();
554 else
556 QString artist;
557 Meta::TrackPtr currentTrack = index.data( TrackRole ).value< Meta::TrackPtr >();
558 if( currentTrack->artist() )
559 artist = currentTrack->artist()->name();
560 else
561 return QString();
562 //it's an album group, and the current row is the head, so the next row is either Body or End
563 //that means we have to execute the loop at least once
564 QModelIndex idx;
565 int row = m_currentRow + 1;
568 idx = The::playlistModel()->index( row++, 0 );
569 Meta::TrackPtr track = idx.data( TrackRole ).value< Meta::TrackPtr >();
570 if( track->artist() )
572 if( artist != track->artist()->name() )
573 return QString();
575 else
577 return QString();
580 while( idx.data( GroupRole ).toInt() == Body );
582 return artist;
586 QRectF
587 Playlist::GraphicsItem::boundingRect() const
589 // the viewport()->size() takes scrollbars into account
590 return QRectF( 0.0, 0.0, The::playlistView()->viewport()->size().width(), m_height );
593 void
594 Playlist::GraphicsItem::play()
596 The::playlistModel()->play( m_currentRow );
599 void
600 Playlist::GraphicsItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event )
602 if( m_items )
604 event->accept();
605 play();
606 return;
608 QGraphicsItem::mouseDoubleClickEvent( event );
611 void
612 Playlist::GraphicsItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
614 if( event->buttons() & Qt::RightButton || !m_items )
616 event->ignore();
617 return;
619 m_items->preDragLocation = mapToScene( boundingRect() ).boundingRect();
621 //did we hit the collapse / expand button?
622 if ( m_collapsible ) {
623 QRectF rect( boundingRect().width() - ( 16 + MARGIN ), MARGIN, 16, 16 );
624 if ( rect.contains( event->pos() ) ) {
625 if ( m_groupMode == Head_Collapsed )
626 The::playlistModel()->setCollapsed( m_currentRow, false );
627 else if ( m_groupMode == Head )
628 The::playlistModel()->setCollapsed( m_currentRow, true );
633 QGraphicsItem::mousePressEvent( event );
636 // With help from QGraphicsView::mouseMoveEvent()
637 void
638 Playlist::GraphicsItem::mouseMoveEvent( QGraphicsSceneMouseEvent *event )
640 if( (event->buttons() & Qt::LeftButton) && ( flags() & QGraphicsItem::ItemIsMovable) && m_items )
642 QPointF scenePosition = event->scenePos();
644 if( scenePosition.y() < 0 )
645 return;
647 bool dragOverOriginalPosition = m_items->preDragLocation.contains( scenePosition );
649 //make sure item is drawn on top of other items
650 setZValue( 2.0 );
652 // Determine the list of selected items
653 QList<QGraphicsItem *> selectedItems = scene()->selectedItems();
654 if( !isSelected() )
655 selectedItems << this;
656 // Move all selected items
657 foreach( QGraphicsItem *item, selectedItems )
659 if( (item->flags() & QGraphicsItem::ItemIsMovable) && (!item->parentItem() || !item->parentItem()->isSelected()) )
661 Playlist::GraphicsItem *above = 0;
662 QPointF diff;
663 if( item == this && !dragOverOriginalPosition )
665 diff = event->scenePos() - event->lastScenePos();
666 QList<QGraphicsItem*> collisions = scene()->items( event->scenePos() );
667 foreach( QGraphicsItem *i, collisions )
669 Playlist::GraphicsItem *c = dynamic_cast<Playlist::GraphicsItem *>( i );
670 if( c && c != this )
672 above = c;
673 break;
677 else
679 diff = item->mapToParent( item->mapFromScene(event->scenePos()))
680 - item->mapToParent(item->mapFromScene(event->lastScenePos()));
683 item->moveBy( 0, diff.y() );
684 if( item->flags() & ItemIsSelectable )
685 item->setSelected( true );
687 if( dragOverOriginalPosition )
688 Playlist::DropVis::instance()->show( m_items->preDragLocation.y() );
689 else
690 Playlist::DropVis::instance()->show( above );
694 else
696 QGraphicsItem::mouseMoveEvent( event );
700 void
701 Playlist::GraphicsItem::dragEnterEvent( QGraphicsSceneDragDropEvent *event )
703 foreach( QString mime, The::playlistModel()->mimeTypes() )
705 if( event->mimeData()->hasFormat( mime ) )
707 event->accept();
708 Playlist::DropVis::instance()->show( this );
709 break;
714 void
715 Playlist::GraphicsItem::dropEvent( QGraphicsSceneDragDropEvent * event )
717 event->accept();
718 setZValue( 1.0 );
719 The::playlistModel()->dropMimeData( event->mimeData(), Qt::CopyAction, m_currentRow, 0, QModelIndex() );
720 Playlist::DropVis::instance()->hide();
723 void
724 Playlist::GraphicsItem::refresh()
726 QPixmap albumPixmap;
727 if( !m_items || !m_items->track )
728 return;
730 if( m_items->track->album() )
731 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
733 //m_items->albumArt->hide();
734 //delete ( m_items->albumArt );
735 //m_items->albumArt = new QGraphicsPixmapItem( albumPixmap, this );
736 //m_items->albumArt->setPos( 0.0, MARGIN );
739 void Playlist::GraphicsItem::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
741 bool dragOverOriginalPosition = m_items->preDragLocation.contains( event->scenePos() );
742 if( dragOverOriginalPosition )
744 setPos( m_items->preDragLocation.topLeft() );
745 Playlist::DropVis::instance()->hide();
746 return;
749 Playlist::GraphicsItem *above = 0;
750 QList<QGraphicsItem*> collisions = scene()->items( event->scenePos() );
751 foreach( QGraphicsItem *i, collisions )
753 Playlist::GraphicsItem *c = dynamic_cast<Playlist::GraphicsItem *>( i );
754 if( c && c != this )
756 above = c;
757 break;
760 // if we've dropped ourself ontop of another item, then we need to shuffle the tracks below down
761 if( above )
763 setPos( above->pos() );
764 The::playlistView()->moveItem( this, above );
765 } else {
766 //Don't just drop item into the void, make it the last item!
768 The::playlistView()->moveItem( this, 0 );
769 //setPos( above->pos() );
770 //The::playlistView()->moveItem( this, above );
774 //make sure item resets its z value
775 setZValue( 1.0 );
776 Playlist::DropVis::instance()->hide();
779 void Playlist::GraphicsItem::setRow(int row)
781 //DEBUG_BLOCK
782 m_currentRow = row;
784 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
786 //figure out our group state and set height accordingly
787 int currentGroupState = index.data( GroupRole ).toInt();
789 if ( currentGroupState != m_groupMode ) {
791 debug() << "Group changed for row " << row;
793 prepareGeometryChange();
796 m_groupMode = currentGroupState;
797 m_groupModeChanged = true;
799 switch ( m_groupMode ) {
801 case None:
802 debug() << "None";
803 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + 2 * MARGIN + 2;
804 break;
805 case Head:
806 debug() << "Head";
807 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + MARGIN + s_fm->height() + 4;
808 break;
809 case Head_Collapsed:
810 debug() << "Collapsed head";
811 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + MARGIN + s_fm->height() + 10;
812 if ( !m_items ) {
813 const Meta::TrackPtr track = index.data( ItemRole ).value< Playlist::Item* >()->track();
814 m_items = new Playlist::GraphicsItem::ActiveItems();
815 m_items->track = track;
816 init( track );
818 m_items->groupedTracks = index.data( GroupedTracksRole ).toInt();
819 break;
820 case Body:
821 debug() << "Body";
822 m_height = s_fm->height()/*+ 2 * MARGIN*/;
823 break;
824 case End:
825 debug() << "End";
826 m_height = s_fm->height() + 6 /*+ 2 * MARGIN*/;
827 break;
828 case Collapsed:
829 debug() << "Collapsed";
830 m_height = 0;
831 break;
832 default:
833 debug() << "ERROR!!??";
838 void Playlist::GraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
840 //DEBUG_BLOCK
842 /*if ( m_groupMode == Head_Collapsed )
843 The::playlistModel()->setCollapsed( m_currentRow, false ); */