]> git.sesse.net Git - vlc/blobdiff - modules/gui/qt4/components/playlist/playlist_model.cpp
Qt: use the new PlIconView class
[vlc] / modules / gui / qt4 / components / playlist / playlist_model.cpp
index 77b8dd13e8840ee979319986e7cce46bd49c9b0d..eb695f3ad66f6c8df0b0c9b8cf3383d4ce98a05c 100644 (file)
@@ -6,6 +6,7 @@
  *
  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
  *          Ilkka Ollakkka <ileoo (at) videolan dot org>
+ *          Jakob Leben <jleben@videolan.org>
  *
  * 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
 
 QIcon PLModel::icons[ITEM_TYPE_NUMBER];
 
-static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
-                         vlc_value_t oval, vlc_value_t nval, void *param );
-static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
-                        vlc_value_t oval, vlc_value_t nval, void *param );
-
 /*************************************************************************
  * Playlist model implementation
  *************************************************************************/
@@ -63,12 +59,9 @@ PLModel::PLModel( playlist_t *_p_playlist,  /* THEPL */
                   playlist_item_t * p_root,
                   /*playlist_GetPreferredNode( THEPL, THEPL->p_local_category );
                     and THEPL->p_root_category for SelectPL */
-                  int _i_depth,             /* -1 for StandPL, 1 for SelectPL */
                   QObject *parent )         /* Basic Qt parent */
                   : QAbstractItemModel( parent )
 {
-    i_depth = _i_depth;
-    assert( i_depth == DEPTH_SEL || i_depth == DEPTH_PL );
     p_intf            = _p_intf;
     p_playlist        = _p_playlist;
     i_cached_id       = -1;
@@ -78,19 +71,8 @@ PLModel::PLModel( playlist_t *_p_playlist,  /* THEPL */
 
     rootItem          = NULL; /* PLItem rootItem, will be set in rebuild( ) */
 
-    if( i_depth == DEPTH_SEL )
-        i_showflags = 0;
-    else
-    {
-        i_showflags = getSettings()->value( "qt-pl-showflags", COLUMN_DEFAULT ).toInt();
-        if( i_showflags < 1)
-            i_showflags = COLUMN_DEFAULT; /* reasonable default to show something */
-        else if ( i_showflags >= COLUMN_END )
-            i_showflags = COLUMN_END - 1; /* show everything */
-    }
-
     /* Icons initialization */
-#define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( QPixmap( x ) )
+#define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( x )
     ADD_ICON( UNKNOWN , type_unknown_xpm );
     ADD_ICON( FILE, ":/type/file" );
     ADD_ICON( DIRECTORY, ":/type/directory" );
@@ -102,18 +84,19 @@ PLModel::PLModel( playlist_t *_p_playlist,  /* THEPL */
     ADD_ICON( NODE, ":/type/node" );
 #undef ADD_ICON
 
-    rebuild( p_root );
+    rebuild( p_root, true );
     CONNECT( THEMIM->getIM(), metaChanged( input_item_t *),
             this, processInputItemUpdate( input_item_t *) );
     CONNECT( THEMIM, inputChanged( input_thread_t * ),
             this, processInputItemUpdate( input_thread_t* ) );
+    CONNECT( THEMIM, playlistItemAppended( int, int ),
+             this, processItemAppend( int, int ) );
+    CONNECT( THEMIM, playlistItemRemoved( int ),
+             this, processItemRemoval( int ) );
 }
 
 PLModel::~PLModel()
 {
-    if(i_depth == -1)
-        getSettings()->setValue( "qt-pl-showflags", i_showflags );
-    delCallbacks();
     delete rootItem;
 }
 
@@ -128,21 +111,7 @@ Qt::ItemFlags PLModel::flags( const QModelIndex &index ) const
 
     PLItem *item = index.isValid() ? getItem( index ) : rootItem;
 
-    input_item_t *pl_input =
-        p_playlist->p_local_category ?
-        p_playlist->p_local_category->p_input : NULL;
-    input_item_t *ml_input =
-        p_playlist->p_ml_category ?
-        p_playlist->p_ml_category->p_input : NULL;
-
-    if( i_depth == DEPTH_SEL )
-    {
-        if( ( pl_input && item->p_input == pl_input ) ||
-            ( ml_input && item->p_input == ml_input ) )
-                flags |= Qt::ItemIsDropEnabled;
-    }
-    else if( ( pl_input && rootItem->p_input == pl_input ) ||
-              ( ml_input && rootItem->p_input == ml_input ) )
+    if( canEdit() )
     {
         PL_LOCK;
         playlist_item_t *plItem =
@@ -248,7 +217,9 @@ void PLModel::dropAppendCopy( QByteArray& data, PLItem *target )
             PLAYLIST_APPEND | PLAYLIST_SPREPARSE, PLAYLIST_END,
             p_input->i_duration,
             p_input->i_options, p_input->ppsz_options, p_input->optflagc,
-            p_parent == p_playlist->p_local_category, true );
+            ( p_parent == p_playlist->p_local_category ||
+            p_parent == p_playlist->p_local_onelevel ),
+            true );
     }
     PL_UNLOCK;
 }
