Commit ca08ed0e authored by François Cartegnie's avatar François Cartegnie 🤞

Qt: Set popup entries logic into models, and keep interaction outside.

- popup now created according to the selected items and models.
- fixes view/popup model abstraction.
- allows introducing new methods/models.
parent 3de79f56
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "components/playlist/sorting.h" #include "components/playlist/sorting.h"
#include "dialogs_provider.hpp" #include "dialogs_provider.hpp"
#include "input_manager.hpp" /* THEMIM */ #include "input_manager.hpp" /* THEMIM */
#include "util/qt_dirs.hpp"
#include <assert.h> #include <assert.h>
#include <vlc_intf_strings.h> #include <vlc_intf_strings.h>
...@@ -99,7 +100,7 @@ MLModel::~MLModel() ...@@ -99,7 +100,7 @@ MLModel::~MLModel()
var_DelCallback( p_ml, "media-added", mediaAdded, this ); var_DelCallback( p_ml, "media-added", mediaAdded, this );
} }
void MLModel::clearPlaylist() void MLModel::removeAll()
{ {
vlc_array_t* p_where = vlc_array_new(); vlc_array_t* p_where = vlc_array_new();
if ( !p_where ) return; if ( !p_where ) return;
...@@ -499,32 +500,116 @@ void MLModel::activateItem( const QModelIndex &idx ) ...@@ -499,32 +500,116 @@ void MLModel::activateItem( const QModelIndex &idx )
AddItemToPlaylist( itemId( idx, MLMEDIA_ID ), true, p_ml, true ); AddItemToPlaylist( itemId( idx, MLMEDIA_ID ), true, p_ml, true );
} }
void MLModel::action( QAction *action, const QModelIndexList &indexes ) bool MLModel::action( QAction *action, const QModelIndexList &indexes )
{ {
actionsContainerType a = action->data().value<actionsContainerType>(); actionsContainerType a = action->data().value<actionsContainerType>();
input_item_t *p_input;
switch ( a.action ) switch ( a.action )
{ {
case actionsContainerType::ACTION_PLAY: case ACTION_PLAY:
if ( ! indexes.empty() && indexes.first().isValid() ) if ( ! indexes.empty() && indexes.first().isValid() )
{
activateItem( indexes.first() ); activateItem( indexes.first() );
return true;
}
break; break;
case actionsContainerType::ACTION_ADDTOPLAYLIST: case ACTION_ADDTOPLAYLIST:
foreach( const QModelIndex &index, indexes ) foreach( const QModelIndex &index, indexes )
{ {
if( !index.isValid() ) break; if( !index.isValid() ) return false;
AddItemToPlaylist( itemId( index, MLMEDIA_ID ), false, p_ml, true ); AddItemToPlaylist( itemId( index, MLMEDIA_ID ), false, p_ml, true );
} }
break; return true;
case actionsContainerType::ACTION_REMOVE: case ACTION_REMOVE:
doDelete( indexes ); doDelete( indexes );
return true;
case ACTION_SORT:
break; break;
case actionsContainerType::ACTION_SORT: case ACTION_CLEAR:
removeAll();
return true;
case ACTION_ENQUEUEFILE:
foreach( const QString &uri, a.uris )
playlist_Add( THEPL, uri.toAscii().constData(),
NULL, PLAYLIST_APPEND | PLAYLIST_PREPARSE,
PLAYLIST_END, false, pl_Unlocked );
return true;
case ACTION_ENQUEUEDIR:
if( a.uris.isEmpty() ) return false;
p_input = input_item_New( a.uris.first().toAscii().constData(), NULL );
if( unlikely( p_input == NULL ) ) return false;
/* FIXME: playlist_AddInput() can fail */
playlist_AddInput( THEPL, p_input,
PLAYLIST_APPEND,
PLAYLIST_END, true, pl_Unlocked );
vlc_gc_decref( p_input );
return true;
case ACTION_ENQUEUEGENERIC:
foreach( const QString &uri, a.uris )
{
p_input = input_item_New( qtu( uri ), NULL );
/* Insert options */
foreach( const QString &option, a.options.split( " :" ) )
{
QString temp = colon_unescape( option );
if( !temp.isEmpty() )
input_item_AddOption( p_input, qtu( temp ),
VLC_INPUT_OPTION_TRUSTED );
}
/* FIXME: playlist_AddInput() can fail */
playlist_AddInput( THEPL, p_input,
PLAYLIST_APPEND | PLAYLIST_PREPARSE,
PLAYLIST_END, false, pl_Unlocked );
vlc_gc_decref( p_input );
}
return true;
default:
break; break;
} }
return false;
}
bool MLModel::isSupportedAction( actions action, const QModelIndex &index ) const
{
switch ( action )
{
case ACTION_ADDTOPLAYLIST:
return index.isValid();
case ACTION_SORT:
return false;
case ACTION_PLAY:
case ACTION_STREAM:
case ACTION_SAVE:
case ACTION_INFO:
case ACTION_REMOVE:
return index.isValid();
case ACTION_EXPLORE:
if( index.isValid() )
return getURI( index ).startsWith( "file://" );
case ACTION_CREATENODE:
return false;
case ACTION_CLEAR:
return rowCount() && canEdit();
case ACTION_ENQUEUEFILE:
case ACTION_ENQUEUEDIR:
case ACTION_ENQUEUEGENERIC:
return canEdit();
default:
return false;
}
return false;
} }
QModelIndex MLModel::rootIndex() const QModelIndex MLModel::rootIndex() const
...@@ -545,13 +630,6 @@ bool MLModel::canEdit() const ...@@ -545,13 +630,6 @@ bool MLModel::canEdit() const
return true; return true;
} }
bool MLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const
{
if ( where == IN_SQLMEDIALIB )
return index.isValid();
return false;
}
QModelIndex MLModel::getIndexByMLID( int id ) const QModelIndex MLModel::getIndexByMLID( int id ) const
{ {
for( int i = 0; i < rowCount( ); i++ ) for( int i = 0; i < rowCount( ); i++ )
......
...@@ -82,6 +82,7 @@ public: ...@@ -82,6 +82,7 @@ public:
Qt::ItemFlags flags( const QModelIndex& ) const; Qt::ItemFlags flags( const QModelIndex& ) const;
QMimeData* mimeData( const QModelIndexList & indexes ) const; QMimeData* mimeData( const QModelIndexList & indexes ) const;
virtual bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() ); virtual bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() );
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );
// Custom functions // Custom functions
bool isEditable( const QModelIndex& ) const; bool isEditable( const QModelIndex& ) const;
...@@ -94,22 +95,21 @@ public: ...@@ -94,22 +95,21 @@ public:
virtual void rebuild( playlist_item_t * p = NULL ); virtual void rebuild( playlist_item_t * p = NULL );
virtual void doDelete( QModelIndexList selected ); virtual void doDelete( QModelIndexList selected );
virtual void createNode( QModelIndex, QString ) {}; virtual void createNode( QModelIndex, QString ) {};
virtual void removeAll();
virtual QModelIndex rootIndex() const; virtual QModelIndex rootIndex() const;
virtual void filter( const QString& search_text, const QModelIndex & root, bool b_recursive ); virtual void filter( const QString& search_text, const QModelIndex & root, bool b_recursive );
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );
virtual QModelIndex currentIndex() const; virtual QModelIndex currentIndex() const;
virtual QModelIndex indexByPLID( const int i_plid, const int c ) const; virtual QModelIndex indexByPLID( const int i_plid, const int c ) const;
virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const; virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const;
virtual bool isTree() const; virtual bool isTree() const;
virtual bool canEdit() const; virtual bool canEdit() const;
virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const; virtual bool action( QAction *action, const QModelIndexList &indexes );
virtual void action( QAction *action, const QModelIndexList &indexes ); virtual bool isSupportedAction( actions action, const QModelIndex & ) const;
/* VLCModelSubInterface virtual slots */ /* VLCModelSubInterface virtual slots */
virtual void activateItem( const QModelIndex &index ); virtual void activateItem( const QModelIndex &index );
virtual void clearPlaylist();
protected: protected:
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "qt4.hpp" #include "qt4.hpp"
#include "components/playlist/playlist_model.hpp" #include "components/playlist/playlist_model.hpp"
#include "input_manager.hpp" /* THEMIM */ #include "input_manager.hpp" /* THEMIM */
#include "util/qt_dirs.hpp"
#include <vlc_intf_strings.h> /* I_DIR */ #include <vlc_intf_strings.h> /* I_DIR */
...@@ -90,6 +91,16 @@ QModelIndexList VLCProxyModel::mapListToSource( const QModelIndexList& list ) ...@@ -90,6 +91,16 @@ QModelIndexList VLCProxyModel::mapListToSource( const QModelIndexList& list )
return newlist; return newlist;
} }
void VLCProxyModel::sort( const int column, Qt::SortOrder order )
{
/* sorting on PLModel affects playlist order. */
if ( model() == sourcemodels[ PL_MODEL ] )
model()->sort( column, order );
else
/* otherwise we just use native proxy sorting */
QSortFilterProxyModel::sort( column, order );
}
/************************************************************************* /*************************************************************************
* Playlist model implementation * Playlist model implementation
*************************************************************************/ *************************************************************************/
...@@ -479,20 +490,6 @@ PLItem* PLModel::getItem( const QModelIndex & index ) const ...@@ -479,20 +490,6 @@ PLItem* PLModel::getItem( const QModelIndex & index ) const
return item; return item;
} }
bool PLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const
{
if ( where == IN_PLAYLIST )
{
return itemId( index, PLAYLIST_ID ) == THEPL->p_playing->i_id;
}
else if ( where == IN_MEDIALIBRARY )
{
return ( p_playlist->p_media_library &&
rootItem->inputItem() == p_playlist->p_media_library->p_input );
}
return false;
}
QModelIndex PLModel::index( const int row, const int column, const QModelIndex &parent ) QModelIndex PLModel::index( const int row, const int column, const QModelIndex &parent )
const const
{ {
...@@ -615,6 +612,15 @@ PLItem * PLModel::findInner( PLItem *root, int i_id, bool b_isinputid ) const ...@@ -615,6 +612,15 @@ PLItem * PLModel::findInner( PLItem *root, int i_id, bool b_isinputid ) const
return NULL; return NULL;
} }
PLModel::pl_nodetype PLModel::getPLRootType() const
{
if ( rootItem->id( PLAYLIST_ID ) == 3 )
return ROOTTYPE_MEDIA_LIBRARY;
else
return ROOTTYPE_CURRENT_PLAYING; // id == 2
/* FIXME: handle all cases */
}
bool PLModel::canEdit() const bool PLModel::canEdit() const
{ {
return ( return (
...@@ -1006,7 +1012,7 @@ void PLModel::filter( const QString& search_text, const QModelIndex & idx, bool ...@@ -1006,7 +1012,7 @@ void PLModel::filter( const QString& search_text, const QModelIndex & idx, bool
rebuild(); rebuild();
} }
void PLModel::clearPlaylist() void PLModel::removeAll()
{ {
if( rowCount() < 1 ) return; if( rowCount() < 1 ) return;
...@@ -1032,19 +1038,24 @@ void PLModel::createNode( QModelIndex index, QString name ) ...@@ -1032,19 +1038,24 @@ void PLModel::createNode( QModelIndex index, QString name )
PL_UNLOCK; PL_UNLOCK;
} }
void PLModel::action( QAction *action, const QModelIndexList &indexes ) bool PLModel::action( QAction *action, const QModelIndexList &indexes )
{ {
QModelIndex index; QModelIndex index;
actionsContainerType a = action->data().value<actionsContainerType>(); actionsContainerType a = action->data().value<actionsContainerType>();
input_item_t *p_input;
switch ( a.action ) switch ( a.action )
{ {
case actionsContainerType::ACTION_PLAY: case ACTION_PLAY:
if ( !indexes.empty() && indexes.first().isValid() ) if ( !indexes.empty() && indexes.first().isValid() )
{
activateItem( indexes.first() ); activateItem( indexes.first() );
return true;
}
break; break;
case actionsContainerType::ACTION_ADDTOPLAYLIST: case ACTION_ADDTOPLAYLIST:
PL_LOCK; PL_LOCK;
foreach( const QModelIndex &currentIndex, indexes ) foreach( const QModelIndex &currentIndex, indexes )
{ {
...@@ -1056,22 +1067,107 @@ void PLModel::action( QAction *action, const QModelIndexList &indexes ) ...@@ -1056,22 +1067,107 @@ void PLModel::action( QAction *action, const QModelIndexList &indexes )
PLAYLIST_END ); PLAYLIST_END );
} }
PL_UNLOCK; PL_UNLOCK;
break; return true;
case actionsContainerType::ACTION_REMOVE: case ACTION_REMOVE:
doDelete( indexes ); doDelete( indexes );
break; return true;
case actionsContainerType::ACTION_SORT: case ACTION_SORT:
if ( indexes.empty() ) break; if ( indexes.empty() ) break;
index = indexes.first().parent(); index = indexes.first().parent();
if( !index.isValid() ) index = rootIndex(); if( !index.isValid() ) index = rootIndex();
sort( indexes.first(), index, sort( indexes.first(), index,
a.column > 0 ? a.column - 1 : -a.column - 1, a.column > 0 ? a.column - 1 : -a.column - 1,
a.column > 0 ? Qt::AscendingOrder : Qt::DescendingOrder ); a.column > 0 ? Qt::AscendingOrder : Qt::DescendingOrder );
return true;
case ACTION_CLEAR:
removeAll();
return true;
case ACTION_ENQUEUEFILE:
foreach( const QString &uri, a.uris )
playlist_Add( THEPL, uri.toAscii().constData(),
NULL, PLAYLIST_APPEND | PLAYLIST_PREPARSE,
PLAYLIST_END,
getPLRootType() == ROOTTYPE_CURRENT_PLAYING,
pl_Unlocked );
return true;
case ACTION_ENQUEUEDIR:
if( a.uris.isEmpty() ) break;
p_input = input_item_New( a.uris.first().toAscii().constData(), NULL );
if( unlikely( p_input == NULL ) ) break;
/* FIXME: playlist_AddInput() can fail */
playlist_AddInput( THEPL, p_input,
PLAYLIST_APPEND,
PLAYLIST_END,
getPLRootType() == ROOTTYPE_CURRENT_PLAYING,
pl_Unlocked );
vlc_gc_decref( p_input );
return true;
case ACTION_ENQUEUEGENERIC:
foreach( const QString &uri, a.uris )
{
p_input = input_item_New( qtu( uri ), NULL );
/* Insert options */
foreach( const QString &option, a.options.split( " :" ) )
{
QString temp = colon_unescape( option );
if( !temp.isEmpty() )
input_item_AddOption( p_input, qtu( temp ),
VLC_INPUT_OPTION_TRUSTED );
}
/* FIXME: playlist_AddInput() can fail */
playlist_AddInput( THEPL, p_input,
PLAYLIST_APPEND | PLAYLIST_PREPARSE,
PLAYLIST_END, true, pl_Unlocked );
vlc_gc_decref( p_input );
}
return true;
default:
break; break;
}
return false;
}
bool PLModel::isSupportedAction( actions action, const QModelIndex &index ) const
{
switch ( action )
{
case ACTION_ADDTOPLAYLIST:
/* Only if we are not already in Current Playing */
if ( getPLRootType() == ROOTTYPE_CURRENT_PLAYING ) return false;
if( index.isValid() && index != rootIndex() )
return ( itemId( index, PLAYLIST_ID ) != THEPL->p_playing->i_id );
case ACTION_SORT:
return rowCount();
case ACTION_PLAY:
case ACTION_STREAM:
case ACTION_SAVE:
case ACTION_INFO:
case ACTION_REMOVE:
return index.isValid() && index != rootIndex();
case ACTION_EXPLORE:
if( index.isValid() )
return getURI( index ).startsWith( "file://" );
case ACTION_CREATENODE:
return ( canEdit() && isTree() );
case ACTION_CLEAR:
return rowCount() && canEdit();
case ACTION_ENQUEUEFILE:
case ACTION_ENQUEUEDIR:
case ACTION_ENQUEUEGENERIC:
return canEdit();
default:
return false;
} }
return false;
} }
/******************* Drag and Drop helper class ******************/ /******************* Drag and Drop helper class ******************/
......
...@@ -60,12 +60,13 @@ public: ...@@ -60,12 +60,13 @@ public:
return qobject_cast<VLCModel *>( sourceModel() ); return qobject_cast<VLCModel *>( sourceModel() );
} }
/* Different Models Handling */
enum models enum models
{ {
PL_MODEL = 0, PL_MODEL = 0,
SQLML_MODEL /* note: keep it last */ SQLML_MODEL /* note: keep it last */
}; };
bool switchToModel( models type ); bool switchToModel( models type );
void setModel( models type, VLCModel *model ) void setModel( models type, VLCModel *model )
{ {
...@@ -73,24 +74,17 @@ public: ...@@ -73,24 +74,17 @@ public:
} }
QModelIndexList mapListToSource( const QModelIndexList& list ); QModelIndexList mapListToSource( const QModelIndexList& list );
/* Different Models Handling */
/* VLCModelSubInterface Methods */ /* VLCModelSubInterface Methods */
virtual void rebuild( playlist_item_t * p = NULL ) { model()->rebuild( p ); } virtual void rebuild( playlist_item_t * p = NULL ) { model()->rebuild( p ); }
virtual void doDelete( QModelIndexList list ) { model()->doDelete( mapListToSource( list ) ); } virtual void doDelete( QModelIndexList list ) { model()->doDelete( mapListToSource( list ) ); }
virtual void createNode( QModelIndex a, QString b ) { model()->createNode( mapToSource( a ), b ); } virtual void createNode( QModelIndex a, QString b ) { model()->createNode( mapToSource( a ), b ); }
virtual void removeAll() { model()->removeAll(); }
virtual QModelIndex rootIndex() const { return mapFromSource( model()->rootIndex() ); } virtual QModelIndex rootIndex() const { return mapFromSource( model()->rootIndex() ); }
virtual void filter( const QString& text, const QModelIndex & root, bool b_recursive ) virtual void filter( const QString& text, const QModelIndex & root, bool b_recursive )
{ {
model()->filter( text, mapToSource( root ), b_recursive ); model()->filter( text, mapToSource( root ), b_recursive );
} }
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder )
{
/* use native */
QSortFilterProxyModel::sort( column, order );
}
virtual QModelIndex currentIndex() const { return mapFromSource( model()->currentIndex() ); } virtual QModelIndex currentIndex() const { return mapFromSource( model()->currentIndex() ); }
virtual QModelIndex indexByPLID( const int i_plid, const int c ) const { return mapFromSource( model()->indexByPLID( i_plid, c ) ); } virtual QModelIndex indexByPLID( const int i_plid, const int c ) const { return mapFromSource( model()->indexByPLID( i_plid, c ) ); }
...@@ -99,19 +93,20 @@ public: ...@@ -99,19 +93,20 @@ public:
virtual bool isTree() const { return model()->isTree(); } virtual bool isTree() const { return model()->isTree(); }
virtual bool canEdit() const { return model()->canEdit(); } virtual bool canEdit() const { return model()->canEdit(); }
virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const { return model()->isCurrentItem( mapToSource( index ), where ); }
virtual QString getURI( const QModelIndex &index ) const { return model()->getURI( mapToSource( index ) ); } virtual QString getURI( const QModelIndex &index ) const { return model()->getURI( mapToSource( index ) ); }
virtual input_item_t *getInputItem( const QModelIndex &index ) const { return model()->getInputItem( mapToSource( index ) ); } virtual input_item_t *getInputItem( const QModelIndex &index ) const { return model()->getInputItem( mapToSource( index ) ); }
virtual QString getTitle( const QModelIndex &index ) const { return model()->getTitle( mapToSource( index ) ); } virtual QString getTitle( const QModelIndex &index ) const { return model()->getTitle( mapToSource( index ) ); }
virtual void action( QAction *action, const QModelIndexList &indexes ) virtual bool action( QAction *action, const QModelIndexList &indexes )
{ {
model()->action( action, mapListToSource( indexes ) ); return model()->action( action, mapListToSource( indexes ) );
} }
virtual bool isSupportedAction( actions action, const QModelIndex &index ) const { return model()->isSupportedAction( action, mapToSource( index ) ); }
/* Indirect slots handlers */ /* Indirect slots handlers */
virtual void activateItem( const QModelIndex &index ) { model()->activateItem( mapToSource( index ) ); } virtual void activateItem( const QModelIndex &index ) { model()->activateItem( mapToSource( index ) ); }
virtual void ensureArtRequested( const QModelIndex &index ) { model()->ensureArtRequested( mapToSource( index ) ); } virtual void ensureArtRequested( const QModelIndex &index ) { model()->ensureArtRequested( mapToSource( index ) ); }
virtual void clearPlaylist() { model()->clearPlaylist(); }
/* AbstractItemModel subclassing */
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );
/* Local signals for index conversion */ /* Local signals for index conversion */
public slots: public slots:
...@@ -172,6 +167,7 @@ public: ...@@ -172,6 +167,7 @@ public:
virtual void rebuild( playlist_item_t * p = NULL ); virtual void rebuild( playlist_item_t * p = NULL );
virtual void doDelete( QModelIndexList selected ); virtual void doDelete( QModelIndexList selected );
virtual void createNode( QModelIndex index, QString name ); virtual void createNode( QModelIndex index, QString name );
virtual void removeAll();
/* Lookups */ /* Lookups */
virtual QModelIndex rootIndex() const; virtual QModelIndex rootIndex() const;
...@@ -181,12 +177,11 @@ public: ...@@ -181,12 +177,11 @@ public:
virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const; virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const;
virtual bool isTree() const;