1 /*****************************************************************************
2 * views.cpp : Views for the Playlist
3 ****************************************************************************
4 * Copyright © 2010 the VideoLAN team
7 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include "components/playlist/views.hpp"
25 #include "components/playlist/vlc_model.hpp" /* VLCModel */
26 #include "components/playlist/sorting.h" /* Columns List */
27 #include "input_manager.hpp" /* THEMIM */
31 #include <QStyleOptionViewItem>
32 #include <QFontMetrics>
34 #include <QDragMoveEvent>
36 #include <QHeaderView>
40 /* ICON_SCALER comes currently from harrison-stetson method, so good value */
41 #define ICON_SCALER 16
45 void AbstractPlViewItemDelegate::paintBackground(
46 QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
48 /* FIXME: This does not indicate item selection in all QStyles, so for the time being we
49 have to draw it ourselves, to ensure visible effect of selection on all platforms */
50 /* QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &option,
54 QRect r = option.rect.adjusted( 0, 0, -1, -1 );
55 if( option.state & QStyle::State_Selected )
57 painter->setBrush( option.palette.color( QPalette::Highlight ) );
58 painter->setPen( option.palette.color( QPalette::Highlight ).darker( 150 ) );
59 painter->drawRect( r );
61 else if( index.data( VLCModel::IsCurrentRole ).toBool() )
63 painter->setBrush( QBrush( Qt::lightGray ) );
64 painter->setPen( QColor( Qt::darkGray ) );
65 painter->drawRect( r );
67 if( option.state & QStyle::State_MouseOver )
68 { /* requires WA_hover on viewport */
69 painter->setOpacity( 0.5 );
70 painter->setPen( Qt::NoPen );
71 painter->setBrush( option.palette.color( QPalette::Highlight ).lighter( 150 ) );
72 painter->drawRect( option.rect );
77 void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
79 QString title = VLCModel::getMeta( index, COLUMN_TITLE );
80 QString artist = VLCModel::getMeta( index, COLUMN_ARTIST );
82 QFont font( index.data( Qt::FontRole ).value<QFont>() );
83 font.setPointSize( __MAX( font.pointSize() + i_zoom, 4 ) );
84 font.setBold( index.data( VLCModel::IsCurrentRole ).toBool() );
85 painter->setFont( font );
86 QFontMetrics fm = painter->fontMetrics();
88 int averagewidth = fm.averageCharWidth();
89 QSize rectSize = option.rect.size();
90 int art_width = averagewidth * ICON_SCALER;
91 int art_height = averagewidth * ICON_SCALER;
93 QPixmap artPix = VLCModel::getArtPixmap( index, QSize( art_width, art_height) );
95 paintBackground( painter, option, index );
99 QRect artRect( option.rect.x() + ( rectSize.width() - artPix.width() ) / 2,
100 option.rect.y() - averagewidth*3 + ( rectSize.height() - artPix.height() ) / 2,
101 artPix.width(), artPix.height() );
103 // Draw the drop shadow
105 painter->setOpacity( 0.7 );
106 painter->setBrush( QBrush( Qt::darkGray ) );
107 painter->setPen( Qt::NoPen );
108 painter->drawRoundedRect( artRect.adjusted( 0, 0, 2, 2 ), ART_RADIUS, ART_RADIUS );
111 // Draw the art pixmap
112 QPainterPath artRectPath;
113 artRectPath.addRoundedRect( artRect, ART_RADIUS, ART_RADIUS );
114 painter->setClipPath( artRectPath );
115 painter->drawPixmap( artRect, artPix );
116 painter->setClipping( false );
118 if( option.state & QStyle::State_Selected )
119 painter->setPen( option.palette.color( QPalette::HighlightedText ) );
122 //Draw children indicator
123 if( !index.data( VLCModel::IsLeafNodeRole ).toBool() )
125 QRect r( option.rect );
126 r.setSize( QSize( 25, 25 ) );
128 if( index.data( VLCModel::IsCurrentsParentNodeRole ).toBool() )
130 painter->setOpacity( 0.75 );
131 QPainterPath nodeRectPath;
132 nodeRectPath.addRoundedRect( r, 4, 4 );
133 painter->fillPath( nodeRectPath, option.palette.color( QPalette::Highlight ) );
134 painter->setOpacity( 1.0 );
136 QPixmap dirPix( ":/type/node" );
137 QRect r2( dirPix.rect() );
138 r2.moveCenter( r.center() );
139 painter->drawPixmap( r2, dirPix );
143 font.setItalic( true );
146 textRect.setRect( option.rect.x() , artRect.bottom() + fm.height()/2, option.rect.width(), fm.height() );
148 painter->drawText( textRect,
149 fm.elidedText( title, Qt::ElideRight, textRect.width() ),
150 QTextOption( Qt::AlignCenter ) );
153 painter->setPen( painter->pen().color().lighter( 150 ) );
154 font.setItalic( false );
155 painter->setFont( font );
156 fm = painter->fontMetrics();
158 textRect.moveTop( textRect.bottom() + 1 );
160 painter->drawText( textRect,
161 fm.elidedText( artist, Qt::ElideRight, textRect.width() ),
162 QTextOption( Qt::AlignCenter ) );
167 QSize PlIconViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QModelIndex & index ) const
169 QFont f( index.data( Qt::FontRole ).value<QFont>() );
170 f.setPointSize( __MAX( f.pointSize() + i_zoom, 4 ) );
172 QFontMetrics fm( f );
173 int textHeight = fm.height();
174 int averagewidth = fm.averageCharWidth();
175 QSize sz ( averagewidth * ICON_SCALER + 4 * SPACER,
176 averagewidth * ICON_SCALER + 4 * SPACER + 2 * textHeight + 1 );
181 #define LISTVIEW_ART_SIZE 45
183 void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
185 QString title = VLCModel::getMeta( index, COLUMN_TITLE );
186 QString duration = VLCModel::getMeta( index, COLUMN_DURATION );
187 if( !duration.isEmpty() ) title += QString(" [%1]").arg( duration );
189 QString artist = VLCModel::getMeta( index, COLUMN_ARTIST );
190 QString album = VLCModel::getMeta( index, COLUMN_ALBUM );
191 QString trackNum = VLCModel::getMeta( index, COLUMN_TRACK_NUMBER );
192 QString artistAlbum = artist;
193 if( !album.isEmpty() )
195 if( !artist.isEmpty() ) artistAlbum += ": ";
196 artistAlbum += album;
197 if( !trackNum.isEmpty() ) artistAlbum += QString( " [#%1]" ).arg( trackNum );
200 QPixmap artPix = VLCModel::getArtPixmap( index, QSize( LISTVIEW_ART_SIZE, LISTVIEW_ART_SIZE ) );
202 //Draw selection rectangle and current playing item indication
203 paintBackground( painter, option, index );
205 QRect artRect( artPix.rect() );
206 artRect.moveCenter( QPoint( artRect.center().x() + 3,
207 option.rect.center().y() ) );
209 painter->drawPixmap( artRect, artPix );
214 if( option.state & QStyle::State_Selected )
215 painter->setPen( option.palette.color( QPalette::HighlightedText ) );
217 QTextOption textOpt( Qt::AlignVCenter | Qt::AlignLeft );
218 textOpt.setWrapMode( QTextOption::NoWrap );
220 QFont f( index.data( Qt::FontRole ).value<QFont>() );
224 f.setPointSize( __MAX( f.pointSize() + i_zoom, 4 ) );
225 f.setBold( index.data( VLCModel::IsCurrentRole ).toBool() );
226 painter->setFont( f );
227 QFontMetrics fm( painter->fontMetrics() );
229 QRect textRect = option.rect.adjusted( LISTVIEW_ART_SIZE + 10, 0, -10, 0 );
230 if( !artistAlbum.isEmpty() )
232 textRect.setHeight( fm.height() );
233 textRect.moveBottom( option.rect.center().y() - 2 );
236 //Draw children indicator
237 if( !index.data( VLCModel::IsLeafNodeRole ).toBool() )
239 QPixmap dirPix = QPixmap( ":/type/node" );
240 painter->drawPixmap( QPoint( textRect.x(), textRect.center().y() - dirPix.height() / 2 ),
242 textRect.setLeft( textRect.x() + dirPix.width() + 5 );
245 painter->drawText( textRect,
246 fm.elidedText( title, Qt::ElideRight, textRect.width() ),
249 // Draw artist and album info
250 if( !artistAlbum.isEmpty() )
252 f.setItalic( false );
253 painter->setFont( f );
254 fm = painter->fontMetrics();
256 textRect.moveTop( textRect.bottom() + 4 );
257 textRect.setLeft( textRect.x() + 20 );
259 painter->drawText( textRect,
260 fm.elidedText( artistAlbum, Qt::ElideRight, textRect.width() ),
267 QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QModelIndex & ) const
271 QFontMetrics fm( f );
272 int height = qMax( LISTVIEW_ART_SIZE, 2 * fm.height() + 4 ) + 6;
273 return QSize( 0, height );
277 void PlTreeViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
279 if ( index.data( VLCModel::IsCurrentRole ).toBool() )
281 QStyleOptionViewItem myoptions = option;
282 myoptions.font.setBold( true );
283 AbstractPlViewItemDelegate::paint( painter, myoptions, index );
287 AbstractPlViewItemDelegate::paint( painter, option, index );
291 void CellPixmapDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
293 QPixmap pixmap = index.data( Qt::DecorationRole ).value<QPixmap>();
294 painter->drawPixmap( option.rect.topLeft(),
295 pixmap.scaled( option.rect.size(), Qt::KeepAspectRatio ) );
298 static inline void plViewStartDrag( QAbstractItemView *view, const Qt::DropActions & supportedActions )
300 QDrag *drag = new QDrag( view );
301 drag->setPixmap( QPixmap( ":/noart64" ) );
302 drag->setMimeData( view->model()->mimeData(
303 view->selectionModel()->selectedIndexes() ) );
304 drag->exec( supportedActions );
307 static void plViewDragMoveEvent( QAbstractItemView *, QDragMoveEvent * event )
309 if( event->keyboardModifiers() & Qt::ControlModifier &&
310 event->possibleActions() & Qt::CopyAction )
311 event->setDropAction( Qt::CopyAction );
312 else event->acceptProposedAction();
315 PlIconView::PlIconView( QAbstractItemModel *, QWidget *parent ) : QListView( parent )
317 PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this );
319 setViewMode( QListView::IconMode );
320 setMovement( QListView::Static );
321 setResizeMode( QListView::Adjust );
323 setUniformItemSizes( true );
324 setSelectionMode( QAbstractItemView::ExtendedSelection );
325 setSelectionBehavior( QAbstractItemView::SelectRows );
326 setDragEnabled(true);
327 setAttribute( Qt::WA_MacShowFocusRect, false );
328 viewport()->setAttribute( Qt::WA_Hover );
329 /* dropping in QListView::IconMode does not seem to work */
330 //setAcceptDrops( true );
331 //setDropIndicatorShown(true);
333 setItemDelegate( delegate );
336 void PlIconView::startDrag ( Qt::DropActions supportedActions )
338 plViewStartDrag( this, supportedActions );
341 void PlIconView::dragMoveEvent ( QDragMoveEvent * event )
343 plViewDragMoveEvent( this, event );
344 QAbstractItemView::dragMoveEvent( event );
347 bool PlIconView::viewportEvent ( QEvent * event )
349 if ( event->type() == QEvent::ToolTip )
354 else if ( event->type() == QEvent::Wheel )
356 QWheelEvent *wEvent = static_cast<QWheelEvent *>(event);
357 if( wEvent->modifiers() & Qt::ControlModifier ) {
362 return QAbstractItemView::viewportEvent( event );
365 PlListView::PlListView( QAbstractItemModel *, QWidget *parent ) : QListView( parent )
367 setViewMode( QListView::ListMode );
368 setUniformItemSizes( true );
369 setSelectionMode( QAbstractItemView::ExtendedSelection );
370 setSelectionBehavior( QAbstractItemView::SelectRows );
371 setAlternatingRowColors( true );
372 setDragEnabled(true);
373 setAcceptDrops( true );
374 setDropIndicatorShown(true);
376 PlListViewItemDelegate *delegate = new PlListViewItemDelegate( this );
377 setItemDelegate( delegate );
378 setAttribute( Qt::WA_MacShowFocusRect, false );
379 viewport()->setAttribute( Qt::WA_Hover );
382 void PlListView::startDrag ( Qt::DropActions supportedActions )
384 plViewStartDrag( this, supportedActions );
387 void PlListView::dragMoveEvent ( QDragMoveEvent * event )
389 plViewDragMoveEvent( this, event );
390 QAbstractItemView::dragMoveEvent( event );
393 void PlListView::keyPressEvent( QKeyEvent *event )
395 //If the space key is pressed, override the standard list behaviour to allow pausing
397 if ( event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Space )
398 QWidget::keyPressEvent( event );
399 //Otherwise, just do as usual.
401 QListView::keyPressEvent( event );
404 bool PlListView::viewportEvent ( QEvent * event )
406 if ( event->type() == QEvent::ToolTip )
411 else if ( event->type() == QEvent::Wheel )
413 QWheelEvent *wEvent = static_cast<QWheelEvent *>(event);
414 if( wEvent->modifiers() & Qt::ControlModifier ) {
419 return QAbstractItemView::viewportEvent( event );
422 PlTreeView::PlTreeView( QAbstractItemModel *, QWidget *parent ) : QTreeView( parent )
424 setItemDelegate( new PlTreeViewItemDelegate( this ) );
425 setItemDelegateForColumn( VLCModel::metaToColumn(COLUMN_COVER),
426 new CellPixmapDelegate( this ) );
427 setIconSize( QSize( 20, 20 ) );
428 setAlternatingRowColors( true );
430 setUniformRowHeights( true );
431 setSortingEnabled( true );
432 setAttribute( Qt::WA_MacShowFocusRect, false );
433 viewport()->setAttribute( Qt::WA_Hover );
434 header()->setSortIndicator( -1 , Qt::AscendingOrder );
435 header()->setSortIndicatorShown( true );
437 header()->setSectionsClickable( true );
439 header()->setClickable( true );
441 header()->setContextMenuPolicy( Qt::CustomContextMenu );
443 setSelectionBehavior( QAbstractItemView::SelectRows );
444 setSelectionMode( QAbstractItemView::ExtendedSelection );
445 setDragEnabled( true );
446 setAcceptDrops( true );
447 setDropIndicatorShown( true );
448 setContextMenuPolicy( Qt::CustomContextMenu );
451 void PlTreeView::setModel( QAbstractItemModel * model )
453 QTreeView::setModel( model );
454 VLCModel *m = static_cast<VLCModel*>(model);
455 CONNECT( this, expanded( const QModelIndex & ),
456 m, ensureArtRequested( const QModelIndex & ) );
459 void PlTreeView::startDrag ( Qt::DropActions supportedActions )
461 plViewStartDrag( this, supportedActions );
464 void PlTreeView::dragMoveEvent ( QDragMoveEvent * event )
466 plViewDragMoveEvent( this, event );
467 QAbstractItemView::dragMoveEvent( event );
470 void PlTreeView::keyPressEvent( QKeyEvent *event )
472 //If the space key is pressed, override the standard list behaviour to allow pausing
474 if ( event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Space )
475 QWidget::keyPressEvent( event );
476 //Otherwise, just do as usual.
478 QTreeView::keyPressEvent( event );
481 #include <QHBoxLayout>
482 PicFlowView::PicFlowView( QAbstractItemModel *p_model, QWidget *parent ) : QAbstractItemView( parent )
484 QHBoxLayout *layout = new QHBoxLayout( this );
485 layout->setMargin( 0 );
486 picFlow = new PictureFlow( this, p_model );
487 picFlow->setContextMenuPolicy( Qt::CustomContextMenu );
488 connect( picFlow, SIGNAL(customContextMenuRequested( const QPoint & )),
489 this, SIGNAL(customContextMenuRequested( const QPoint & )) );
490 layout->addWidget( picFlow );
491 picFlow->setSlideSize(QSize( 4*LISTVIEW_ART_SIZE, 3*LISTVIEW_ART_SIZE) );
492 setSelectionMode( QAbstractItemView::SingleSelection );
495 void PicFlowView::setModel( QAbstractItemModel *model )
497 QAbstractItemView::setModel( model );
498 picFlow->setModel( model );
501 int PicFlowView::horizontalOffset() const
506 int PicFlowView::verticalOffset() const
511 QRect PicFlowView::visualRect(const QModelIndex & ) const
513 return QRect( QPoint(0,0), picFlow->slideSize() );
516 void PicFlowView::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint)
518 int currentIndex = picFlow->centerIndex();
519 if( qAbs( currentIndex - index.row()) > 20 )
521 /* offset is offset from target index toward currentIndex */
523 if( index.row() > currentIndex )
525 picFlow->setCenterIndex( index.row() + offset );
526 picFlow->showSlide( index.row() );
529 picFlow->showSlide( index.row() );
532 QModelIndex PicFlowView::indexAt(const QPoint &) const
534 return QModelIndex();
535 // No idea, PictureFlow doesn't provide anything to help this
538 QModelIndex PicFlowView::moveCursor(QAbstractItemView::CursorAction, Qt::KeyboardModifiers)
540 return QModelIndex();
543 bool PicFlowView::isIndexHidden(const QModelIndex &index) const
545 int currentIndex = picFlow->centerIndex();
546 if( index.row()-5 <= currentIndex &&
547 index.row()+5 >= currentIndex )
553 QRegion PicFlowView::visualRegionForSelection(const QItemSelection &) const
558 void PicFlowView::setSelection(const QRect &, QFlags<QItemSelectionModel::SelectionFlag>)
560 // No selection possible
563 void PicFlowView::dataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight )
565 int currentIndex = picFlow->centerIndex();
566 for(int i = topLeft.row(); i<=bottomRight.row(); i++ )
568 if( i-5 <= currentIndex &&
569 i+5 >= currentIndex )
577 void PicFlowView::playItem( int i_item )
579 emit activated( model()->index(i_item, 0) );
582 bool PicFlowView::viewportEvent ( QEvent * event )
584 if ( event->type() == QEvent::ToolTip )
589 else if ( event->type() == QEvent::Wheel )
591 QWheelEvent *wEvent = static_cast<QWheelEvent *>(event);
592 if( wEvent->modifiers() & Qt::ControlModifier ) {
597 return QAbstractItemView::viewportEvent( event );