@@ -316,20 +287,6 @@ void PLModel::removeItem( int i_id )
     removeItem( item );
 }
 
-/* callbacks and slots */
-void PLModel::addCallbacks()
-{
-    /* One item has been updated */
-    var_AddCallback( p_playlist, "playlist-item-append", ItemAppended, this );
-    var_AddCallback( p_playlist, "playlist-item-deleted", ItemDeleted, this );
-}
-
-void PLModel::delCallbacks()
-{
-    var_DelCallback( p_playlist, "playlist-item-append", ItemAppended, this );
-    var_DelCallback( p_playlist, "playlist-item-deleted", ItemDeleted, this );
-}
-
 void PLModel::activateItem( const QModelIndex &index )
 {
     assert( index.isValid() );
@@ -363,15 +320,7 @@ QVariant PLModel::data( const QModelIndex &index, int role ) const
     PLItem *item = getItem( index );
     if( role == Qt::DisplayRole )
     {
-        if( i_depth == DEPTH_SEL )
-        {
-            vlc_mutex_lock( &item->p_input->lock );
-            QString returninfo = QString( qfu( item->p_input->psz_name ) );
-            vlc_mutex_unlock( &item->p_input->lock );
-            return QVariant(returninfo);
-        }
-
-        int metadata = columnToMeta( index.column(), i_showflags );
+        int metadata = columnToMeta( index.column() );
         if( metadata == COLUMN_END ) return QVariant();
 
         QString returninfo;
@@ -387,9 +336,8 @@ QVariant PLModel::data( const QModelIndex &index, int role ) const
     }
     else if( role == Qt::DecorationRole && index.column() == 0  )
     {
-        /* Use to segfault here because i_type wasn't always initialized */
-        if( item->p_input->i_type >= 0 )
-            return QVariant( PLModel::icons[item->p_input->i_type] );
+        /* Used to segfault here because i_type wasn't always initialized */
+        return QVariant( PLModel::icons[item->p_input->i_type] );
     }
     else if( role == Qt::FontRole )
     {
@@ -418,9 +366,7 @@ QVariant PLModel::headerData( int section, Qt::Orientation orientation,
     if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
         return QVariant();
 
-    if( i_depth == DEPTH_SEL ) return QVariant( QString("") );
-
-    int meta_col = columnToMeta( section, i_showflags );
+    int meta_col = columnToMeta( section );
 
     if( meta_col == COLUMN_END ) return QVariant();
 
@@ -475,17 +421,7 @@ QModelIndex PLModel::parent( const QModelIndex &index ) const
 
 int PLModel::columnCount( const QModelIndex &i) const
 {
-    int columnCount=0;
-    int metadata=1;
-    if( i_depth == DEPTH_SEL ) return 1;
-
-    while( metadata < COLUMN_END )
-    {
-        if( metadata & i_showflags )
-            columnCount++;
-        metadata <<= 1;
-    }
-    return columnCount;
+    return columnFromMeta( COLUMN_END );
 }
 
 int PLModel::rowCount( const QModelIndex &parent ) const
@@ -509,7 +445,7 @@ QStringList PLModel::selectedURIs()
                 char *psz = input_item_GetURI( p_item->p_input );
                 if( psz )
                 {
-                    lst.append( psz );
+                    lst.append( qfu(psz) );
                     free( psz );
                 }
             }
@@ -519,35 +455,6 @@ QStringList PLModel::selectedURIs()
     return lst;
 }
 
-/************************* General playlist status ***********************/
-
-bool PLModel::hasRandom()
-{
-    return var_GetBool( p_playlist, "random" );
-}
-bool PLModel::hasRepeat()
-{
-    return var_GetBool( p_playlist, "repeat" );
-}
-bool PLModel::hasLoop()
-{
-    return var_GetBool( p_playlist, "loop" );
-}
-void PLModel::setLoop( bool on )
-{
-    var_SetBool( p_playlist, "loop", on ? true:false );
-    config_PutInt( p_playlist, "loop", on ? 1: 0 );
-}
-void PLModel::setRepeat( bool on )
-{
-    var_SetBool( p_playlist, "repeat", on ? true:false );
-    config_PutInt( p_playlist, "repeat", on ? 1: 0 );
-}
-void PLModel::setRandom( bool on )
-{
-    var_SetBool( p_playlist, "random", on ? true:false );
-    config_PutInt( p_playlist, "random", on ? 1: 0 );
-}
 
 /************************* Lookups *****************************/
 
@@ -567,6 +474,7 @@ PLItem *PLModel::findByInput( PLItem *root, int i_id )
 
 PLItem * PLModel::findInner( PLItem *root, int i_id, bool b_input )
 {
+    if( !root ) return NULL;
     if( ( !b_input && i_cached_id == i_id) ||
         ( b_input && i_cached_input_id ==i_id ) )
     {
@@ -622,65 +530,48 @@ PLItem *PLModel::getItem( QModelIndex index )
     return static_cast<PLItem*>( index.internalPointer() );
 }
 
-/*
-Computes meta data column id from shown column index and shown columns flags.
-Returns COLUMN_END in case of failure.
-*/
-int PLModel::columnToMeta( int column, int shown_flags ) const
+int PLModel::columnToMeta( int _column ) const
 {
     int meta = 1;
-    int index = -1;
+    int column = 0;
 
-    while( meta < COLUMN_END )
+    while( column != _column && meta != COLUMN_END )
     {
-        if( meta & shown_flags )
-            index++;
-        if( index == column )
-            break;
         meta <<= 1;
+        column++;
     }
 
     return meta;
 }
 
-/*
-Computes shown column index from meta data column id and shown columns flags.
-meta_col must be contained in shown_flags!
-*/
-int PLModel::columnFromMeta( int meta_col, int shown_flags ) const
+int PLModel::columnFromMeta( int meta_col ) const
 {
-    assert( meta & shown_flags );
-
     int meta = 1;
-    int index = -1;
+    int column = 0;
 
-    while( meta < COLUMN_END )
+    while( meta != meta_col && meta != COLUMN_END )
     {
-        if( meta & shown_flags )
-            index++;
-        if( meta == meta_col )
-            break;
         meta <<= 1;
+        column++;
     }
 
-    return index;
+    return column;
 }
 
-/************************* Updates handling *****************************/
-void PLModel::customEvent( QEvent *event )
+bool PLModel::canEdit() const
 {
-    int type = event->type();
-    if( type != ItemAppend_Type &&
-        type != ItemDelete_Type )
-        return;
-
-    PLEvent *ple = static_cast<PLEvent *>(event);
-
-    if( type == ItemAppend_Type )
-        processItemAppend( &ple->add );
-    else if( type == ItemDelete_Type )
-        processItemRemoval( ple->i_id );
+  return (
+    rootItem != NULL &&
+    (
+      rootItem->p_input == p_playlist->p_local_category->p_input ||
+      (
+        p_playlist->p_ml_category &&
+        rootItem->p_input == p_playlist->p_ml_category->p_input
+      )
+    )
+  );
 }
+/************************* Updates handling *****************************/
 
 /**** Events processing ****/
 void PLModel::processInputItemUpdate( input_thread_t *p_input )
@@ -703,32 +594,29 @@ void PLModel::processInputItemUpdate( input_item_t *p_item )
     if( !p_item ||  p_item->i_id <= 0 ) return;
     PLItem *item = findByInput( rootItem, p_item->i_id );
     if( item )
-        updateTreeItem( item, true, true);
+        updateTreeItem( item );
 }
 
 void PLModel::processItemRemoval( int i_id )
 {
     if( i_id <= 0 ) return;
-    if( i_id == i_cached_id ) i_cached_id = -1;
-    i_cached_input_id = -1;
-
     removeItem( i_id );
 }
 
-void PLModel::processItemAppend( const playlist_add_t *p_add )
+void PLModel::processItemAppend( int i_item, int i_parent )
 {
     playlist_item_t *p_item = NULL;
     PLItem *newItem = NULL;
 
-    PLItem *nodeItem = findById( rootItem, p_add->i_node );
+    PLItem *nodeItem = findById( rootItem, i_parent );
     if( !nodeItem ) return;
 
+    foreach( PLItem *existing, nodeItem->children )
+      if( existing->i_id == i_item ) return;
+
     PL_LOCK;
-    p_item = playlist_ItemGetById( p_playlist, p_add->i_item );
+    p_item = playlist_ItemGetById( p_playlist, i_item );
     if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG ) goto end;
-    if( i_depth == DEPTH_SEL && p_item->p_parent &&
-                        p_item->p_parent->i_id != rootItem->i_id )
-        goto end;
 
     newItem = new PLItem( p_item, nodeItem );
     PL_UNLOCK;
@@ -736,7 +624,7 @@ void PLModel::processItemAppend( const playlist_add_t *p_add )
     beginInsertRows( index( nodeItem, 0 ), nodeItem->childCount(), nodeItem->childCount() );
     nodeItem->appendChild( newItem );
     endInsertRows();
-    updateTreeItem( newItem, true );
+    updateTreeItem( newItem );
     return;
 end:
     PL_UNLOCK;
@@ -746,14 +634,13 @@ end:
 
 void PLModel::rebuild()
 {
-    rebuild( NULL );
+    rebuild( NULL, false );
 }
 
-void PLModel::rebuild( playlist_item_t *p_root )
+void PLModel::rebuild( playlist_item_t *p_root, bool b_first )
 {
     playlist_item_t* p_item;
-    /* Remove callbacks before locking to avoid deadlocks */
-    delCallbacks();
+
     /* Invalidate cache */
     i_cached_id = i_cached_input_id = -1;
 
@@ -778,8 +665,6 @@ void PLModel::rebuild( playlist_item_t *p_root )
     reset();
 
     emit currentChanged( index( currentItem, 0 ) );
-
-    addCallbacks();
 }
 
 void PLModel::takeItem( PLItem *item )
@@ -811,14 +696,28 @@ void PLModel::insertChildren( PLItem *node, QList<PLItem*>& items, int i_pos )
 void PLModel::removeItem( PLItem *item )
 {
     if( !item ) return;
-    if( currentItem == item )
+
+    if( item->i_id == i_cached_id ) i_cached_id = -1;
+    i_cached_input_id = -1;
+
+    if( currentItem == item || rootItem == item)
     {
         currentItem = NULL;
         emit currentChanged( QModelIndex() );
     }
-    PLItem *parent = item->parentItem;
-    assert( parent );
-    parent->removeChild( item );
+
+    if(item == rootItem)
+        rootItem = NULL;
+
+    if( item->parentItem ) {
+        int i = item->parentItem->children.indexOf( item );
+        beginRemoveRows( index( item->parentItem, 0), i, i );
+        item->parentItem->children.removeAt(i);
+        delete item;
+        endRemoveRows();
+    }
+    else delete item;
+
 }
 
 /* This function must be entered WITH the playlist lock */
@@ -842,21 +741,16 @@ void PLModel::updateChildren( playlist_item_t *p_node, PLItem *root )
             currentItem = newItem;
             emit currentChanged( index( currentItem, 0 ) );
         }
