X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fqt4%2Fcomponents%2Fplaylist%2Fstandardpanel.cpp;h=9ae14e96afc8cb63ba8d05df4d783362edd75308;hb=639eca0ef43b79aba3deeaf2c414c3556c33c7aa;hp=d7eab18b269c33fe895e19f8b53aa9a8cea8f997;hpb=9c191f2fbb13aa7162d61c52a15dd290702fb803;p=vlc diff --git a/modules/gui/qt4/components/playlist/standardpanel.cpp b/modules/gui/qt4/components/playlist/standardpanel.cpp index d7eab18b26..9ae14e96af 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,188 +26,113 @@ # include "config.h" #endif -#include "qt4.hpp" -#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 +#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 "sorting.h" - StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent, intf_thread_t *_p_intf, - playlist_t *p_playlist, - playlist_item_t *p_root ): - QWidget( _parent ), p_intf( _p_intf ) + 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 ) { - layout = new QGridLayout( this ); - layout->setSpacing( 0 ); layout->setMargin( 0 ); + viewStack = new QStackedLayout( this ); + viewStack->setSpacing( 0 ); viewStack->setMargin( 0 ); setMinimumWidth( 300 ); - model = new PLModel( p_playlist, p_intf, p_root, this ); - - /* Create and configure the QTreeView */ - treeView = new QTreeView; - treeView->setModel( model ); - iconView = NULL; - - treeView->setIconSize( QSize( 20, 20 ) ); - treeView->setAlternatingRowColors( true ); - treeView->setAnimated( true ); - treeView->setUniformRowHeights( true ); - treeView->setSortingEnabled( true ); - treeView->header()->setSortIndicator( -1 , Qt::AscendingOrder ); - treeView->header()->setSortIndicatorShown( true ); - treeView->header()->setClickable( true ); - treeView->header()->setContextMenuPolicy( Qt::CustomContextMenu ); - - treeView->setSelectionBehavior( QAbstractItemView::SelectRows ); - treeView->setSelectionMode( QAbstractItemView::ExtendedSelection ); - treeView->setDragEnabled( true ); - treeView->setAcceptDrops( true ); - treeView->setDropIndicatorShown( true ); - treeView->setContextMenuPolicy( Qt::CustomContextMenu ); + iconView = NULL; + treeView = NULL; + listView = NULL; + picFlowView = NULL; - //treeView->installEventFilter( this ); - // I guess we don't need that + currentRootIndexId = -1; + lastActivatedId = -1; /* Saved Settings */ - getSettings()->beginGroup("Playlist"); - if( getSettings()->contains( "headerStateV2" ) ) - { - treeView->header()->restoreState( - getSettings()->value( "headerStateV2" ).toByteArray() ); - } - else - { - for( int m = 1, c = 0; m != COLUMN_END; m <<= 1, c++ ) - { - treeView->setColumnHidden( c, !( m & COLUMN_DEFAULT ) ); - if( m == COLUMN_TITLE ) treeView->header()->resizeSection( c, 200 ); - else if( m == COLUMN_DURATION ) treeView->header()->resizeSection( c, 80 ); - } - } - getSettings()->endGroup(); + int i_savedViewMode = getSettings()->value( "Playlist/view-mode", TREE_VIEW ).toInt(); + showView( i_savedViewMode ); - /* Connections for the TreeView */ - CONNECT( treeView, activated( const QModelIndex& ), - model,activateItem( const QModelIndex& ) ); - CONNECT( treeView->header(), customContextMenuRequested( const QPoint & ), - this, popupSelectColumn( QPoint ) ); - CONNECT( treeView, customContextMenuRequested( const QPoint & ), - this, treeViewPopup( const QPoint & ) ); - CONNECT( model, currentChanged( const QModelIndex& ), - this, handleExpansion( const QModelIndex& ) ); + DCONNECT( THEMIM, leafBecameParent( int ), + this, browseInto( int ) ); - currentRootId = -1; - - /* Title label */ - title = new QLabel; - QFont titleFont; - titleFont.setPointSize( titleFont.pointSize() + 6 ); - titleFont.setFamily( "Verdana" ); - title->setFont( titleFont ); - layout->addWidget( title, 0, 0 ); - - /* A Spacer and the search possibilities */ - layout->setColumnStretch( 1, 10 ); - - SearchLineEdit *search = new SearchLineEdit( this ); - search->setMaximumWidth( 200 ); - layout->addWidget( search, 0, 4 ); - CONNECT( search, textChanged( const QString& ), - this, search( const QString& ) ); - layout->setColumnStretch( 4, 1 ); - - /* Add item to the playlist button */ - addButton = new QPushButton; - addButton->setIcon( QIcon( ":/buttons/playlist/playlist_add" ) ); - addButton->setMaximumWidth( 30 ); - BUTTONACT( addButton, popupAdd() ); - layout->addWidget( addButton, 0, 3 ); - - QPushButton *viewButton = new QPushButton( this ); - viewButton->setIcon( QIcon( ":/buttons/playlist/playlist_add" ) ); - layout->addWidget( viewButton, 0, 2 ); - BUTTONACT( viewButton, toggleView() ); - - /* Finish the layout */ - layout->addWidget( treeView, 1, 0, 1, -1 ); + CONNECT( model, currentIndexChanged( const QModelIndex& ), + this, handleExpansion( const QModelIndex& ) ); + CONNECT( model, rootIndexChanged(), this, browseInto() ); - selectColumnsSigMapper = new QSignalMapper( this ); - CONNECT( selectColumnsSigMapper, mapped( int ), - this, toggleColumnShown( int ) ); + setRootItem( p_root, false ); } StandardPLPanel::~StandardPLPanel() { getSettings()->beginGroup("Playlist"); - getSettings()->setValue( "headerStateV2", treeView->header()->saveState() ); + if( treeView ) + getSettings()->setValue( "headerStateV2", treeView->header()->saveState() ); + getSettings()->setValue( "view-mode", currentViewIndex() ); getSettings()->endGroup(); } /* Unused anymore, but might be useful, like in right-click menu */ void StandardPLPanel::gotoPlayingItem() { - treeView->scrollTo( model->currentIndex() ); + currentView->scrollTo( model->currentIndex() ); } void StandardPLPanel::handleExpansion( const QModelIndex& index ) { - treeView->scrollTo( index ); + assert( currentView ); + if( currentRootIndexId != -1 && currentRootIndexId != model->itemId( index.parent() ) ) + browseInto( index.parent() ); + currentView->scrollTo( index ); } -/* PopupAdd Menu for the Add Menu */ -void StandardPLPanel::popupAdd() +void StandardPLPanel::popupPlView( const QPoint &point ) { - QMenu popup; - if( currentRootId == THEPL->p_local_category->i_id || - currentRootId == THEPL->p_local_onelevel->i_id ) - { - popup.addAction( qtr(I_PL_ADDF), THEDP, SLOT( simplePLAppendDialog()) ); - popup.addAction( qtr(I_PL_ADDDIR), THEDP, SLOT( PLAppendDir()) ); - popup.addAction( qtr(I_OP_ADVOP), THEDP, SLOT( PLAppendDialog()) ); - } - else if( ( THEPL->p_ml_category && - currentRootId == THEPL->p_ml_category->i_id ) || - ( THEPL->p_ml_onelevel && - currentRootId == THEPL->p_ml_onelevel->i_id ) ) - { - popup.addAction( qtr(I_PL_ADDF), THEDP, SLOT( simpleMLAppendDialog()) ); - popup.addAction( qtr(I_PL_ADDDIR), THEDP, SLOT( MLAppendDir() ) ); - popup.addAction( qtr(I_OP_ADVOP), THEDP, SLOT( MLAppendDialog() ) ); - } + QModelIndex index = currentView->indexAt( point ); + QPoint globalPoint = currentView->viewport()->mapToGlobal( point ); + QItemSelectionModel *selection = currentView->selectionModel(); + QModelIndexList list = selection->selectedIndexes(); - popup.exec( QCursor::pos() - addButton->mapFromGlobal( QCursor::pos() ) - + QPoint( 0, addButton->height() ) ); + if( !model->popup( index, globalPoint, list ) ) + 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 ); @@ -216,15 +141,6 @@ void StandardPLPanel::popupSelectColumn( QPoint pos ) menu.exec( QCursor::pos() ); } -void StandardPLPanel::treeViewPopup( const QPoint &point ) -{ - QModelIndex index = treeView->indexAt( point ); - QPoint globalPoint = treeView->viewport()->mapToGlobal( point ); - QItemSelectionModel *selection = treeView->selectionModel(); - QModelIndexList list = selection->selectedIndexes(); - model->popup( index, globalPoint, list ); -} - void StandardPLPanel::toggleColumnShown( int i ) { treeView->setColumnHidden( i, !treeView->isColumnHidden( i ) ); @@ -233,143 +149,320 @@ void StandardPLPanel::toggleColumnShown( int i ) /* Search in the playlist */ void StandardPLPanel::search( const QString& searchText ) { - model->search( searchText ); + 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::doPopup( QModelIndex index, QPoint point ) +void StandardPLPanel::searchDelayed( const QString& searchText ) { - QItemSelectionModel *selection = treeView->selectionModel(); - QModelIndexList list = selection->selectedIndexes(); - model->popup( index, point, list ); + 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::setRootItem( playlist_item_t *p_item, bool b ) { - QPL_LOCK; - assert( p_item ); - - playlist_item_t *p_pref_item = playlist_GetPreferredNode( THEPL, p_item ); - if( p_pref_item ) p_item = p_pref_item; - - /* needed for popupAdd() */ - currentRootId = p_item->i_id; - - /* cosmetics, ..still need playlist locking.. */ - char *psz_title = input_item_GetName( p_item->p_input ); - title->setText( qfu(psz_title) ); - free( psz_title ); - - QPL_UNLOCK; - - /* do THE job */ - model->rebuild( p_item ); - - /* enable/disable adding */ - if( p_item == THEPL->p_local_category || - p_item == THEPL->p_local_onelevel ) +#ifdef MEDIA_LIBRARY + if( b ) { - addButton->setEnabled( true ); - addButton->setToolTip( qtr(I_PL_ADDPL) ); + msg_Dbg( p_intf, "Setting the SQL ML" ); + currentView->setModel( mlmodel ); } - else if( ( THEPL->p_ml_category && p_item == THEPL->p_ml_category) || - ( THEPL->p_ml_onelevel && p_item == THEPL->p_ml_onelevel ) ) + else +#else + Q_UNUSED( b ); +#endif { - addButton->setEnabled( true ); - addButton->setToolTip( qtr(I_PL_ADDML) ); + msg_Dbg( p_intf, "Normal PL/ML or SD" ); + if( currentView->model() != model ) + currentView->setModel( model ); + model->rebuild( p_item ); } - else - addButton->setEnabled( false ); } -void StandardPLPanel::removeItem( int i_id ) +void StandardPLPanel::browseInto( const QModelIndex &index ) +{ + if( currentView == iconView || currentView == listView || currentView == picFlowView ) + { + currentRootIndexId = model->itemId( index ); + currentView->setRootIndex( index ); + } + + emit viewChanged( index ); +} + +void StandardPLPanel::browseInto() +{ + browseInto( (currentRootIndexId != -1 && currentView != treeView) ? + model->index( currentRootIndexId, 0 ) : + QModelIndex() ); +} + +void StandardPLPanel::wheelEvent( QWheelEvent *e ) { - model->removeItem( i_id ); + // Accept this event in order to prevent unwanted volume up/down changes + e->accept(); } -/* Delete and Suppr key remove the selection - FilterKey function and code function */ -void StandardPLPanel::keyPressEvent( QKeyEvent *e ) +bool StandardPLPanel::eventFilter ( QObject *, QEvent * event ) { - switch( e->key() ) + if (event->type() == QEvent::KeyPress) { - case Qt::Key_Back: - case Qt::Key_Delete: - deleteSelection(); - break; + QKeyEvent *keyEvent = static_cast(event); + if( keyEvent->key() == Qt::Key_Delete || + keyEvent->key() == Qt::Key_Backspace ) + { + deleteSelection(); + return true; + } } + return false; } void StandardPLPanel::deleteSelection() { - QItemSelectionModel *selection = treeView->selectionModel(); + QItemSelectionModel *selection = currentView->selectionModel(); QModelIndexList list = selection->selectedIndexes(); model->doDelete( list ); } -void StandardPLPanel::toggleView() +void StandardPLPanel::createIconView() +{ + iconView = new PlIconView( model, this ); + iconView->setContextMenuPolicy( Qt::CustomContextMenu ); + CONNECT( iconView, customContextMenuRequested( const QPoint & ), + this, popupPlView( const QPoint & ) ); + CONNECT( iconView, activated( const QModelIndex & ), + this, activate( const QModelIndex & ) ); + iconView->installEventFilter( this ); + viewStack->addWidget( iconView ); +} + +void StandardPLPanel::createListView() { - if( treeView && treeView->isVisible() ) + listView = new PlListView( model, this ); + listView->setContextMenuPolicy( Qt::CustomContextMenu ); + CONNECT( listView, customContextMenuRequested( const QPoint & ), + this, popupPlView( const QPoint & ) ); + CONNECT( listView, activated( const QModelIndex & ), + this, activate( const QModelIndex & ) ); + listView->installEventFilter( this ); + 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 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 ); + treeView->header()->setContextMenuPolicy( Qt::CustomContextMenu ); + + treeView->setSelectionBehavior( QAbstractItemView::SelectRows ); + treeView->setSelectionMode( QAbstractItemView::ExtendedSelection ); + treeView->setDragEnabled( true ); + treeView->setAcceptDrops( true ); + treeView->setDropIndicatorShown( true ); + treeView->setContextMenuPolicy( Qt::CustomContextMenu ); + + /* setModel after setSortingEnabled(true), or the model will sort immediately! */ + + getSettings()->beginGroup("Playlist"); + + if( getSettings()->contains( "headerStateV2" ) ) { - if( iconView == NULL ) + treeView->header()->restoreState( + getSettings()->value( "headerStateV2" ).toByteArray() ); + } + else + { + for( int m = 1, c = 0; m != COLUMN_END; m <<= 1, c++ ) { - iconView = new PlIconView( model, this ); - layout->addWidget( iconView, 1, 0, 1, -1 ); - installEventFilter( iconView ); + treeView->setColumnHidden( c, !( m & COLUMN_DEFAULT ) ); + if( m == COLUMN_TITLE ) treeView->header()->resizeSection( c, 200 ); + else if( m == COLUMN_DURATION ) treeView->header()->resizeSection( c, 80 ); } - treeView->hide(); - iconView->show(); } + + getSettings()->endGroup(); + + /* Connections for the TreeView */ + CONNECT( treeView, activated( const QModelIndex& ), + this, activate( const QModelIndex& ) ); + CONNECT( treeView->header(), customContextMenuRequested( const QPoint & ), + this, popupSelectColumn( QPoint ) ); + CONNECT( treeView, customContextMenuRequested( const QPoint & ), + this, popupPlView( const QPoint & ) ); + treeView->installEventFilter( this ); + + /* SignalMapper for columns */ + selectColumnsSigMapper = new QSignalMapper( this ); + CONNECT( selectColumnsSigMapper, mapped( int ), + this, toggleColumnShown( int ) ); + + 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 ) { - iconView->hide(); - treeView->show(); + case ICON_VIEW: + { + if( iconView == NULL ) + createIconView(); + currentView = iconView; + break; + } + case LIST_VIEW: + { + if( listView == NULL ) + createListView(); + currentView = listView; + break; + } + 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; } -bool StandardPLPanel::eventFilter( QObject *obj, QEvent *event ) +void StandardPLPanel::cycleViews() { - QAbstractItemView *aView = qobject_cast(obj); - if( !aView ) return false; + if( currentView == iconView ) + showView( TREE_VIEW ); + 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 ); +} - switch( event->type() ) +void StandardPLPanel::activate( const QModelIndex &index ) +{ + if( currentView->model() == model ) { - case QEvent::MouseButtonPress: - { - QMouseEvent *mouseEvent = static_cast(event); - if( mouseEvent->button() & Qt::RightButton ) - { - QModelIndex index = aView->indexAt( - QPoint( mouseEvent->x(), mouseEvent->y() ) ); - doPopup( index, QCursor::pos() ); - return true; - } - else if( mouseEvent->button() & Qt::LeftButton ) - { - if( !aView->indexAt( QPoint( mouseEvent->x(), - mouseEvent->y() ) ).isValid() ) - aView->clearSelection(); - } - // aView->mousePressEvent( mouseEvent ); - } - return true; - case QEvent::MouseButtonRelease: - { - QMouseEvent *mouseEvent2 = static_cast(event); - if( mouseEvent2->button() & Qt::RightButton ) - return false; /* Do NOT forward to QTreeView!! */ - // aView->mouseReleaseEvent( mouseEvent ); - return true; - } - default: - return false; + /* 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 ); + } } - return true; } -void StandardPLPanel::wheelEvent( QWheelEvent *e ) +void StandardPLPanel::browseInto( int i_id ) { - // Accept this event in order to prevent unwanted volume up/down changes - e->accept(); + if( i_id != lastActivatedId ) return; + + QModelIndex index = model->index( i_id, 0 ); + playlist_Unlock( THEPL ); + + if( currentView == treeView ) + treeView->setExpanded( index, true ); + else + browseInto( index ); + + lastActivatedId = -1; }