X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fqt4%2Fcomponents%2Fplaylist%2Fstandardpanel.cpp;h=95fa90e58714fd811324c9f3cf68ac794e822780;hb=139cf222f01e9d0f88d02d706618428b71147ba8;hp=bc31e5ae9b6fb1ec1dae925b7111aaaf4537703e;hpb=778a6f0719a6bf547917ff9f2ef7fd84769fd901;p=vlc diff --git a/modules/gui/qt4/components/playlist/standardpanel.cpp b/modules/gui/qt4/components/playlist/standardpanel.cpp index bc31e5ae9b..95fa90e587 100644 --- a/modules/gui/qt4/components/playlist/standardpanel.cpp +++ b/modules/gui/qt4/components/playlist/standardpanel.cpp @@ -1,11 +1,11 @@ /***************************************************************************** * standardpanel.cpp : The "standard" playlist panel : just a treeview **************************************************************************** - * Copyright (C) 2000-2009 VideoLAN + * Copyright © 2000-2010 VideoLAN * $Id$ * * Authors: Clément Stenac - * JB Kempf + * Jean-Baptiste Kempf * * 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 @@ -26,109 +26,67 @@ # include "config.h" #endif -#include "dialogs_provider.hpp" - -#include "components/playlist/playlist_model.hpp" #include "components/playlist/standardpanel.hpp" -#include "components/playlist/icon_view.hpp" -#include "util/customwidgets.hpp" -#include "menus.hpp" -#include +#include "components/playlist/vlc_model.hpp" /* VLCModel */ +#include "components/playlist/playlist_model.hpp" /* PLModel */ +#include "components/playlist/ml_model.hpp" /* MLModel */ +#include "components/playlist/views.hpp" /* 3 views */ +#include "components/playlist/selector.hpp" /* PLSelector */ +#include "menus.hpp" /* Popup */ +#include "input_manager.hpp" /* THEMIM */ + +#include "sorting.h" /* Columns order */ + +#include /* SD_CMD_SEARCH */ -#include #include -#include #include -#include #include -#include +#include #include -#include -#include -#include +#include +#include +#include #include -#include "sorting.h" - -static const QString viewNames[] = { qtr( "Detailed View" ), - qtr( "Icon View" ), - qtr( "List View" ) }; - StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent, intf_thread_t *_p_intf, - playlist_t *p_playlist, - playlist_item_t *p_root ): - QWidget( _parent ), p_intf( _p_intf ) -{ - layout = new QGridLayout( this ); - layout->setSpacing( 0 ); layout->setMargin( 0 ); + playlist_item_t *p_root, + PLSelector *_p_selector, + PLModel *_p_model, + MLModel *_p_plmodel) + : QWidget( _parent ), + model( _p_model ), + mlmodel( _p_plmodel), + p_intf( _p_intf ), + p_selector( _p_selector ) +{ + viewStack = new QStackedLayout( this ); + viewStack->setSpacing( 0 ); viewStack->setMargin( 0 ); setMinimumWidth( 300 ); - iconView = NULL; - treeView = NULL; - listView = NULL; - - model = new PLModel( p_playlist, p_intf, p_root, this ); - currentRootId = -1; - currentRootIndexId = -1; - lastActivatedId = -1; - - locationBar = new LocationBar( model ); - locationBar->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred ); - layout->addWidget( locationBar, 0, 0 ); - layout->setColumnStretch( 0, 5 ); - CONNECT( locationBar, invoked( const QModelIndex & ), - this, browseInto( const QModelIndex & ) ); - - searchEdit = new SearchLineEdit( this ); - searchEdit->setMaximumWidth( 250 ); - searchEdit->setMinimumWidth( 80 ); - layout->addWidget( searchEdit, 0, 2 ); - CONNECT( searchEdit, textChanged( const QString& ), - this, search( const QString& ) ); - layout->setColumnStretch( 2, 3 ); - - /* Button to switch views */ - QToolButton *viewButton = new QToolButton( this ); - viewButton->setIcon( style()->standardIcon( QStyle::SP_FileDialogDetailedView ) ); - layout->addWidget( viewButton, 0, 1 ); - - /* View selection menu */ - viewSelectionMapper = new QSignalMapper( this ); - CONNECT( viewSelectionMapper, mapped( int ), this, showView( int ) ); - - QActionGroup *actionGroup = new QActionGroup( this ); - - for( int i = 0; i < VIEW_COUNT; i++ ) - { - viewActions[i] = actionGroup->addAction( viewNames[i] ); - viewActions[i]->setCheckable( true ); - viewSelectionMapper->setMapping( viewActions[i], i ); - CONNECT( viewActions[i], triggered(), viewSelectionMapper, map() ); - } - - BUTTONACT( viewButton, cycleViews() ); - QMenu *viewMenu = new QMenu( this ); - viewMenu->addActions( actionGroup->actions() ); + iconView = NULL; + treeView = NULL; + listView = NULL; + picFlowView = NULL; - viewButton->setMenu( viewMenu ); + currentRootIndexId = -1; + lastActivatedId = -1; /* Saved Settings */ - getSettings()->beginGroup("Playlist"); + int i_savedViewMode = getSettings()->value( "Playlist/view-mode", TREE_VIEW ).toInt(); + showView( i_savedViewMode ); - int i_viewMode = getSettings()->value( "view-mode", TREE_VIEW ).toInt(); - showView( i_viewMode ); + DCONNECT( THEMIM, leafBecameParent( int ), + this, browseInto( int ) ); - getSettings()->endGroup(); - - DCONNECT( THEMIM, leafBecameParent( input_item_t *), - this, browseInto( input_item_t * ) ); - - CONNECT( model, currentChanged( const QModelIndex& ), + CONNECT( model, currentIndexChanged( const QModelIndex& ), this, handleExpansion( const QModelIndex& ) ); - CONNECT( model, rootChanged(), this, handleRootChange() ); + CONNECT( model, rootChanged(), this, browseInto() ); + + setRoot( p_root, false ); } StandardPLPanel::~StandardPLPanel() @@ -136,12 +94,7 @@ StandardPLPanel::~StandardPLPanel() getSettings()->beginGroup("Playlist"); if( treeView ) getSettings()->setValue( "headerStateV2", treeView->header()->saveState() ); - if( currentView == treeView ) - getSettings()->setValue( "view-mode", TREE_VIEW ); - else if( currentView == listView ) - getSettings()->setValue( "view-mode", LIST_VIEW ); - else if( currentView == iconView ) - getSettings()->setValue( "view-mode", ICON_VIEW ); + getSettings()->setValue( "view-mode", currentViewIndex() ); getSettings()->endGroup(); } @@ -154,14 +107,11 @@ void StandardPLPanel::gotoPlayingItem() void StandardPLPanel::handleExpansion( const QModelIndex& index ) { assert( currentView ); + if( currentRootIndexId != -1 && currentRootIndexId != model->itemId( index.parent() ) ) + browseInto( index.parent() ); currentView->scrollTo( index ); } -void StandardPLPanel::handleRootChange() -{ - browseInto(); -} - void StandardPLPanel::popupPlView( const QPoint &point ) { QModelIndex index = currentView->indexAt( point ); @@ -173,18 +123,16 @@ void StandardPLPanel::popupPlView( const QPoint &point ) QVLCMenu::PopupMenu( p_intf, true ); } -void StandardPLPanel::popupSelectColumn( QPoint pos ) +void StandardPLPanel::popupSelectColumn( QPoint ) { QMenu menu; assert( treeView ); /* We do not offer the option to hide index 0 column, or - * QTreeView will behave weird */ - int i, j; - for( i = 1 << 1, j = 1; i < COLUMN_END; i <<= 1, j++ ) + * QTreeView will behave weird */ + for( int i = 1 << 1, j = 1; i < COLUMN_END; i <<= 1, j++ ) { - QAction* option = menu.addAction( - qfu( psz_column_title( i ) ) ); + QAction* option = menu.addAction( qfu( psz_column_title( i ) ) ); option->setCheckable( true ); option->setChecked( !treeView->isColumnHidden( j ) ); selectColumnsSigMapper->setMapping( option, j ); @@ -201,36 +149,72 @@ void StandardPLPanel::toggleColumnShown( int i ) /* Search in the playlist */ void StandardPLPanel::search( const QString& searchText ) { - bool flat = currentView == iconView || currentView == listView; - model->search( searchText, - flat ? currentView->rootIndex() : QModelIndex(), - !flat ); + int type; + QString name; + p_selector->getCurrentSelectedItem( &type, &name ); + if( type != SD_TYPE ) + { + bool flat = ( currentView == iconView || + currentView == listView || + currentView == picFlowView ); + model->search( searchText, + flat ? currentView->rootIndex() : QModelIndex(), + !flat ); + } +} + +void StandardPLPanel::searchDelayed( const QString& searchText ) +{ + int type; + QString name; + p_selector->getCurrentSelectedItem( &type, &name ); + + if( type == SD_TYPE ) + { + if( !name.isEmpty() && !searchText.isEmpty() ) + playlist_ServicesDiscoveryControl( THEPL, qtu( name ), SD_CMD_SEARCH, + qtu( searchText ) ); + } } /* Set the root of the new Playlist */ /* This activated by the selector selection */ -void StandardPLPanel::setRoot( playlist_item_t *p_item ) +void StandardPLPanel::setRoot( playlist_item_t *p_item, bool b ) { - model->rebuild( p_item ); +#ifdef MEDIA_LIBRARY + if( b ) + { + msg_Dbg( p_intf, "Setting the SQL ML" ); + currentView->setModel( mlmodel ); + } + else +#else + Q_UNUSED( b ); +#endif + { + msg_Dbg( p_intf, "Normal PL/ML or SD" ); + if( currentView->model() != model ) + currentView->setModel( model ); + model->rebuild( p_item ); + } } void StandardPLPanel::browseInto( const QModelIndex &index ) { - if( currentView == iconView || currentView == listView ) + if( currentView == iconView || currentView == listView || currentView == picFlowView ) { - currentRootIndexId = model->itemId( index );; + currentRootIndexId = model->itemId( index ); currentView->setRootIndex( index ); } - locationBar->setIndex( index ); - searchEdit->clear(); + emit viewChanged( index ); } -void StandardPLPanel::browseInto( ) +void StandardPLPanel::browseInto() { - browseInto( currentRootIndexId != -1 && currentView != treeView ? - model->index( currentRootIndexId, 0 ) : - QModelIndex() ); + browseInto( (currentRootIndexId != -1 && currentView != treeView) ? + model->index( currentRootIndexId, 0 ) : + QModelIndex() ); } void StandardPLPanel::wheelEvent( QWheelEvent *e ) @@ -239,7 +223,7 @@ void StandardPLPanel::wheelEvent( QWheelEvent *e ) e->accept(); } -bool StandardPLPanel::eventFilter ( QObject * watched, QEvent * event ) +bool StandardPLPanel::eventFilter ( QObject *, QEvent * event ) { if (event->type() == QEvent::KeyPress) { @@ -270,7 +254,7 @@ void StandardPLPanel::createIconView() CONNECT( iconView, activated( const QModelIndex & ), this, activate( const QModelIndex & ) ); iconView->installEventFilter( this ); - layout->addWidget( iconView, 1, 0, 1, -1 ); + viewStack->addWidget( iconView ); } void StandardPLPanel::createListView() @@ -282,20 +266,32 @@ void StandardPLPanel::createListView() CONNECT( listView, activated( const QModelIndex & ), this, activate( const QModelIndex & ) ); listView->installEventFilter( this ); - layout->addWidget( listView, 1, 0, 1, -1 ); + viewStack->addWidget( listView ); } +void StandardPLPanel::createCoverView() +{ + picFlowView = new PicFlowView( model, this ); + picFlowView->setContextMenuPolicy( Qt::CustomContextMenu ); + CONNECT( picFlowView, customContextMenuRequested( const QPoint & ), + this, popupPlView( const QPoint & ) ); + CONNECT( picFlowView, activated( const QModelIndex & ), + this, activate( const QModelIndex & ) ); + viewStack->addWidget( picFlowView ); + picFlowView->installEventFilter( this ); +} void StandardPLPanel::createTreeView() { /* Create and configure the QTreeView */ - treeView = new QTreeView; + treeView = new PlTreeView; treeView->setIconSize( QSize( 20, 20 ) ); treeView->setAlternatingRowColors( true ); treeView->setAnimated( true ); treeView->setUniformRowHeights( true ); treeView->setSortingEnabled( true ); + treeView->setAttribute( Qt::WA_MacShowFocusRect, false ); treeView->header()->setSortIndicator( -1 , Qt::AscendingOrder ); treeView->header()->setSortIndicatorShown( true ); treeView->header()->setClickable( true ); @@ -309,9 +305,9 @@ void StandardPLPanel::createTreeView() treeView->setContextMenuPolicy( Qt::CustomContextMenu ); /* setModel after setSortingEnabled(true), or the model will sort immediately! */ - treeView->setModel( model ); getSettings()->beginGroup("Playlist"); + if( getSettings()->contains( "headerStateV2" ) ) { treeView->header()->restoreState( @@ -326,6 +322,7 @@ void StandardPLPanel::createTreeView() else if( m == COLUMN_DURATION ) treeView->header()->resizeSection( c, 80 ); } } + getSettings()->endGroup(); /* Connections for the TreeView */ @@ -342,56 +339,81 @@ void StandardPLPanel::createTreeView() CONNECT( selectColumnsSigMapper, mapped( int ), this, toggleColumnShown( int ) ); - /* Finish the layout */ - layout->addWidget( treeView, 1, 0, 1, -1 ); + viewStack->addWidget( treeView ); +} + +void StandardPLPanel::changeModel( bool b_ml ) +{ +#ifdef MEDIA_LIBRARY + VLCModel *mod; + if( b_ml ) + mod = mlmodel; + else + mod = model; + if( currentView->model() != mod ) + currentView->setModel( mod ); +#else + Q_UNUSED( b_ml ); + if( currentView->model() != model ) + currentView->setModel( model ); +#endif } void StandardPLPanel::showView( int i_view ) { + switch( i_view ) { - case TREE_VIEW: - { - if( treeView == NULL ) - createTreeView(); - if( iconView ) iconView->hide(); - if( listView ) listView->hide(); - treeView->show(); - currentView = treeView; - viewActions[i_view]->setChecked( true ); - break; - } case ICON_VIEW: { if( iconView == NULL ) createIconView(); - - if( treeView ) treeView->hide(); - if( listView ) listView->hide(); - iconView->show(); currentView = iconView; - viewActions[i_view]->setChecked( true ); break; } case LIST_VIEW: { if( listView == NULL ) createListView(); - - if( treeView ) treeView->hide(); - if( iconView ) iconView->hide(); - listView->show(); currentView = listView; - viewActions[i_view]->setChecked( true ); break; } - default: return; + case PICTUREFLOW_VIEW: + { + if( picFlowView == NULL ) + createCoverView(); + currentView = picFlowView; + break; } + default: + case TREE_VIEW: + { + if( treeView == NULL ) + createTreeView(); + currentView = treeView; + break; + } + } + + changeModel( false ); + viewStack->setCurrentWidget( currentView ); browseInto(); gotoPlayingItem(); } +int StandardPLPanel::currentViewIndex() const +{ + if( currentView == treeView ) + return TREE_VIEW; + else if( currentView == iconView ) + return ICON_VIEW; + else if( currentView == listView ) + return LIST_VIEW; + else + return PICTUREFLOW_VIEW; +} + void StandardPLPanel::cycleViews() { if( currentView == iconView ) @@ -399,6 +421,10 @@ void StandardPLPanel::cycleViews() else if( currentView == treeView ) showView( LIST_VIEW ); else if( currentView == listView ) +#ifndef NDEBUG + showView( PICTUREFLOW_VIEW ); + else if( currentView == picFlowView ) +#endif showView( ICON_VIEW ); else assert( 0 ); @@ -406,38 +432,31 @@ void StandardPLPanel::cycleViews() void StandardPLPanel::activate( const QModelIndex &index ) { - if( !index.data( PLModel::IsLeafNodeRole ).toBool() ) + if( currentView->model() == model ) { - if( currentView != treeView ) - browseInto( index ); - } - else - { - playlist_Lock( THEPL ); - playlist_item_t *p_item = playlist_ItemGetById( THEPL, model->itemId( index ) ); - p_item->i_flags |= PLAYLIST_SUBITEM_STOP_FLAG; - lastActivatedId = p_item->p_input->i_id; - playlist_Unlock( THEPL ); - model->activateItem( index ); + /* If we are not a leaf node */ + if( !index.data( PLModel::IsLeafNodeRole ).toBool() ) + { + if( currentView != treeView ) + browseInto( index ); + } + else + { + playlist_Lock( THEPL ); + playlist_item_t *p_item = playlist_ItemGetById( THEPL, model->itemId( index ) ); + p_item->i_flags |= PLAYLIST_SUBITEM_STOP_FLAG; + lastActivatedId = p_item->p_input->i_id; + playlist_Unlock( THEPL ); + model->activateItem( index ); + } } } -void StandardPLPanel::browseInto( input_item_t *p_input ) +void StandardPLPanel::browseInto( int i_id ) { + if( i_id != lastActivatedId ) return; - if( p_input->i_id != lastActivatedId ) return; - - playlist_Lock( THEPL ); - - playlist_item_t *p_item = playlist_ItemGetByInput( THEPL, p_input ); - if( !p_item ) - { - playlist_Unlock( THEPL ); - return; - } - - QModelIndex index = model->index( p_item->i_id, 0 ); - + QModelIndex index = model->index( i_id, 0 ); playlist_Unlock( THEPL ); if( currentView == treeView ) @@ -446,191 +465,4 @@ void StandardPLPanel::browseInto( input_item_t *p_input ) browseInto( index ); lastActivatedId = -1; - - -} - -LocationBar::LocationBar( PLModel *m ) -{ - model = m; - mapper = new QSignalMapper( this ); - CONNECT( mapper, mapped( int ), this, invoke( int ) ); - - btnMore = new LocationButton( "...", false, true, this ); - menuMore = new QMenu( this ); - btnMore->setMenu( menuMore ); -} - -void LocationBar::setIndex( const QModelIndex &index ) -{ - qDeleteAll( buttons ); - buttons.clear(); - qDeleteAll( actions ); - actions.clear(); - - QModelIndex i = index; - bool first = true; - - while( true ) - { - PLItem *item = model->getItem( i ); - - char *fb_name = input_item_GetTitleFbName( item->inputItem() ); - QString text = qfu(fb_name); - free(fb_name); - - QAbstractButton *btn = new LocationButton( text, first, !first, this ); - btn->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed ); - buttons.append( btn ); - - QAction *action = new QAction( text, this ); - actions.append( action ); - CONNECT( btn, clicked(), action, trigger() ); - - mapper->setMapping( action, item->id() ); - CONNECT( action, triggered(), mapper, map() ); - - first = false; - - if( i.isValid() ) i = i.parent(); - else break; - } - - QString prefix; - for( int a = actions.count() - 1; a >= 0 ; a-- ) - { - actions[a]->setText( prefix + actions[a]->text() ); - prefix += QString(" "); - } - - if( isVisible() ) layOut( size() ); -} - -void LocationBar::setRootIndex() -{ - setIndex( QModelIndex() ); -} - -void LocationBar::invoke( int i_id ) -{ - QModelIndex index = model->index( i_id, 0 ); - emit invoked ( index ); -} - -void LocationBar::layOut( const QSize& size ) -{ - menuMore->clear(); - widths.clear(); - - int count = buttons.count(); - int totalWidth = 0; - for( int i = 0; i < count; i++ ) - { - int w = buttons[i]->sizeHint().width(); - widths.append( w ); - totalWidth += w; - if( totalWidth > size.width() ) break; - } - - int x = 0; - int shown = widths.count(); - - if( totalWidth > size.width() && count > 1 ) - { - QSize sz = btnMore->sizeHint(); - btnMore->setGeometry( 0, 0, sz.width(), size.height() ); - btnMore->show(); - x = sz.width(); - totalWidth += x; - } - else - { - btnMore->hide(); - } - for( int i = count - 1; i >= 0; i-- ) - { - if( totalWidth <= size.width() || i == 0) - { - buttons[i]->setGeometry( x, 0, qMin( size.width() - x, widths[i] ), size.height() ); - buttons[i]->show(); - x += widths[i]; - totalWidth -= widths[i]; - } - else - { - menuMore->addAction( actions[i] ); - buttons[i]->hide(); - if( i < shown ) totalWidth -= widths[i]; - } - } } - -void LocationBar::resizeEvent ( QResizeEvent * event ) -{ - layOut( event->size() ); -} - -QSize LocationBar::sizeHint() const -{ - return btnMore->sizeHint(); -} - -LocationButton::LocationButton( const QString &text, bool bold, - bool arrow, QWidget * parent ) - : b_arrow( arrow ), QPushButton( parent ) -{ - QFont font; - font.setBold( bold ); - setFont( font ); - setText( text ); -} - -#define PADDING 4 - -void LocationButton::paintEvent ( QPaintEvent * event ) -{ - QStyleOptionButton option; - option.initFrom( this ); - option.state |= QStyle::State_Enabled; - QPainter p( this ); - - if( underMouse() ) - { - p.save(); - p.setRenderHint( QPainter::Antialiasing, true ); - QColor c = palette().color( QPalette::Highlight ); - p.setPen( c ); - p.setBrush( c.lighter( 150 ) ); - p.setOpacity( 0.2 ); - p.drawRoundedRect( option.rect.adjusted( 0, 2, 0, -2 ), 5, 5 ); - p.restore(); - } - - QRect r = option.rect.adjusted( PADDING, 0, -PADDING - (b_arrow ? 10 : 0), 0 ); - - QString str( text() ); - /* This check is absurd, but either it is not done properly inside elidedText(), - or boundingRect() is wrong */ - if( r.width() < fontMetrics().boundingRect( text() ).width() ) - str = fontMetrics().elidedText( text(), Qt::ElideRight, r.width() ); - p.drawText( r, Qt::AlignVCenter | Qt::AlignLeft, str ); - - if( b_arrow ) - { - option.rect.setWidth( 10 ); - option.rect.moveRight( rect().right() ); - style()->drawPrimitive( QStyle::PE_IndicatorArrowRight, &option, &p ); - } -} - -QSize LocationButton::sizeHint() const -{ - QSize s( fontMetrics().boundingRect( text() ).size() ); - /* Add two pixels to width: font metrics are buggy, if you pass text through elidation - with exactly the width of its bounding rect, sometimes it still elides */ - s.setWidth( s.width() + ( 2 * PADDING ) + ( b_arrow ? 10 : 0 ) + 2 ); - s.setHeight( s.height() + 2 * PADDING ); - return s; -} - -#undef PADDING