-        if( i_depth == DEPTH_PL && p_node->pp_children[i]->i_children != -1 )
+        if( p_node->pp_children[i]->i_children != -1 )
             updateChildren( p_node->pp_children[i], newItem );
     }
 }
 
 /* Function doesn't need playlist-lock, as we don't touch playlist_item_t stuff here*/
-void PLModel::updateTreeItem( PLItem *item, bool signal, bool force )
+void PLModel::updateTreeItem( PLItem *item )
 {
-    if ( !item || !item->p_input )
-        return;
-    if( !force && i_depth == DEPTH_SEL && item->parentItem &&
-                                 item->parentItem->p_input != rootItem->p_input )
-        return;
-    if( signal )
-        emit dataChanged( index( item, 0 ) , index( item, columnCount( QModelIndex() ) ) );
+    if( !item ) return;
+    emit dataChanged( index( item, 0 ) , index( item, columnCount( QModelIndex() ) ) );
 }
 
 /************************* Actions ******************************/
@@ -869,6 +763,8 @@ void PLModel::updateTreeItem( PLItem *item, bool signal, bool force )
  */
 void PLModel::doDelete( QModelIndexList selected )
 {
+    if( !canEdit() ) return;
+
     for( int i = selected.size() -1 ; i >= 0; i-- )
     {
         QModelIndex index = selected[i];
@@ -912,11 +808,9 @@ void PLModel::doDeleteItem( PLItem *item, QModelIndexList *fullList )
     else
         playlist_NodeDelete( p_playlist, p_item, true, false );
     PL_UNLOCK;
+
     /* And finally, remove it from the tree */
-    int itemIndex = item->parentItem->children.indexOf( item );
-    beginRemoveRows( index( item->parentItem, 0), itemIndex, itemIndex );
     removeItem( item );
-    endRemoveRows();
 }
 
 /******* Volume III: Sorting and searching ********/
@@ -927,20 +821,8 @@ void PLModel::sort( int column, Qt::SortOrder order )
 
 void PLModel::sort( int i_root_id, int column, Qt::SortOrder order )
 {
-    int i_index = -1;
-    int i_flag = 0;
-
-    int i_column = 1;
-    for( i_column = 1; i_column != COLUMN_END; i_column<<=1 )
-    {
-        if( ( shownFlags() & i_column ) )
-            i_index++;
-        if( column == i_index )
-        {
-            i_flag = i_column;
-            break;
-        }
-    }
+    int meta = columnToMeta( column );
+    if( meta == COLUMN_END ) return;
 
     PLItem *item = findById( rootItem, i_root_id );
     if( !item ) return;
@@ -957,14 +839,17 @@ void PLModel::sort( int i_root_id, int column, Qt::SortOrder order )
     {
         playlist_item_t *p_root = playlist_ItemGetById( p_playlist,
                                                         i_root_id );
-        if( p_root && i_flag )
+        if( p_root )
         {
             playlist_RecursiveNodeSort( p_playlist, p_root,
-                                        i_column_sorting( i_flag ),
+                                        i_column_sorting( meta ),
                                         order == Qt::AscendingOrder ?
                                             ORDER_NORMAL : ORDER_REVERSE );
         }
     }
+
+    i_cached_id = i_cached_input_id = -1;
+
     if( count )
     {
         beginInsertRows( qIndex, 0, count - 1 );
@@ -1016,64 +901,33 @@ void PLModel::popup( QModelIndex & index, QPoint &point, QModelIndexList list )
     PL_UNLOCK;
 
     current_selection = list;
-    QMenu *menu = new QMenu;
+
+    QMenu menu;
     if( i_popup_item > -1 )
     {
-        menu->addAction( qtr(I_POP_PLAY), this, SLOT( popupPlay() ) );
-        menu->addAction( qtr(I_POP_DEL), this, SLOT( popupDel() ) );
-        menu->addSeparator();
-        menu->addAction( qtr(I_POP_STREAM), this, SLOT( popupStream() ) );
-        menu->addAction( qtr(I_POP_SAVE), this, SLOT( popupSave() ) );
-        menu->addSeparator();
-        menu->addAction( qtr(I_POP_INFO), this, SLOT( popupInfo() ) );
-        menu->addSeparator();
-        QMenu *sort_menu = menu->addMenu( qtr( "Sort by ") +
-            qfu( psz_column_title( columnToMeta( index.column(), i_showflags ) ) ) );
+        menu.addAction( qtr(I_POP_PLAY), this, SLOT( popupPlay() ) );
+        menu.addAction( qtr(I_POP_DEL), this, SLOT( popupDel() ) );
+        menu.addSeparator();
+        menu.addAction( qtr(I_POP_STREAM), this, SLOT( popupStream() ) );
+        menu.addAction( qtr(I_POP_SAVE), this, SLOT( popupSave() ) );
+        menu.addSeparator();
+        menu.addAction( qtr(I_POP_INFO), this, SLOT( popupInfo() ) );
+        menu.addSeparator();
+        QMenu *sort_menu = menu.addMenu( qtr( "Sort by ") +
+            qfu( psz_column_title( columnToMeta( index.column() ) ) ) );
         sort_menu->addAction( qtr( "Ascending" ),
             this, SLOT( popupSortAsc() ) );
         sort_menu->addAction( qtr( "Descending" ),
             this, SLOT( popupSortDesc() ) );
     }
-    if( tree )
-        menu->addAction( qtr(I_POP_ADD), this, SLOT( popupAddNode() ) );
+    if( tree && canEdit() )
+        menu.addAction( qtr(I_POP_ADD), this, SLOT( popupAddNode() ) );
     if( i_popup_item > -1 )
     {
-        menu->addSeparator();
-        menu->addAction( qtr( I_POP_EXPLORE ), this, SLOT( popupExplore() ) );
-    }
-    menu->popup( point );
-}
-
-void PLModel::viewchanged( int meta )
-{
-    assert( meta );
-    int _meta = meta;
-    if( rootItem )
-    {
-        if( i_showflags & meta )
-            /* Removing columns */
-        {
-            int index = columnFromMeta( meta, i_showflags );
-
-            beginRemoveColumns( QModelIndex(), index, index );
-            i_showflags &= ~( meta );
-            getSettings()->setValue( "qt-pl-showflags", i_showflags );
-            endRemoveColumns();
-        }
-        else
-        {
-            int sf = i_showflags;
-            sf |= meta;
-            int index = columnFromMeta( meta, sf );
-            /* Adding columns */
-            beginInsertColumns( QModelIndex(), index, index );
-            i_showflags = sf;
-            getSettings()->setValue( "qt-pl-showflags", i_showflags );
-            endInsertColumns();
-        }
-
-        emit columnsChanged( meta );
+        menu.addSeparator();
+        menu.addAction( qtr( I_POP_EXPLORE ), this, SLOT( popupExplore() ) );
     }
+    if( !menu.isEmpty() ) menu.exec( point );
 }
 
 void PLModel::popupDel()
@@ -1188,26 +1042,3 @@ void PLModel::popupSortDesc()
 {
     sort( i_popup_parent, i_popup_column, Qt::DescendingOrder );
 }
-/**********************************************************************
- * Playlist callbacks
- **********************************************************************/
-
-static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
-                        vlc_value_t oval, vlc_value_t nval, void *param )
-{
-    PLModel *p_model = (PLModel *) param;
-    PLEvent *event = new PLEvent( ItemDelete_Type, nval.i_int );
-    QApplication::postEvent( p_model, event );
-    return VLC_SUCCESS;
-}
-
-static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
-                         vlc_value_t oval, vlc_value_t nval, void *param )
-{
-    PLModel *p_model = (PLModel *) param;
-    const playlist_add_t *p_add = (playlist_add_t *)nval.p_address;
-    PLEvent *event = new PLEvent( p_add );
-    QApplication::postEvent( p_model, event );
-    return VLC_SUCCESS;
-}
-