1 /*****************************************************************************
2 * playlist_model.cpp : Manage playlist model
3 ****************************************************************************
4 * Copyright (C) 2006-2007 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@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
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
32 #include <QApplication>
35 #include "components/playlist/playlist_model.hpp"
36 #include "dialogs/mediainfo.hpp"
37 #include <vlc_intf_strings.h>
39 #include "pixmaps/type_unknown.xpm"
41 QIcon PLModel::icons[ITEM_TYPE_NUMBER];
43 static int PlaylistChanged( vlc_object_t *, const char *,
44 vlc_value_t, vlc_value_t, void * );
45 static int PlaylistNext( vlc_object_t *, const char *,
46 vlc_value_t, vlc_value_t, void * );
47 static int ItemChanged( vlc_object_t *, const char *,
48 vlc_value_t, vlc_value_t, void * );
49 static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
50 vlc_value_t oval, vlc_value_t nval, void *param );
51 static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
52 vlc_value_t oval, vlc_value_t nval, void *param );
54 /*************************************************************************
55 * Playlist model implementation
56 *************************************************************************/
59 This model is called two times, for the selector and the standard panel
61 PLModel::PLModel( playlist_t *_p_playlist, /* THEPL */
62 intf_thread_t *_p_intf, /* main Qt p_intf */
63 playlist_item_t * p_root,
64 /*playlist_GetPreferredNode( THEPL, THEPL->p_local_category );
65 and THEPL->p_root_category for SelectPL */
66 int _i_depth, /* -1 for StandPL, 1 for SelectPL */
67 QObject *parent ) /* Basic Qt parent */
68 : QAbstractItemModel( parent )
71 assert( i_depth == DEPTH_SEL || i_depth == DEPTH_PL );
73 p_playlist = _p_playlist;
74 i_items_to_append = 0;
75 b_need_update = false;
77 i_cached_input_id = -1;
78 i_popup_item = i_popup_parent = -1;
80 rootItem = NULL; /* PLItem rootItem, will be set in rebuild( ) */
82 /* Icons initialization */
83 #define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( QPixmap( x ) )
84 ADD_ICON( UNKNOWN , type_unknown_xpm );
85 ADD_ICON( FILE, ":/pixmaps/type_file.png" );
86 ADD_ICON( DIRECTORY, ":/pixmaps/type_directory.png" );
87 ADD_ICON( DISC, ":/pixmaps/disc_16px.png" );
88 ADD_ICON( CDDA, ":/pixmaps/cdda_16px.png" );
89 ADD_ICON( CARD, ":/pixmaps/capture-card_16px.png" );
90 ADD_ICON( NET, ":/pixmaps/type_net.png" );
91 ADD_ICON( PLAYLIST, ":/pixmaps/type_playlist.png" );
92 ADD_ICON( NODE, ":/pixmaps/type_node.png" );
105 Qt::DropActions PLModel::supportedDropActions() const
107 return Qt::CopyAction; /* Why not Qt::MoveAction */
110 Qt::ItemFlags PLModel::flags( const QModelIndex &index ) const
112 Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index );
113 if( index.isValid() )
114 return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
116 return Qt::ItemIsDropEnabled | defaultFlags;
119 /* A list of model indexes are a playlist */
120 QStringList PLModel::mimeTypes() const
123 types << "vlc/playlist-item-id";
127 QMimeData *PLModel::mimeData( const QModelIndexList &indexes ) const
129 QMimeData *mimeData = new QMimeData();
130 QByteArray encodedData;
131 QDataStream stream( &encodedData, QIODevice::WriteOnly );
133 foreach( QModelIndex index, indexes ) {
134 if( index.isValid() && index.column() == 0 )
135 stream << itemId( index );
137 mimeData->setData( "vlc/playlist-item-id", encodedData );
142 bool PLModel::dropMimeData( const QMimeData *data, Qt::DropAction action,
143 int row, int column, const QModelIndex &target )
145 if( data->hasFormat( "vlc/playlist-item-id" ) )
147 if( action == Qt::IgnoreAction )
151 if( target.isValid() )
152 targetItem = static_cast<PLItem*>( target.internalPointer() );
154 targetItem = rootItem;
156 QByteArray encodedData = data->data( "vlc/playlist-item-id" );
157 QDataStream stream( &encodedData, QIODevice::ReadOnly );
159 PLItem *newParentItem;
160 while( !stream.atEnd() )
167 playlist_item_t *p_target =
168 playlist_ItemGetById( p_playlist, targetItem->i_id,
170 playlist_item_t *p_src = playlist_ItemGetById( p_playlist, srcId,
173 if( !p_target || !p_src )
178 if( p_target->i_children == -1 ) /* A leaf */
180 PLItem *parentItem = targetItem->parent();
181 assert( parentItem );
182 playlist_item_t *p_parent =
183 playlist_ItemGetById( p_playlist, parentItem->i_id,
190 for( i = 0 ; i< p_parent->i_children ; i++ )
191 if( p_parent->pp_children[i] == p_target ) break;
192 playlist_TreeMove( p_playlist, p_src, p_parent, i );
193 newParentItem = parentItem;
197 /* \todo: if we drop on a top-level node, use copy instead ? */
198 playlist_TreeMove( p_playlist, p_src, p_target, 0 );
200 newParentItem = targetItem;
202 /* Remove from source */
203 PLItem *srcItem = FindById( rootItem, p_src->i_id );
204 // We dropped on the source selector. Ask the dialog to forward
208 emit shouldRemove( p_src->i_id );
211 srcItem->remove( srcItem );
213 /* Display at new destination */
214 PLItem *newItem = new PLItem( p_src, newParentItem, this );
215 newParentItem->insertChild( newItem, i, true );
216 UpdateTreeItem( p_src, newItem, true );
217 if( p_src->i_children != -1 )
218 UpdateNodeChildren( newItem );
225 /* remove item with its id */
226 void PLModel::removeItem( int i_id )
228 PLItem *item = FindById( rootItem, i_id );
229 if( item ) item->remove( item );
232 /* callbacks and slots */
233 void PLModel::addCallbacks()
235 /* Some global changes happened -> Rebuild all */
236 var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
237 /* We went to the next item */
238 var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
239 /* One item has been updated */
240 var_AddCallback( p_playlist, "item-change", ItemChanged, this );
241 var_AddCallback( p_playlist, "item-append", ItemAppended, this );
242 var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
245 void PLModel::delCallbacks()
247 var_DelCallback( p_playlist, "item-change", ItemChanged, this );
248 var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
249 var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
250 var_DelCallback( p_playlist, "item-append", ItemAppended, this );
251 var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );
254 void PLModel::activateItem( const QModelIndex &index )
256 assert( index.isValid() );
257 PLItem *item = static_cast<PLItem*>(index.internalPointer());
260 playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id,
262 activateItem( p_item );
266 /* Must be entered with lock */
267 void PLModel::activateItem( playlist_item_t *p_item )
269 if( !p_item ) return;
270 playlist_item_t *p_parent = p_item;
273 if( p_parent->i_id == rootItem->i_id ) break;
274 p_parent = p_parent->p_parent;
277 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VLC_TRUE,
281 /****************** Base model mandatory implementations *****************/
282 QVariant PLModel::data( const QModelIndex &index, int role ) const
284 if( !index.isValid() ) return QVariant();
285 PLItem *item = static_cast<PLItem*>(index.internalPointer());
286 if( role == Qt::DisplayRole )
288 return QVariant( item->columnString( index.column() ) );
290 else if( role == Qt::DecorationRole && index.column() == 0 )
292 /* Use to segfault here because i_type wasn't always initialized */
293 if( item->i_type >= 0 )
294 return QVariant( PLModel::icons[item->i_type] );
296 else if( role == Qt::FontRole )
298 if( item->b_current == true )
300 QFont f; f.setBold( true ); return QVariant( f );
306 bool PLModel::isCurrent( const QModelIndex &index )
308 assert( index.isValid() );
309 return static_cast<PLItem*>(index.internalPointer())->b_current;
312 int PLModel::itemId( const QModelIndex &index ) const
314 assert( index.isValid() );
315 return static_cast<PLItem*>(index.internalPointer())->i_id;
318 QVariant PLModel::headerData( int section, Qt::Orientation orientation,
321 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
322 return QVariant( rootItem->columnString( section ) );
326 QModelIndex PLModel::index( int row, int column, const QModelIndex &parent )
330 if( !parent.isValid() )
331 parentItem = rootItem;
333 parentItem = static_cast<PLItem*>(parent.internalPointer());
335 PLItem *childItem = parentItem->child( row );
337 return createIndex( row, column, childItem );
339 return QModelIndex();
342 /* Return the index of a given item */
343 QModelIndex PLModel::index( PLItem *item, int column ) const
345 if( !item ) return QModelIndex();
346 const PLItem *parent = item->parent();
348 return createIndex( parent->children.lastIndexOf( item ),
350 return QModelIndex();
353 QModelIndex PLModel::parent( const QModelIndex &index ) const
355 if( !index.isValid() ) return QModelIndex();
357 PLItem *childItem = static_cast<PLItem*>(index.internalPointer());
360 msg_Err( p_playlist, "NULL CHILD" );
361 return QModelIndex();
364 PLItem *parentItem = childItem->parent();
365 if( !parentItem || parentItem == rootItem ) return QModelIndex();
366 if( !parentItem->parentItem )
368 msg_Err( p_playlist, "No parent parent, trying row 0 " );
369 msg_Err( p_playlist, "----- PLEASE REPORT THIS ------" );
370 return createIndex( 0, 0, parentItem );
372 QModelIndex ind = createIndex(parentItem->row(), 0, parentItem);
376 int PLModel::columnCount( const QModelIndex &i) const
378 return rootItem->item_col_strings.count();
381 int PLModel::childrenCount( const QModelIndex &parent ) const
383 return rowCount( parent );
386 int PLModel::rowCount( const QModelIndex &parent ) const
390 if( !parent.isValid() )
391 parentItem = rootItem;
393 parentItem = static_cast<PLItem*>(parent.internalPointer());
395 return parentItem->childCount();
398 /************************* General playlist status ***********************/
400 bool PLModel::hasRandom()
402 if( var_GetBool( p_playlist, "random" ) ) return true;
405 bool PLModel::hasRepeat()
407 if( var_GetBool( p_playlist, "repeat" ) ) return true;
410 bool PLModel::hasLoop()
412 if( var_GetBool( p_playlist, "loop" ) ) return true;
415 void PLModel::setLoop( bool on )
417 var_SetBool( p_playlist, "loop", on ? VLC_TRUE:VLC_FALSE );
418 config_PutInt( p_playlist, "loop", on ? 1: 0 );
420 void PLModel::setRepeat( bool on )
422 var_SetBool( p_playlist, "repeat", on ? VLC_TRUE:VLC_FALSE );
423 config_PutInt( p_playlist, "repeat", on ? 1: 0 );
425 void PLModel::setRandom( bool on )
427 var_SetBool( p_playlist, "random", on ? VLC_TRUE:VLC_FALSE );
428 config_PutInt( p_playlist, "random", on ? 1: 0 );
431 /************************* Lookups *****************************/
433 PLItem *PLModel::FindById( PLItem *root, int i_id )
435 return FindInner( root, i_id, false );
438 PLItem *PLModel::FindByInput( PLItem *root, int i_id )
440 return FindInner( root, i_id, true );
443 #define CACHE( i, p ) { i_cached_id = i; p_cached_item = p; }
444 #define ICACHE( i, p ) { i_cached_input_id = i; p_cached_item_bi = p; }
446 PLItem * PLModel::FindInner( PLItem *root, int i_id, bool b_input )
448 if( ( !b_input && i_cached_id == i_id) ||
449 ( b_input && i_cached_input_id ==i_id ) )
451 return b_input ? p_cached_item_bi : p_cached_item;
454 if( !b_input && root->i_id == i_id )
459 else if( b_input && root->i_input_id == i_id )
461 ICACHE( i_id, root );
465 QList<PLItem *>::iterator it = root->children.begin();
466 while ( it != root->children.end() )
468 if( !b_input && (*it)->i_id == i_id )
470 CACHE( i_id, (*it) );
471 return p_cached_item;
473 else if( b_input && (*it)->i_input_id == i_id )
475 ICACHE( i_id, (*it) );
476 return p_cached_item_bi;
478 if( (*it)->children.size() )
480 PLItem *childFound = FindInner( (*it), i_id, b_input );
484 ICACHE( i_id, childFound )
486 CACHE( i_id, childFound )
498 /************************* Updates handling *****************************/
499 void PLModel::customEvent( QEvent *event )
501 int type = event->type();
502 if( type != ItemUpdate_Type && type != ItemAppend_Type &&
503 type != ItemDelete_Type && type != PLUpdate_Type )
506 PLEvent *ple = static_cast<PLEvent *>(event);
508 if( type == ItemUpdate_Type )
509 ProcessInputItemUpdate( ple->i_id );
510 else if( type == ItemAppend_Type )
511 ProcessItemAppend( ple->p_add );
512 else if( type == ItemDelete_Type )
513 ProcessItemRemoval( ple->i_id );
518 /**** Events processing ****/
519 void PLModel::ProcessInputItemUpdate( int i_input_id )
521 if( i_input_id <= 0 ) return;
522 PLItem *item = FindByInput( rootItem, i_input_id );
524 UpdateTreeItem( item, true );
527 void PLModel::ProcessItemRemoval( int i_id )
529 if( i_id <= 0 ) return;
530 if( i_id == i_cached_id ) i_cached_id = -1;
531 i_cached_input_id = -1;
536 void PLModel::ProcessItemAppend( playlist_add_t *p_add )
538 playlist_item_t *p_item = NULL;
539 PLItem *newItem = NULL;
541 if( b_need_update ) return;
543 PLItem *nodeItem = FindById( rootItem, p_add->i_node );
545 if( !nodeItem ) goto end;
547 p_item = playlist_ItemGetById( p_playlist, p_add->i_item, VLC_TRUE );
548 if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG ) goto end;
549 if( i_depth == DEPTH_SEL && p_item->p_parent &&
550 p_item->p_parent->i_id != rootItem->i_id )
553 newItem = new PLItem( p_item, nodeItem, this );
554 nodeItem->appendChild( newItem );
555 UpdateTreeItem( p_item, newItem, true );
562 void PLModel::rebuild()
567 void PLModel::rebuild( playlist_item_t *p_root )
569 /* Remove callbacks before locking to avoid deadlocks */
571 /* Invalidate cache */
572 i_cached_id = i_cached_input_id = -1;
578 if( rootItem->children.size() )
580 beginRemoveRows( index( rootItem, 0 ), 0,
581 rootItem->children.size() -1 );
582 qDeleteAll( rootItem->children );
583 rootItem->children.clear();
589 //if( rootItem ) delete rootItem;
590 rootItem = new PLItem( p_root, NULL, this );
593 /* Recreate from root */
594 UpdateNodeChildren( rootItem );
595 if( p_playlist->status.p_item )
597 PLItem *currentItem = FindByInput( rootItem,
598 p_playlist->status.p_item->p_input->i_id );
601 UpdateTreeItem( p_playlist->status.p_item, currentItem,
607 /* And signal the view */
608 emit layoutChanged();
612 /* This function must be entered WITH the playlist lock */
613 void PLModel::UpdateNodeChildren( PLItem *root )
615 playlist_item_t *p_node = playlist_ItemGetById( p_playlist, root->i_id,
617 UpdateNodeChildren( p_node, root );
620 /* This function must be entered WITH the playlist lock */
621 void PLModel::UpdateNodeChildren( playlist_item_t *p_node, PLItem *root )
623 for( int i = 0; i < p_node->i_children ; i++ )
625 if( p_node->pp_children[i]->i_flags & PLAYLIST_DBL_FLAG ) continue;
626 PLItem *newItem = new PLItem( p_node->pp_children[i], root, this );
627 root->appendChild( newItem, false );
628 UpdateTreeItem( newItem, false, true );
629 if( i_depth == DEPTH_PL && p_node->pp_children[i]->i_children != -1 )
630 UpdateNodeChildren( p_node->pp_children[i], newItem );
634 /* This function must be entered WITH the playlist lock */
635 void PLModel::UpdateTreeItem( PLItem *item, bool signal, bool force )
637 playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id,
639 UpdateTreeItem( p_item, item, signal, force );
642 /* This function must be entered WITH the playlist lock */
643 void PLModel::UpdateTreeItem( playlist_item_t *p_item, PLItem *item,
644 bool signal, bool force )
648 if( !force && i_depth == DEPTH_SEL && p_item->p_parent &&
649 p_item->p_parent->i_id != rootItem->i_id )
651 item->update( p_item, p_item == p_playlist->status.p_item );
653 emit dataChanged( index( item, 0 ) , index( item, 1 ) );
656 /************************* Actions ******************************/
659 * Deletion, here we have to do a ugly slow hack as we retrieve the full
660 * list of indexes to delete at once: when we delete a node and all of
661 * its children, we need to update the list.
662 * Todo: investigate whethere we can use ranges to be sure to delete all items?
664 void PLModel::doDelete( QModelIndexList selected )
666 for( int i = selected.size() -1 ; i >= 0; i-- )
668 QModelIndex index = selected[i];
669 if( index.column() != 0 ) continue;
670 PLItem *item = static_cast<PLItem*>(index.internalPointer());
673 if( item->children.size() )
674 recurseDelete( item->children, &selected );
675 doDeleteItem( item, &selected );
680 void PLModel::recurseDelete( QList<PLItem*> children, QModelIndexList *fullList )
682 for( int i = children.size() - 1; i >= 0 ; i-- )
684 PLItem *item = children[i];
685 if( item->children.size() )
686 recurseDelete( item->children, fullList );
687 doDeleteItem( item, fullList );
691 void PLModel::doDeleteItem( PLItem *item, QModelIndexList *fullList )
693 QModelIndex deleteIndex = index( item, 0 );
694 fullList->removeAll( deleteIndex );
697 playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id,
703 if( p_item->i_children == -1 )
704 playlist_DeleteFromInput( p_playlist, item->i_input_id, VLC_TRUE );
706 playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE );
707 /* And finally, remove it from the tree */
708 item->remove( item );
712 /******* Volume III: Sorting and searching ********/
713 void PLModel::sort( int column, Qt::SortOrder order )
717 playlist_item_t *p_root = playlist_ItemGetById( p_playlist,
723 case 0: i_mode = SORT_TITLE_NODES_FIRST;break;
724 case 1: i_mode = SORT_ARTIST;break;
725 case 2: i_mode = SORT_DURATION; break;
726 default: i_mode = SORT_TITLE_NODES_FIRST; break;
729 playlist_RecursiveNodeSort( p_playlist, p_root, i_mode,
730 order == Qt::AscendingOrder ?
731 ORDER_NORMAL : ORDER_REVERSE );
737 void PLModel::search( QString search_text )
739 /** \todo Fire the search with a small delay ? */
742 playlist_item_t *p_root = playlist_ItemGetById( p_playlist,
746 char *psz_name = search_text.toUtf8().data();
747 playlist_LiveSearchUpdate( p_playlist , p_root, psz_name );
753 /*********** Popup *********/
754 void PLModel::popup( QModelIndex & index, QPoint &point, QModelIndexList list )
756 assert( index.isValid() );
758 playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
759 itemId( index ), VLC_TRUE );
762 i_popup_item = p_item->i_id;
763 i_popup_parent = p_item->p_parent ? p_item->p_parent->i_id : -1;
765 current_selection = list;
766 QMenu *menu = new QMenu;
767 menu->addAction( qfu(I_POP_PLAY), this, SLOT( popupPlay() ) );
768 menu->addAction( qfu(I_POP_DEL), this, SLOT( popupDel() ) );
769 menu->addSeparator();
770 menu->addAction( qfu(I_POP_STREAM), this, SLOT( popupStream() ) );
771 menu->addAction( qfu(I_POP_SAVE), this, SLOT( popupSave() ) );
772 menu->addSeparator();
773 menu->addAction( qfu(I_POP_INFO), this, SLOT( popupInfo() ) );
774 if( p_item->i_children > -1 )
776 menu->addSeparator();
777 menu->addAction( qfu(I_POP_SORT), this, SLOT( popupSort() ) );
778 menu->addAction( qfu(I_POP_ADD), this, SLOT( popupAdd() ) );
781 menu->addSeparator();
782 menu->addAction( qfu( I_POP_EXPLORE ), this, SLOT( popupExplore() ) );
784 menu->popup( point );
791 void PLModel::viewchanged( int meta )
798 case VLC_META_ENGINE_TITLE:
800 case VLC_META_ENGINE_DURATION:
802 case VLC_META_ENGINE_ARTIST:
804 case VLC_META_ENGINE_GENRE:
806 case VLC_META_ENGINE_COPYRIGHT:
808 case VLC_META_ENGINE_COLLECTION:
810 case VLC_META_ENGINE_SEQ_NUM:
812 case VLC_META_ENGINE_DESCRIPTION:
817 /* UNUSED emit layoutAboutToBeChanged(); */
818 index = __MIN( index , rootItem->item_col_strings.count() );
819 QModelIndex parent = createIndex( 0, 0, rootItem );
821 if( rootItem->i_showflags & meta )
822 /* Removing columns */
824 beginRemoveColumns( parent, index, index+1 );
825 rootItem->i_showflags &= ~( meta );
826 rootItem->updateColumnHeaders();
832 beginInsertColumns( createIndex( 0, 0, rootItem), index, index+1 );
833 rootItem->i_showflags |= meta;
834 rootItem->updateColumnHeaders();
838 config_PutInt( p_intf, "qt-pl-showflags", rootItem->i_showflags );
839 config_SaveConfigFile( p_intf, NULL );
843 void PLModel::popupDel()
845 doDelete( current_selection );
847 void PLModel::popupPlay()
851 playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
852 i_popup_item,VLC_TRUE );
853 activateItem( p_item );
858 void PLModel::popupInfo()
860 playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
865 MediaInfoDialog *mid = new MediaInfoDialog( p_intf, p_item->p_input );
870 void PLModel::popupStream()
872 msg_Err( p_playlist, "Stream not implemented" );
875 void PLModel::popupSave()
877 msg_Err( p_playlist, "Save not implemented" );
881 #include <shellapi.h>
882 void PLModel::popupExplore()
884 ShellExecuteW( NULL, L"explore", L"C:\\", NULL, NULL, SW_SHOWNORMAL );
888 /**********************************************************************
890 **********************************************************************/
891 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
892 vlc_value_t oval, vlc_value_t nval, void *param )
894 PLModel *p_model = (PLModel *) param;
895 PLEvent *event = new PLEvent( PLUpdate_Type, 0 );
896 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
900 static int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
901 vlc_value_t oval, vlc_value_t nval, void *param )
903 PLModel *p_model = (PLModel *) param;
904 PLEvent *event = new PLEvent( ItemUpdate_Type, oval.i_int );
905 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
906 event = new PLEvent( ItemUpdate_Type, nval.i_int );
907 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
911 static int ItemChanged( vlc_object_t *p_this, const char *psz_variable,
912 vlc_value_t oval, vlc_value_t nval, void *param )
914 PLModel *p_model = (PLModel *) param;
915 PLEvent *event = new PLEvent( ItemUpdate_Type, nval.i_int );
916 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
920 static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
921 vlc_value_t oval, vlc_value_t nval, void *param )
923 PLModel *p_model = (PLModel *) param;
924 PLEvent *event = new PLEvent( ItemDelete_Type, nval.i_int );
925 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
929 static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
930 vlc_value_t oval, vlc_value_t nval, void *param )
932 PLModel *p_model = (PLModel *) param;
933 playlist_add_t *p_add = (playlist_add_t *)malloc( sizeof( playlist_add_t));
934 memcpy( p_add, nval.p_address, sizeof( playlist_add_t ) );
936 if( ++p_model->i_items_to_append >= 50 )
938 // p_model->b_need_update = VLC_TRUE;
939 // return VLC_SUCCESS;
941 PLEvent *event = new PLEvent( p_add );
942 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );