1 /***************************************************************************
2 * copyright : (C) 2007 Ian Monroe <ian@monroe.nu> *
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 ***************************************************************************/
11 #include "PlaylistModel.h"
12 #include "PlaylistGraphicsItem.h"
13 #include "PlaylistGraphicsView.h"
14 #include "PlaylistGraphicsScene.h"
15 #include "PlaylistDropVis.h"
16 #include "TheInstances.h"
21 #include <QGraphicsItemAnimation>
22 #include <QModelIndex>
27 Playlist::GraphicsView
*Playlist::GraphicsView::s_instance
= 0;
29 Playlist::GraphicsView::GraphicsView( QWidget
*parent
)
30 : QGraphicsView( parent
)
33 setAlignment( Qt::AlignLeft
| Qt::AlignTop
);
34 setTransformationAnchor( QGraphicsView::AnchorUnderMouse
);
36 setScene( new Playlist::GraphicsScene() );
37 scene()->addItem( Playlist::DropVis::instance() );
42 Playlist::GraphicsView::setModel( Playlist::Model
*model
)
48 rowsInserted( QModelIndex(), 0, m_model
->rowCount() - 1);
50 connect( m_model
, SIGNAL( modelReset() ), this, SLOT( modelReset() ) );
51 connect( m_model
, SIGNAL( rowsInserted( const QModelIndex
&, int, int ) ), this, SLOT( rowsInserted( const QModelIndex
&, int, int ) ) );
52 connect( m_model
, SIGNAL( rowsRemoved( const QModelIndex
&, int, int ) ), this, SLOT( rowsRemoved( const QModelIndex
&, int, int ) ) );
53 connect( m_model
, SIGNAL( dataChanged( const QModelIndex
&, const QModelIndex
& ) ), this, SLOT( dataChanged( const QModelIndex
& ) ) );
58 Playlist::GraphicsView::contextMenuEvent( QContextMenuEvent
*event
)
60 QPointF sceneClickPos
= mapToScene( event
->pos() );
61 QGraphicsItem
*topItem
= scene()->itemAt( sceneClickPos
);
66 Playlist::GraphicsItem
*item
= dynamic_cast<Playlist::GraphicsItem
*>( topItem
);
68 item
= dynamic_cast<Playlist::GraphicsItem
*>( topItem
->parentItem() );
69 if( !item
) // we've clicked on empty space
72 item
->setSelected( true );
75 KAction
*playAction
= new KAction( KIcon( Amarok::icon( "play" ) ), i18n( "&Play" ), this );
76 playAction
->setData( QVariant( sceneClickPos
) );
77 connect( playAction
, SIGNAL( triggered() ), this, SLOT( playTrack() ) );
79 KMenu
*menu
= new KMenu( this );
80 menu
->addAction( playAction
);
82 menu
->addAction( i18n( "Remove From Playlist" ), this, SLOT( removeSelection() ) );
83 menu
->exec( event
->globalPos() );
87 Playlist::GraphicsView::keyPressEvent( QKeyEvent
* event
)
90 debug() << "Pressed: " << event
;
91 if( event
->matches( QKeySequence::Delete
) )
93 if( !scene()->selectedItems().isEmpty() )
100 QGraphicsView::keyPressEvent( event
);
104 Playlist::GraphicsView::playTrack()
106 QAction
*playAction
= dynamic_cast<QAction
*>( sender() );
110 QPointF sceneClickPos
= playAction
->data().toPointF();
111 Playlist::GraphicsItem
*item
= dynamic_cast<Playlist::GraphicsItem
*>( scene()->itemAt( sceneClickPos
)->parentItem() );
118 Playlist::GraphicsView::removeSelection()
120 QList
<QGraphicsItem
*> selection
= scene()->selectedItems();
121 foreach( QGraphicsItem
*i
, selection
)
123 int index
= m_tracks
.indexOf( static_cast<Playlist::GraphicsItem
*>(i
) );
124 m_model
->removeRows( index
, 1 );
129 Playlist::GraphicsView::rowsInserted( const QModelIndex
& parent
, int start
, int end
)
133 //call setRow on track imidiately preceding the insertion as this might have to change its
134 // look and height if it has been grouped by the model.
136 m_tracks
[ start
-1]->setRow( start
-1 );
138 int cumulativeHeight
= 0;
139 for ( int j
= 0; j
< start
; j
++ )
140 cumulativeHeight
+= m_tracks
.at( j
)->boundingRect().height();
142 debug() << "start: " << start
<< " ,end: " << end
;
143 for( int i
= start
; i
<= end
; i
++ )
146 Playlist::GraphicsItem
* item
= new Playlist::GraphicsItem();
148 item
->setPos( 0.0, cumulativeHeight
);
149 cumulativeHeight
+= item
->boundingRect().height();
150 scene()->addItem( item
);
151 m_tracks
.insert( i
, item
);
154 // make sure all following tracks has their colors updated correctly
155 for ( int i
= end
+ 1 ; i
< m_tracks
.count(); i
++ )
156 m_tracks
.at( i
)->setRow( i
);
158 shuffleTracks( end
+ 1 );
162 Playlist::GraphicsView::rowsRemoved(const QModelIndex
& parent
, int start
, int end
)
166 for( int i
= end
; i
>= start
; i
-- )
167 delete m_tracks
.takeAt( i
);
169 // make sure all following tracks has their colors updated correctly
170 for ( int i
= start
; i
< m_tracks
.count(); i
++ )
171 m_tracks
.at( i
)->setRow( i
);
174 shuffleTracks( start
);
178 Playlist::GraphicsView::moveItem( Playlist::GraphicsItem
*moveMe
, Playlist::GraphicsItem
*above
)
180 int moveMeIndex
= m_tracks
.indexOf( moveMe
);
181 int aboveIndex
= m_tracks
.indexOf( above
);
183 //call set row on all items below the first one potentially modified to
184 //make sure that all items have correct background color and group info
187 if( moveMeIndex
< aboveIndex
)
189 m_model
->moveRow( moveMeIndex
, aboveIndex
-1 );
190 m_tracks
.move( moveMeIndex
, aboveIndex
- 1 );
194 for ( i
= moveMeIndex
; i
< m_tracks
.count(); i
++ )
195 m_tracks
.at( i
)->setRow( i
);
198 shuffleTracks( moveMeIndex
, aboveIndex
);
202 m_model
->moveRow( moveMeIndex
, aboveIndex
);
203 m_tracks
.move( moveMeIndex
, aboveIndex
);
206 for ( i
= aboveIndex
; i
< m_tracks
.count(); i
++ )
207 m_tracks
.at( i
)->setRow( i
);
209 shuffleTracks( aboveIndex
, moveMeIndex
+ 1);
214 Playlist::GraphicsView::shuffleTracks( int startPosition
, int stopPosition
)
216 if( startPosition
< 0 )
219 if( stopPosition
< 0 || stopPosition
> m_tracks
.size() )
220 stopPosition
= m_tracks
.size();
222 QTimeLine
*timer
= new QTimeLine( 300 ); // 0.3 second duration
223 timer
->setCurveShape( QTimeLine::EaseInCurve
);
226 int cumulativeHeight
= 0;
228 for ( int j
= 0; j
< startPosition
; j
++ )
229 cumulativeHeight
+= m_tracks
.at( j
)->boundingRect().height();
231 for( int i
= startPosition
; i
< stopPosition
; ++i
)
233 Playlist::GraphicsItem
*item
= m_tracks
.at( i
);
234 qreal currentY
= item
->pos().y();
237 qreal desiredY
= cumulativeHeight
;
238 cumulativeHeight
+= item
->boundingRect().height();
241 if( desiredY
> currentY
)
244 qreal distanceMoved
= moveUp
? ( desiredY
- currentY
) : ( currentY
- desiredY
);
246 QGraphicsItemAnimation
*animator
= new QGraphicsItemAnimation
;
247 animator
->setItem( item
);
248 animator
->setTimeLine( timer
);
250 // if distanceMoved is negative, then we are moving the object towards the bottom of the screen
251 for( qreal i
= 0; i
< distanceMoved
; ++i
)
253 qreal newY
= moveUp
? ( currentY
+ i
) : ( currentY
- i
);
254 animator
->setPosAt( i
/ distanceMoved
, QPointF( 0.0, newY
) );
261 Playlist::GraphicsView::modelReset()
263 foreach( Playlist::GraphicsItem
* it
, m_tracks
)
271 Playlist::GraphicsView::dataChanged(const QModelIndex
& index
)
274 if ( !index
.isValid() )
277 if ( m_tracks
.count() > index
.row() )
278 m_tracks
.at( index
.row() )->refresh();
282 Playlist::GraphicsView
* playlistView() { return Playlist::GraphicsView::instance(); }
286 #include "PlaylistGraphicsView.moc"