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 *****************************************************************************/
29 #include "components/playlist/playlist_model.hpp"
30 #include "dialogs/mediainfo.hpp"
31 #include <vlc_intf_strings.h>
33 #include "pixmaps/type_unknown.xpm"
39 #include <QApplication>
42 QIcon
PLModel::icons
[ITEM_TYPE_NUMBER
];
44 static int PlaylistChanged( vlc_object_t
*, const char *,
45 vlc_value_t
, vlc_value_t
, void * );
46 static int PlaylistNext( vlc_object_t
*, const char *,
47 vlc_value_t
, vlc_value_t
, void * );
48 static int ItemChanged( vlc_object_t
*, const char *,
49 vlc_value_t
, vlc_value_t
, void * );
50 static int ItemAppended( vlc_object_t
*p_this
, const char *psz_variable
,
51 vlc_value_t oval
, vlc_value_t nval
, void *param
);
52 static int ItemDeleted( vlc_object_t
*p_this
, const char *psz_variable
,
53 vlc_value_t oval
, vlc_value_t nval
, void *param
);
55 /*************************************************************************
56 * Playlist model implementation
57 *************************************************************************/
60 This model is called two times, for the selector and the standard panel
62 PLModel::PLModel( playlist_t
*_p_playlist
, /* THEPL */
63 intf_thread_t
*_p_intf
, /* main Qt p_intf */
64 playlist_item_t
* p_root
,
65 /*playlist_GetPreferredNode( THEPL, THEPL->p_local_category );
66 and THEPL->p_root_category for SelectPL */
67 int _i_depth
, /* -1 for StandPL, 1 for SelectPL */
68 QObject
*parent
) /* Basic Qt parent */
69 : QAbstractItemModel( parent
)
72 assert( i_depth
== DEPTH_SEL
|| i_depth
== DEPTH_PL
);
74 p_playlist
= _p_playlist
;
75 i_items_to_append
= 0;
76 b_need_update
= false;
78 i_cached_input_id
= -1;
79 i_popup_item
= i_popup_parent
= -1;
81 rootItem
= NULL
; /* PLItem rootItem, will be set in rebuild( ) */
83 /* Icons initialization */
84 #define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( QPixmap( x ) )
85 ADD_ICON( UNKNOWN
, type_unknown_xpm
);
86 ADD_ICON( FILE, ":/pixmaps/type_file.png" );
87 ADD_ICON( DIRECTORY
, ":/pixmaps/type_directory.png" );
88 ADD_ICON( DISC
, ":/pixmaps/disc_16px.png" );
89 ADD_ICON( CDDA
, ":/pixmaps/cdda_16px.png" );
90 ADD_ICON( CARD
, ":/pixmaps/capture-card_16px.png" );
91 ADD_ICON( NET
, ":/pixmaps/type_net.png" );
92 ADD_ICON( PLAYLIST
, ":/pixmaps/type_playlist.png" );
93 ADD_ICON( NODE
, ":/pixmaps/type_node.png" );
101 QSettings
settings( "vlc", "vlc-qt-interface" );
102 settings
.setValue( "qt-pl-showflags", rootItem
->i_showflags
);
107 Qt::DropActions
PLModel::supportedDropActions() const
109 return Qt::CopyAction
; /* Why not Qt::MoveAction */
112 Qt::ItemFlags
PLModel::flags( const QModelIndex
&index
) const
114 Qt::ItemFlags defaultFlags
= QAbstractItemModel::flags( index
);
115 if( index
.isValid() )
116 return Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled
| defaultFlags
;
118 return Qt::ItemIsDropEnabled
| defaultFlags
;
121 /* A list of model indexes are a playlist */
122 QStringList
PLModel::mimeTypes() const
125 types
<< "vlc/playlist-item-id";
129 QMimeData
*PLModel::mimeData( const QModelIndexList
&indexes
) const
131 QMimeData
*mimeData
= new QMimeData();
132 QByteArray encodedData
;
133 QDataStream
stream( &encodedData
, QIODevice::WriteOnly
);
135 foreach( QModelIndex index
, indexes
) {
136 if( index
.isValid() && index
.column() == 0 )
137 stream
<< itemId( index
);
139 mimeData
->setData( "vlc/playlist-item-id", encodedData
);
144 bool PLModel::dropMimeData( const QMimeData
*data
, Qt::DropAction action
,
145 int row
, int column
, const QModelIndex
&target
)
147 if( data
->hasFormat( "vlc/playlist-item-id" ) )
149 if( action
== Qt::IgnoreAction
)
153 if( target
.isValid() )
154 targetItem
= static_cast<PLItem
*>( target
.internalPointer() );
156 targetItem
= rootItem
;
158 QByteArray encodedData
= data
->data( "vlc/playlist-item-id" );
159 QDataStream
stream( &encodedData
, QIODevice::ReadOnly
);
161 PLItem
*newParentItem
;
162 while( !stream
.atEnd() )
169 playlist_item_t
*p_target
=
170 playlist_ItemGetById( p_playlist
, targetItem
->i_id
,
172 playlist_item_t
*p_src
= playlist_ItemGetById( p_playlist
, srcId
,
175 if( !p_target
|| !p_src
)
180 if( p_target
->i_children
== -1 ) /* A leaf */
182 PLItem
*parentItem
= targetItem
->parent();
183 assert( parentItem
);
184 playlist_item_t
*p_parent
=
185 playlist_ItemGetById( p_playlist
, parentItem
->i_id
,
192 for( i
= 0 ; i
< p_parent
->i_children
; i
++ )
193 if( p_parent
->pp_children
[i
] == p_target
) break;
194 playlist_TreeMove( p_playlist
, p_src
, p_parent
, i
);
195 newParentItem
= parentItem
;
199 /* \todo: if we drop on a top-level node, use copy instead ? */
200 playlist_TreeMove( p_playlist
, p_src
, p_target
, 0 );
202 newParentItem
= targetItem
;
204 /* Remove from source */
205 PLItem
*srcItem
= FindById( rootItem
, p_src
->i_id
);
206 // We dropped on the source selector. Ask the dialog to forward
210 emit
shouldRemove( p_src
->i_id
);
213 srcItem
->remove( srcItem
);
215 /* Display at new destination */
216 PLItem
*newItem
= new PLItem( p_src
, newParentItem
, this );
217 newParentItem
->insertChild( newItem
, i
, true );
218 UpdateTreeItem( p_src
, newItem
, true );
219 if( p_src
->i_children
!= -1 )
220 UpdateNodeChildren( newItem
);
227 /* remove item with its id */
228 void PLModel::removeItem( int i_id
)
230 PLItem
*item
= FindById( rootItem
, i_id
);
231 if( item
) item
->remove( item
);
234 /* callbacks and slots */
235 void PLModel::addCallbacks()
237 /* Some global changes happened -> Rebuild all */
238 var_AddCallback( p_playlist
, "intf-change", PlaylistChanged
, this );
239 /* We went to the next item */
240 var_AddCallback( p_playlist
, "playlist-current", PlaylistNext
, this );
241 /* One item has been updated */
242 var_AddCallback( p_playlist
, "item-change", ItemChanged
, this );
243 var_AddCallback( p_playlist
, "item-append", ItemAppended
, this );
244 var_AddCallback( p_playlist
, "item-deleted", ItemDeleted
, this );
247 void PLModel::delCallbacks()
249 var_DelCallback( p_playlist
, "item-change", ItemChanged
, this );
250 var_DelCallback( p_playlist
, "playlist-current", PlaylistNext
, this );
251 var_DelCallback( p_playlist
, "intf-change", PlaylistChanged
, this );
252 var_DelCallback( p_playlist
, "item-append", ItemAppended
, this );
253 var_DelCallback( p_playlist
, "item-deleted", ItemDeleted
, this );
256 void PLModel::activateItem( const QModelIndex
&index
)
258 assert( index
.isValid() );
259 PLItem
*item
= static_cast<PLItem
*>(index
.internalPointer());
262 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, item
->i_id
,
264 activateItem( p_item
);
268 /* Must be entered with lock */
269 void PLModel::activateItem( playlist_item_t
*p_item
)
271 if( !p_item
) return;
272 playlist_item_t
*p_parent
= p_item
;
275 if( p_parent
->i_id
== rootItem
->i_id
) break;
276 p_parent
= p_parent
->p_parent
;
279 playlist_Control( p_playlist
, PLAYLIST_VIEWPLAY
, VLC_TRUE
,
283 /****************** Base model mandatory implementations *****************/
284 QVariant
PLModel::data( const QModelIndex
&index
, int role
) const
286 if( !index
.isValid() ) return QVariant();
287 PLItem
*item
= static_cast<PLItem
*>(index
.internalPointer());
288 if( role
== Qt::DisplayRole
)
290 return QVariant( item
->columnString( index
.column() ) );
292 else if( role
== Qt::DecorationRole
&& index
.column() == 0 )
294 /* Use to segfault here because i_type wasn't always initialized */
295 if( item
->i_type
>= 0 )
296 return QVariant( PLModel::icons
[item
->i_type
] );
298 else if( role
== Qt::FontRole
)
300 if( item
->b_current
== true )
302 QFont f
; f
.setBold( true ); return QVariant( f
);
308 bool PLModel::isCurrent( const QModelIndex
&index
)
310 assert( index
.isValid() );
311 return static_cast<PLItem
*>(index
.internalPointer())->b_current
;
314 int PLModel::itemId( const QModelIndex
&index
) const
316 assert( index
.isValid() );
317 return static_cast<PLItem
*>(index
.internalPointer())->i_id
;
320 QVariant
PLModel::headerData( int section
, Qt::Orientation orientation
,
323 if (orientation
== Qt::Horizontal
&& role
== Qt::DisplayRole
)
324 return QVariant( rootItem
->columnString( section
) );
328 QModelIndex
PLModel::index( int row
, int column
, const QModelIndex
&parent
)
332 if( !parent
.isValid() )
333 parentItem
= rootItem
;
335 parentItem
= static_cast<PLItem
*>(parent
.internalPointer());
337 PLItem
*childItem
= parentItem
->child( row
);
339 return createIndex( row
, column
, childItem
);
341 return QModelIndex();
344 /* Return the index of a given item */
345 QModelIndex
PLModel::index( PLItem
*item
, int column
) const
347 if( !item
) return QModelIndex();
348 const PLItem
*parent
= item
->parent();
350 return createIndex( parent
->children
.lastIndexOf( item
),
352 return QModelIndex();
355 QModelIndex
PLModel::parent( const QModelIndex
&index
) const
357 if( !index
.isValid() ) return QModelIndex();
359 PLItem
*childItem
= static_cast<PLItem
*>(index
.internalPointer());
362 msg_Err( p_playlist
, "NULL CHILD" );
363 return QModelIndex();
366 PLItem
*parentItem
= childItem
->parent();
367 if( !parentItem
|| parentItem
== rootItem
) return QModelIndex();
368 if( !parentItem
->parentItem
)
370 msg_Err( p_playlist
, "No parent parent, trying row 0 " );
371 msg_Err( p_playlist
, "----- PLEASE REPORT THIS ------" );
372 return createIndex( 0, 0, parentItem
);
374 QModelIndex ind
= createIndex(parentItem
->row(), 0, parentItem
);
378 int PLModel::columnCount( const QModelIndex
&i
) const
380 return rootItem
->item_col_strings
.count();
383 int PLModel::childrenCount( const QModelIndex
&parent
) const
385 return rowCount( parent
);
388 int PLModel::rowCount( const QModelIndex
&parent
) const
392 if( !parent
.isValid() )
393 parentItem
= rootItem
;
395 parentItem
= static_cast<PLItem
*>(parent
.internalPointer());
397 return parentItem
->childCount();
400 /************************* General playlist status ***********************/
402 bool PLModel::hasRandom()
404 if( var_GetBool( p_playlist
, "random" ) ) return true;
407 bool PLModel::hasRepeat()
409 if( var_GetBool( p_playlist
, "repeat" ) ) return true;
412 bool PLModel::hasLoop()
414 if( var_GetBool( p_playlist
, "loop" ) ) return true;
417 void PLModel::setLoop( bool on
)
419 var_SetBool( p_playlist
, "loop", on
? VLC_TRUE
:VLC_FALSE
);
420 config_PutInt( p_playlist
, "loop", on
? 1: 0 );
422 void PLModel::setRepeat( bool on
)
424 var_SetBool( p_playlist
, "repeat", on
? VLC_TRUE
:VLC_FALSE
);
425 config_PutInt( p_playlist
, "repeat", on
? 1: 0 );
427 void PLModel::setRandom( bool on
)
429 var_SetBool( p_playlist
, "random", on
? VLC_TRUE
:VLC_FALSE
);
430 config_PutInt( p_playlist
, "random", on
? 1: 0 );
433 /************************* Lookups *****************************/
435 PLItem
*PLModel::FindById( PLItem
*root
, int i_id
)
437 return FindInner( root
, i_id
, false );
440 PLItem
*PLModel::FindByInput( PLItem
*root
, int i_id
)
442 return FindInner( root
, i_id
, true );
445 #define CACHE( i, p ) { i_cached_id = i; p_cached_item = p; }
446 #define ICACHE( i, p ) { i_cached_input_id = i; p_cached_item_bi = p; }
448 PLItem
* PLModel::FindInner( PLItem
*root
, int i_id
, bool b_input
)
450 if( ( !b_input
&& i_cached_id
== i_id
) ||
451 ( b_input
&& i_cached_input_id
==i_id
) )
453 return b_input
? p_cached_item_bi
: p_cached_item
;
456 if( !b_input
&& root
->i_id
== i_id
)
461 else if( b_input
&& root
->i_input_id
== i_id
)
463 ICACHE( i_id
, root
);
467 QList
<PLItem
*>::iterator it
= root
->children
.begin();
468 while ( it
!= root
->children
.end() )
470 if( !b_input
&& (*it
)->i_id
== i_id
)
472 CACHE( i_id
, (*it
) );
473 return p_cached_item
;
475 else if( b_input
&& (*it
)->i_input_id
== i_id
)
477 ICACHE( i_id
, (*it
) );
478 return p_cached_item_bi
;
480 if( (*it
)->children
.size() )
482 PLItem
*childFound
= FindInner( (*it
), i_id
, b_input
);
486 ICACHE( i_id
, childFound
)
488 CACHE( i_id
, childFound
)
500 /************************* Updates handling *****************************/
501 void PLModel::customEvent( QEvent
*event
)
503 int type
= event
->type();
504 if( type
!= ItemUpdate_Type
&& type
!= ItemAppend_Type
&&
505 type
!= ItemDelete_Type
&& type
!= PLUpdate_Type
)
508 PLEvent
*ple
= static_cast<PLEvent
*>(event
);
510 if( type
== ItemUpdate_Type
)
511 ProcessInputItemUpdate( ple
->i_id
);
512 else if( type
== ItemAppend_Type
)
513 ProcessItemAppend( ple
->p_add
);
514 else if( type
== ItemDelete_Type
)
515 ProcessItemRemoval( ple
->i_id
);
520 /**** Events processing ****/
521 void PLModel::ProcessInputItemUpdate( int i_input_id
)
523 if( i_input_id
<= 0 ) return;
524 PLItem
*item
= FindByInput( rootItem
, i_input_id
);
526 UpdateTreeItem( item
, true );
529 void PLModel::ProcessItemRemoval( int i_id
)
531 if( i_id
<= 0 ) return;
532 if( i_id
== i_cached_id
) i_cached_id
= -1;
533 i_cached_input_id
= -1;
538 void PLModel::ProcessItemAppend( playlist_add_t
*p_add
)
540 playlist_item_t
*p_item
= NULL
;
541 PLItem
*newItem
= NULL
;
543 if( b_need_update
) return;
545 PLItem
*nodeItem
= FindById( rootItem
, p_add
->i_node
);
547 if( !nodeItem
) goto end
;
549 p_item
= playlist_ItemGetById( p_playlist
, p_add
->i_item
, VLC_TRUE
);
550 if( !p_item
|| p_item
->i_flags
& PLAYLIST_DBL_FLAG
) goto end
;
551 if( i_depth
== DEPTH_SEL
&& p_item
->p_parent
&&
552 p_item
->p_parent
->i_id
!= rootItem
->i_id
)
555 newItem
= new PLItem( p_item
, nodeItem
, this );
556 nodeItem
->appendChild( newItem
);
557 UpdateTreeItem( p_item
, newItem
, true );
564 void PLModel::rebuild()
569 void PLModel::rebuild( playlist_item_t
*p_root
)
571 /* Remove callbacks before locking to avoid deadlocks */
573 /* Invalidate cache */
574 i_cached_id
= i_cached_input_id
= -1;
580 if( rootItem
->children
.size() )
582 beginRemoveRows( index( rootItem
, 0 ), 0,
583 rootItem
->children
.size() -1 );
584 qDeleteAll( rootItem
->children
);
585 rootItem
->children
.clear();
591 //if( rootItem ) delete rootItem;
592 rootItem
= new PLItem( p_root
, NULL
, this );
595 /* Recreate from root */
596 UpdateNodeChildren( rootItem
);
597 if( p_playlist
->status
.p_item
)
599 PLItem
*currentItem
= FindByInput( rootItem
,
600 p_playlist
->status
.p_item
->p_input
->i_id
);
603 UpdateTreeItem( p_playlist
->status
.p_item
, currentItem
,
609 /* And signal the view */
610 emit
layoutChanged();
614 /* This function must be entered WITH the playlist lock */
615 void PLModel::UpdateNodeChildren( PLItem
*root
)
617 playlist_item_t
*p_node
= playlist_ItemGetById( p_playlist
, root
->i_id
,
619 UpdateNodeChildren( p_node
, root
);
622 /* This function must be entered WITH the playlist lock */
623 void PLModel::UpdateNodeChildren( playlist_item_t
*p_node
, PLItem
*root
)
625 for( int i
= 0; i
< p_node
->i_children
; i
++ )
627 if( p_node
->pp_children
[i
]->i_flags
& PLAYLIST_DBL_FLAG
) continue;
628 PLItem
*newItem
= new PLItem( p_node
->pp_children
[i
], root
, this );
629 root
->appendChild( newItem
, false );
630 UpdateTreeItem( newItem
, false, true );
631 if( i_depth
== DEPTH_PL
&& p_node
->pp_children
[i
]->i_children
!= -1 )
632 UpdateNodeChildren( p_node
->pp_children
[i
], newItem
);
636 /* This function must be entered WITH the playlist lock */
637 void PLModel::UpdateTreeItem( PLItem
*item
, bool signal
, bool force
)
639 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, item
->i_id
,
641 UpdateTreeItem( p_item
, item
, signal
, force
);
644 /* This function must be entered WITH the playlist lock */
645 void PLModel::UpdateTreeItem( playlist_item_t
*p_item
, PLItem
*item
,
646 bool signal
, bool force
)
650 if( !force
&& i_depth
== DEPTH_SEL
&& p_item
->p_parent
&&
651 p_item
->p_parent
->i_id
!= rootItem
->i_id
)
653 item
->update( p_item
, p_item
== p_playlist
->status
.p_item
);
655 emit
dataChanged( index( item
, 0 ) , index( item
, 1 ) );
658 /************************* Actions ******************************/
661 * Deletion, here we have to do a ugly slow hack as we retrieve the full
662 * list of indexes to delete at once: when we delete a node and all of
663 * its children, we need to update the list.
664 * Todo: investigate whethere we can use ranges to be sure to delete all items?
666 void PLModel::doDelete( QModelIndexList selected
)
668 for( int i
= selected
.size() -1 ; i
>= 0; i
-- )
670 QModelIndex index
= selected
[i
];
671 if( index
.column() != 0 ) continue;
672 PLItem
*item
= static_cast<PLItem
*>(index
.internalPointer());
675 if( item
->children
.size() )
676 recurseDelete( item
->children
, &selected
);
677 doDeleteItem( item
, &selected
);
682 void PLModel::recurseDelete( QList
<PLItem
*> children
, QModelIndexList
*fullList
)
684 for( int i
= children
.size() - 1; i
>= 0 ; i
-- )
686 PLItem
*item
= children
[i
];
687 if( item
->children
.size() )
688 recurseDelete( item
->children
, fullList
);
689 doDeleteItem( item
, fullList
);
693 void PLModel::doDeleteItem( PLItem
*item
, QModelIndexList
*fullList
)
695 QModelIndex deleteIndex
= index( item
, 0 );
696 fullList
->removeAll( deleteIndex
);
699 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, item
->i_id
,
705 if( p_item
->i_children
== -1 )
706 playlist_DeleteFromInput( p_playlist
, item
->i_input_id
, VLC_TRUE
);
708 playlist_NodeDelete( p_playlist
, p_item
, VLC_TRUE
, VLC_FALSE
);
709 /* And finally, remove it from the tree */
710 item
->remove( item
);
714 /******* Volume III: Sorting and searching ********/
715 void PLModel::sort( int column
, Qt::SortOrder order
)
720 #define CHECK_COLUMN( meta ) \
722 if( ( shownFlags() & VLC_META_ENGINE_##meta ) ) \
724 if( column == i_index ) \
726 i_flag = VLC_META_ENGINE_##meta; \
730 CHECK_COLUMN( TITLE
);
731 CHECK_COLUMN( DURATION
);
732 CHECK_COLUMN( ARTIST
);
733 CHECK_COLUMN( GENRE
);
734 CHECK_COLUMN( COLLECTION
);
735 CHECK_COLUMN( SEQ_NUM
);
736 CHECK_COLUMN( DESCRIPTION
);
737 CHECK_COLUMN( TRACKID
);
744 playlist_item_t
*p_root
= playlist_ItemGetById( p_playlist
,
750 case VLC_META_ENGINE_TITLE
: i_mode
= SORT_TITLE_NODES_FIRST
;break;
751 case VLC_META_ENGINE_DURATION
: i_mode
= SORT_DURATION
; break;
752 case VLC_META_ENGINE_ARTIST
: i_mode
= SORT_ARTIST
; break;
753 case VLC_META_ENGINE_GENRE
: i_mode
= SORT_GENRE
; break;
754 case VLC_META_ENGINE_COLLECTION
: i_mode
= SORT_ALBUM
; break;
755 case VLC_META_ENGINE_SEQ_NUM
: i_mode
= SORT_TRACK_NUMBER
; break;
756 case VLC_META_ENGINE_DESCRIPTION
:i_mode
= SORT_DESCRIPTION
; break;
757 case VLC_META_ENGINE_TRACKID
: i_mode
= SORT_ID
; break;
758 default: i_mode
= SORT_TITLE_NODES_FIRST
;break;
762 playlist_RecursiveNodeSort( p_playlist
, p_root
, i_mode
,
763 order
== Qt::AscendingOrder
?
764 ORDER_NORMAL
: ORDER_REVERSE
);
765 p_playlist
->b_reset_currently_playing
= VLC_TRUE
;
772 void PLModel::search( QString search_text
)
774 /** \todo Fire the search with a small delay ? */
777 playlist_item_t
*p_root
= playlist_ItemGetById( p_playlist
,
781 char *psz_name
= search_text
.toUtf8().data();
782 playlist_LiveSearchUpdate( p_playlist
, p_root
, psz_name
);
788 /*********** Popup *********/
789 void PLModel::popup( QModelIndex
& index
, QPoint
&point
, QModelIndexList list
)
791 assert( index
.isValid() );
793 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
794 itemId( index
), VLC_TRUE
);
797 i_popup_item
= p_item
->i_id
;
798 i_popup_parent
= p_item
->p_parent
? p_item
->p_parent
->i_id
: -1;
800 current_selection
= list
;
801 QMenu
*menu
= new QMenu
;
802 menu
->addAction( qfu(I_POP_PLAY
), this, SLOT( popupPlay() ) );
803 menu
->addAction( qfu(I_POP_DEL
), this, SLOT( popupDel() ) );
804 menu
->addSeparator();
805 menu
->addAction( qfu(I_POP_STREAM
), this, SLOT( popupStream() ) );
806 menu
->addAction( qfu(I_POP_SAVE
), this, SLOT( popupSave() ) );
807 menu
->addSeparator();
808 menu
->addAction( qfu(I_POP_INFO
), this, SLOT( popupInfo() ) );
809 if( p_item
->i_children
> -1 )
811 menu
->addSeparator();
812 menu
->addAction( qfu(I_POP_SORT
), this, SLOT( popupSort() ) );
813 menu
->addAction( qfu(I_POP_ADD
), this, SLOT( popupAdd() ) );
816 menu
->addSeparator();
817 menu
->addAction( qfu( I_POP_EXPLORE
), this, SLOT( popupExplore() ) );
819 menu
->popup( point
);
826 void PLModel::viewchanged( int meta
)
833 case VLC_META_ENGINE_TITLE
:
835 case VLC_META_ENGINE_DURATION
:
837 case VLC_META_ENGINE_ARTIST
:
839 case VLC_META_ENGINE_GENRE
:
841 case VLC_META_ENGINE_COPYRIGHT
:
843 case VLC_META_ENGINE_COLLECTION
:
845 case VLC_META_ENGINE_SEQ_NUM
:
847 case VLC_META_ENGINE_DESCRIPTION
:
849 case VLC_META_ENGINE_TRACKID
:
854 /* UNUSED emit layoutAboutToBeChanged(); */
855 index
= __MIN( index
, rootItem
->item_col_strings
.count() );
856 QModelIndex parent
= createIndex( 0, 0, rootItem
);
858 if( rootItem
->i_showflags
& meta
)
859 /* Removing columns */
861 beginRemoveColumns( parent
, index
, index
+1 );
862 rootItem
->i_showflags
&= ~( meta
);
863 rootItem
->updateColumnHeaders();
869 beginInsertColumns( createIndex( 0, 0, rootItem
), index
, index
+1 );
870 rootItem
->i_showflags
|= meta
;
871 rootItem
->updateColumnHeaders();
878 void PLModel::popupDel()
880 doDelete( current_selection
);
882 void PLModel::popupPlay()
886 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
887 i_popup_item
,VLC_TRUE
);
888 activateItem( p_item
);
893 void PLModel::popupInfo()
895 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
900 MediaInfoDialog
*mid
= new MediaInfoDialog( p_intf
, p_item
->p_input
);
905 void PLModel::popupStream()
907 msg_Err( p_playlist
, "Stream not implemented" );
910 void PLModel::popupSave()
912 msg_Err( p_playlist
, "Save not implemented" );
916 #include <shellapi.h>
917 void PLModel::popupExplore()
919 ShellExecute( NULL
, "explore", "C:\\", NULL
, NULL
, SW_SHOWNORMAL
);
923 /**********************************************************************
925 **********************************************************************/
926 static int PlaylistChanged( vlc_object_t
*p_this
, const char *psz_variable
,
927 vlc_value_t oval
, vlc_value_t nval
, void *param
)
929 PLModel
*p_model
= (PLModel
*) param
;
930 PLEvent
*event
= new PLEvent( PLUpdate_Type
, 0 );
931 QApplication::postEvent( p_model
, static_cast<QEvent
*>(event
) );
935 static int PlaylistNext( vlc_object_t
*p_this
, const char *psz_variable
,
936 vlc_value_t oval
, vlc_value_t nval
, void *param
)
938 PLModel
*p_model
= (PLModel
*) param
;
939 PLEvent
*event
= new PLEvent( ItemUpdate_Type
, oval
.i_int
);
940 QApplication::postEvent( p_model
, static_cast<QEvent
*>(event
) );
941 event
= new PLEvent( ItemUpdate_Type
, nval
.i_int
);
942 QApplication::postEvent( p_model
, static_cast<QEvent
*>(event
) );
946 static int ItemChanged( vlc_object_t
*p_this
, const char *psz_variable
,
947 vlc_value_t oval
, vlc_value_t nval
, void *param
)
949 PLModel
*p_model
= (PLModel
*) param
;
950 PLEvent
*event
= new PLEvent( ItemUpdate_Type
, nval
.i_int
);
951 QApplication::postEvent( p_model
, static_cast<QEvent
*>(event
) );
955 static int ItemDeleted( vlc_object_t
*p_this
, const char *psz_variable
,
956 vlc_value_t oval
, vlc_value_t nval
, void *param
)
958 PLModel
*p_model
= (PLModel
*) param
;
959 PLEvent
*event
= new PLEvent( ItemDelete_Type
, nval
.i_int
);
960 QApplication::postEvent( p_model
, static_cast<QEvent
*>(event
) );
964 static int ItemAppended( vlc_object_t
*p_this
, const char *psz_variable
,
965 vlc_value_t oval
, vlc_value_t nval
, void *param
)
967 PLModel
*p_model
= (PLModel
*) param
;
968 playlist_add_t
*p_add
= (playlist_add_t
*)malloc( sizeof( playlist_add_t
));
969 memcpy( p_add
, nval
.p_address
, sizeof( playlist_add_t
) );
971 if( ++p_model
->i_items_to_append
>= 50 )
973 // p_model->b_need_update = VLC_TRUE;
974 // return VLC_SUCCESS;
976 PLEvent
*event
= new PLEvent( p_add
);
977 QApplication::postEvent( p_model
, static_cast<QEvent
*>(event
) );