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>
8 * Ilkka Ollakkka <ileoo (at) videolan dot org>
9 * Jakob Leben <jleben@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
31 #include "dialogs_provider.hpp"
32 #include "components/playlist/playlist_model.hpp"
33 #include "dialogs/mediainfo.hpp"
34 #include "dialogs/playlist.hpp"
35 #include <vlc_intf_strings.h>
37 #include "pixmaps/types/type_unknown.xpm"
43 #include <QApplication>
47 #include <QDesktopServices>
48 #include <QInputDialog>
53 I_DIR_OR_FOLDER( N_("Create Directory"), N_( "Create Folder" ) )
54 #define I_NEW_DIR_NAME \
55 I_DIR_OR_FOLDER( N_( "Enter name for new directory:" ), \
56 N_( "Enter name for new folder:" ) )
58 QIcon
PLModel::icons
[ITEM_TYPE_NUMBER
];
60 /*************************************************************************
61 * Playlist model implementation
62 *************************************************************************/
64 PLModel::PLModel( playlist_t
*_p_playlist
, /* THEPL */
65 intf_thread_t
*_p_intf
, /* main Qt p_intf */
66 playlist_item_t
* p_root
,
67 QObject
*parent
) /* Basic Qt parent */
68 : QAbstractItemModel( parent
)
71 p_playlist
= _p_playlist
;
73 i_cached_input_id
= -1;
74 i_popup_item
= i_popup_parent
= -1;
77 rootItem
= NULL
; /* PLItem rootItem, will be set in rebuild( ) */
79 /* Icons initialization */
80 #define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( x )
81 ADD_ICON( UNKNOWN
, type_unknown_xpm
);
82 ADD_ICON( FILE, ":/type/file" );
83 ADD_ICON( DIRECTORY
, ":/type/directory" );
84 ADD_ICON( DISC
, ":/type/disc" );
85 ADD_ICON( CDDA
, ":/type/cdda" );
86 ADD_ICON( CARD
, ":/type/capture-card" );
87 ADD_ICON( NET
, ":/type/net" );
88 ADD_ICON( PLAYLIST
, ":/type/playlist" );
89 ADD_ICON( NODE
, ":/type/node" );
93 DCONNECT( THEMIM
->getIM(), metaChanged( input_item_t
*),
94 this, processInputItemUpdate( input_item_t
*) );
95 DCONNECT( THEMIM
, inputChanged( input_thread_t
* ),
96 this, processInputItemUpdate( input_thread_t
* ) );
97 CONNECT( THEMIM
, playlistItemAppended( int, int ),
98 this, processItemAppend( int, int ) );
99 CONNECT( THEMIM
, playlistItemRemoved( int ),
100 this, processItemRemoval( int ) );
109 Qt::DropActions
PLModel::supportedDropActions() const
111 return Qt::CopyAction
| Qt::MoveAction
;
114 Qt::ItemFlags
PLModel::flags( const QModelIndex
&index
) const
116 Qt::ItemFlags flags
= QAbstractItemModel::flags( index
);
118 PLItem
*item
= index
.isValid() ? getItem( index
) : rootItem
;
123 playlist_item_t
*plItem
=
124 playlist_ItemGetById( p_playlist
, item
->i_id
);
126 if ( plItem
&& ( plItem
->i_children
> -1 ) )
127 flags
|= Qt::ItemIsDropEnabled
;
132 flags
|= Qt::ItemIsDragEnabled
;
137 QStringList
PLModel::mimeTypes() const
140 types
<< "vlc/qt-input-items";
144 bool modelIndexLessThen( const QModelIndex
&i1
, const QModelIndex
&i2
)
146 if( !i1
.isValid() || !i2
.isValid() ) return false;
147 PLItem
*item1
= static_cast<PLItem
*>( i1
.internalPointer() );
148 PLItem
*item2
= static_cast<PLItem
*>( i2
.internalPointer() );
149 if( item1
->parent() == item2
->parent() ) return i1
.row() < i2
.row();
150 else return *item1
< *item2
;
153 QMimeData
*PLModel::mimeData( const QModelIndexList
&indexes
) const
155 PlMimeData
*plMimeData
= new PlMimeData();
156 QModelIndexList list
;
158 foreach( const QModelIndex
&index
, indexes
) {
159 if( index
.isValid() && index
.column() == 0 )
163 qSort(list
.begin(), list
.end(), modelIndexLessThen
);
166 foreach( const QModelIndex
&index
, list
) {
169 PLItem
*testee
= getItem( index
);
170 while( testee
->parent() )
172 if( testee
->parent() == item
||
173 testee
->parent() == item
->parent() ) break;
174 testee
= testee
->parent();
176 if( testee
->parent() == item
) continue;
177 item
= getItem( index
);
180 item
= getItem( index
);
182 plMimeData
->appendItem( item
->p_input
);
189 bool PLModel::dropMimeData( const QMimeData
*data
, Qt::DropAction action
,
190 int row
, int column
, const QModelIndex
&parent
)
192 bool copy
= action
== Qt::CopyAction
;
193 if( !copy
&& action
!= Qt::MoveAction
)
196 const PlMimeData
*plMimeData
= qobject_cast
<const PlMimeData
*>( data
);
200 dropAppendCopy( plMimeData
, getItem( parent
), row
);
202 dropMove( plMimeData
, getItem( parent
), row
);
207 void PLModel::dropAppendCopy( const PlMimeData
*plMimeData
, PLItem
*target
, int pos
)
211 playlist_item_t
*p_parent
=
212 playlist_ItemGetByInput( p_playlist
, target
->p_input
);
213 if( !p_parent
) return;
215 if( pos
== -1 ) pos
= PLAYLIST_END
;
217 QList
<input_item_t
*> inputItems
= plMimeData
->inputItems();
219 foreach( input_item_t
* p_input
, inputItems
)
221 playlist_item_t
*p_item
= playlist_ItemGetByInput( p_playlist
, p_input
);
222 if( !p_item
) continue;
223 pos
= playlist_NodeAddCopy( p_playlist
, p_item
, p_parent
, pos
);
229 void PLModel::dropMove( const PlMimeData
* plMimeData
, PLItem
*target
, int row
)
231 QList
<input_item_t
*> inputItems
= plMimeData
->inputItems();
232 QList
<PLItem
*> model_items
;
233 playlist_item_t
*pp_items
[inputItems
.size()];
237 playlist_item_t
*p_parent
=
238 playlist_ItemGetByInput( p_playlist
, target
->p_input
);
240 if( !p_parent
|| row
> p_parent
->i_children
)
245 int new_pos
= row
== -1 ? p_parent
->i_children
: row
;
246 int model_pos
= new_pos
;
249 foreach( input_item_t
*p_input
, inputItems
)
251 playlist_item_t
*p_item
= playlist_ItemGetByInput( p_playlist
, p_input
);
252 if( !p_item
) continue;
254 PLItem
*item
= findByInput( rootItem
, p_input
->i_id
);
255 if( !item
) continue;
257 /* Better not try to move a node into itself.
258 Abort the whole operation in that case,
259 because it is ambiguous. */
260 PLItem
*climber
= target
;
263 if( climber
== item
)
267 climber
= climber
->parentItem
;
270 if( item
->parentItem
== target
&&
271 target
->children
.indexOf( item
) < new_pos
)
274 model_items
.append( item
);
275 pp_items
[i
] = p_item
;
279 if( model_items
.isEmpty() )
284 playlist_TreeMoveMany( p_playlist
, i
, pp_items
, p_parent
, new_pos
);
288 foreach( PLItem
*item
, model_items
)
291 insertChildren( target
, model_items
, model_pos
);
294 /* remove item with its id */
295 void PLModel::removeItem( int i_id
)
297 PLItem
*item
= findById( rootItem
, i_id
);
301 void PLModel::activateItem( const QModelIndex
&index
)
303 assert( index
.isValid() );
304 PLItem
*item
= getItem( index
);
307 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, item
->i_id
);
308 activateItem( p_item
);
312 /* Must be entered with lock */
313 void PLModel::activateItem( playlist_item_t
*p_item
)
315 if( !p_item
) return;
316 playlist_item_t
*p_parent
= p_item
;
319 if( p_parent
->i_id
== rootItem
->i_id
) break;
320 p_parent
= p_parent
->p_parent
;
323 playlist_Control( p_playlist
, PLAYLIST_VIEWPLAY
, pl_Locked
,
327 /****************** Base model mandatory implementations *****************/
328 QVariant
PLModel::data( const QModelIndex
&index
, int role
) const
330 if( !index
.isValid() ) return QVariant();
331 PLItem
*item
= getItem( index
);
332 if( role
== Qt::DisplayRole
)
334 int metadata
= columnToMeta( index
.column() );
335 if( metadata
== COLUMN_END
) return QVariant();
338 if( metadata
== COLUMN_NUMBER
)
339 returninfo
= QString::number( index
.row() + 1 );
342 char *psz
= psz_column_meta( item
->p_input
, metadata
);
343 returninfo
= qfu( psz
);
346 return QVariant( returninfo
);
348 else if( role
== Qt::DecorationRole
&& index
.column() == 0 )
350 /* Used to segfault here because i_type wasn't always initialized */
351 return QVariant( PLModel::icons
[item
->p_input
->i_type
] );
353 else if( role
== Qt::FontRole
)
355 if( isCurrent( index
) )
357 QFont f
; f
.setBold( true ); return QVariant( f
);
360 else if( role
== Qt::BackgroundRole
&& isCurrent( index
) )
362 return QVariant( QBrush( Qt::gray
) );
364 else if( role
== IsCurrentRole
) return QVariant( isCurrent( index
) );
365 else if( role
== IsLeafNodeRole
)
369 playlist_item_t
*plItem
=
370 playlist_ItemGetById( p_playlist
, item
->i_id
);
373 isLeaf
= plItem
->i_children
== -1;
381 bool PLModel::isCurrent( const QModelIndex
&index
) const
383 return getItem( index
)->p_input
== THEMIM
->currentInputItem();
386 int PLModel::itemId( const QModelIndex
&index
) const
388 return getItem( index
)->i_id
;
391 QVariant
PLModel::headerData( int section
, Qt::Orientation orientation
,
394 if (orientation
!= Qt::Horizontal
|| role
!= Qt::DisplayRole
)
397 int meta_col
= columnToMeta( section
);
399 if( meta_col
== COLUMN_END
) return QVariant();
401 return QVariant( qfu( psz_column_title( meta_col
) ) );
404 QModelIndex
PLModel::index( int row
, int column
, const QModelIndex
&parent
)
407 PLItem
*parentItem
= parent
.isValid() ? getItem( parent
) : rootItem
;
409 PLItem
*childItem
= parentItem
->child( row
);
411 return createIndex( row
, column
, childItem
);
413 return QModelIndex();
416 QModelIndex
PLModel::index( int i_id
, int c
)
418 return index( findById( rootItem
, i_id
), c
);
421 /* Return the index of a given item */
422 QModelIndex
PLModel::index( PLItem
*item
, int column
) const
424 if( !item
) return QModelIndex();
425 const PLItem
*parent
= item
->parent();
427 return createIndex( parent
->children
.lastIndexOf( item
),
429 return QModelIndex();
432 QModelIndex
PLModel::currentIndex()
434 input_thread_t
*p_input_thread
= THEMIM
->getInput();
435 if( !p_input_thread
) return QModelIndex();
436 PLItem
*item
= findByInput( rootItem
, input_GetItem( p_input_thread
)->i_id
);
437 return index( item
, 0 );
440 QModelIndex
PLModel::parent( const QModelIndex
&index
) const
442 if( !index
.isValid() ) return QModelIndex();
444 PLItem
*childItem
= getItem( index
);
447 msg_Err( p_playlist
, "NULL CHILD" );
448 return QModelIndex();
451 PLItem
*parentItem
= childItem
->parent();
452 if( !parentItem
|| parentItem
== rootItem
) return QModelIndex();
453 if( !parentItem
->parentItem
)
455 msg_Err( p_playlist
, "No parent parent, trying row 0 " );
456 msg_Err( p_playlist
, "----- PLEASE REPORT THIS ------" );
457 return createIndex( 0, 0, parentItem
);
459 QModelIndex ind
= createIndex(parentItem
->row(), 0, parentItem
);
463 int PLModel::columnCount( const QModelIndex
&i
) const
465 return columnFromMeta( COLUMN_END
);
468 int PLModel::rowCount( const QModelIndex
&parent
) const
470 PLItem
*parentItem
= parent
.isValid() ? getItem( parent
) : rootItem
;
471 return parentItem
->childCount();
474 QStringList
PLModel::selectedURIs()
477 for( int i
= 0; i
< current_selection
.size(); i
++ )
479 PLItem
*item
= getItem( current_selection
[i
] );
483 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, item
->i_id
);
486 char *psz
= input_item_GetURI( p_item
->p_input
);
489 lst
.append( qfu(psz
) );
500 /************************* Lookups *****************************/
502 PLItem
*PLModel::findById( PLItem
*root
, int i_id
)
504 return findInner( root
, i_id
, false );
507 PLItem
*PLModel::findByInput( PLItem
*root
, int i_id
)
509 PLItem
*result
= findInner( root
, i_id
, true );
513 #define CACHE( i, p ) { i_cached_id = i; p_cached_item = p; }
514 #define ICACHE( i, p ) { i_cached_input_id = i; p_cached_item_bi = p; }
516 PLItem
* PLModel::findInner( PLItem
*root
, int i_id
, bool b_input
)
518 if( !root
) return NULL
;
519 if( ( !b_input
&& i_cached_id
== i_id
) ||
520 ( b_input
&& i_cached_input_id
==i_id
) )
522 return b_input
? p_cached_item_bi
: p_cached_item
;
525 if( !b_input
&& root
->i_id
== i_id
)
530 else if( b_input
&& root
->p_input
->i_id
== i_id
)
532 ICACHE( i_id
, root
);
536 QList
<PLItem
*>::iterator it
= root
->children
.begin();
537 while ( it
!= root
->children
.end() )
539 if( !b_input
&& (*it
)->i_id
== i_id
)
541 CACHE( i_id
, (*it
) );
542 return p_cached_item
;
544 else if( b_input
&& (*it
)->p_input
->i_id
== i_id
)
546 ICACHE( i_id
, (*it
) );
547 return p_cached_item_bi
;
549 if( (*it
)->children
.size() )
551 PLItem
*childFound
= findInner( (*it
), i_id
, b_input
);
555 ICACHE( i_id
, childFound
)
557 CACHE( i_id
, childFound
)
568 int PLModel::columnToMeta( int _column
)
573 while( column
!= _column
&& meta
!= COLUMN_END
)
582 int PLModel::columnFromMeta( int meta_col
)
587 while( meta
!= meta_col
&& meta
!= COLUMN_END
)
596 bool PLModel::canEdit() const
601 rootItem
->p_input
== p_playlist
->p_playing
->p_input
||
603 p_playlist
->p_media_library
&&
604 rootItem
->p_input
== p_playlist
->p_media_library
->p_input
609 /************************* Updates handling *****************************/
611 /**** Events processing ****/
612 void PLModel::processInputItemUpdate( input_thread_t
*p_input
)
614 if( !p_input
) return;
615 if( p_input
&& !( p_input
->b_dead
|| !vlc_object_alive( p_input
) ) )
617 PLItem
*item
= findByInput( rootItem
, input_GetItem( p_input
)->i_id
);
618 if( item
) emit
currentChanged( index( item
, 0 ) );
620 processInputItemUpdate( input_GetItem( p_input
) );
623 void PLModel::processInputItemUpdate( input_item_t
*p_item
)
625 if( !p_item
|| p_item
->i_id
<= 0 ) return;
626 PLItem
*item
= findByInput( rootItem
, p_item
->i_id
);
628 updateTreeItem( item
);
631 void PLModel::processItemRemoval( int i_id
)
633 if( i_id
<= 0 ) return;
637 void PLModel::processItemAppend( int i_item
, int i_parent
)
639 playlist_item_t
*p_item
= NULL
;
640 PLItem
*newItem
= NULL
;
641 input_thread_t
*currentInputThread
;
644 PLItem
*nodeItem
= findById( rootItem
, i_parent
);
645 if( !nodeItem
) return;
647 foreach( PLItem
*existing
, nodeItem
->children
)
648 if( existing
->i_id
== i_item
) return;
651 p_item
= playlist_ItemGetById( p_playlist
, i_item
);
652 if( !p_item
|| p_item
->i_flags
& PLAYLIST_DBL_FLAG
)
657 for( pos
= 0; pos
< p_item
->p_parent
->i_children
; pos
++ )
658 if( p_item
->p_parent
->pp_children
[pos
] == p_item
) break;
660 newItem
= new PLItem( p_item
, nodeItem
);
663 beginInsertRows( index( nodeItem
, 0 ), pos
, pos
);
664 nodeItem
->insertChild( newItem
, pos
);
667 if( newItem
->p_input
== THEMIM
->currentInputItem() )
668 emit
currentChanged( index( newItem
, 0 ) );
672 void PLModel::rebuild()
677 void PLModel::rebuild( playlist_item_t
*p_root
)
679 playlist_item_t
* p_item
;
681 /* Invalidate cache */
682 i_cached_id
= i_cached_input_id
= -1;
684 if( rootItem
) rootItem
->removeChildren();
690 rootItem
= new PLItem( p_root
);
693 /* Recreate from root */
694 updateChildren( rootItem
);
697 /* And signal the view */
700 if( p_root
) emit
rootChanged();
703 void PLModel::takeItem( PLItem
*item
)
706 PLItem
*parent
= item
->parentItem
;
708 int i_index
= parent
->children
.indexOf( item
);
710 beginRemoveRows( index( parent
, 0 ), i_index
, i_index
);
711 parent
->takeChildAt( i_index
);
715 void PLModel::insertChildren( PLItem
*node
, QList
<PLItem
*>& items
, int i_pos
)
718 int count
= items
.size();
720 beginInsertRows( index( node
, 0 ), i_pos
, i_pos
+ count
- 1 );
721 for( int i
= 0; i
< count
; i
++ )
723 node
->children
.insert( i_pos
+ i
, items
[i
] );
724 items
[i
]->parentItem
= node
;
729 void PLModel::removeItem( PLItem
*item
)
734 i_cached_input_id
= -1;
736 if( item
->parentItem
) {
737 int i
= item
->parentItem
->children
.indexOf( item
);
738 beginRemoveRows( index( item
->parentItem
, 0), i
, i
);
739 item
->parentItem
->children
.removeAt(i
);
748 rebuild( p_playlist
->p_playing
);
752 /* This function must be entered WITH the playlist lock */
753 void PLModel::updateChildren( PLItem
*root
)
755 playlist_item_t
*p_node
= playlist_ItemGetById( p_playlist
, root
->i_id
);
756 updateChildren( p_node
, root
);
759 /* This function must be entered WITH the playlist lock */
760 void PLModel::updateChildren( playlist_item_t
*p_node
, PLItem
*root
)
762 for( int i
= 0; i
< p_node
->i_children
; i
++ )
764 if( p_node
->pp_children
[i
]->i_flags
& PLAYLIST_DBL_FLAG
) continue;
765 PLItem
*newItem
= new PLItem( p_node
->pp_children
[i
], root
);
766 root
->appendChild( newItem
);
767 if( p_node
->pp_children
[i
]->i_children
!= -1 )
768 updateChildren( p_node
->pp_children
[i
], newItem
);
772 /* Function doesn't need playlist-lock, as we don't touch playlist_item_t stuff here*/
773 void PLModel::updateTreeItem( PLItem
*item
)
776 emit
dataChanged( index( item
, 0 ) , index( item
, columnCount( QModelIndex() ) ) );
779 /************************* Actions ******************************/
782 * Lets not worry about nodes children, we do refersh anyway when
783 * core tells that playlist has changed, should give some more speed
785 void PLModel::doDelete( QModelIndexList selected
)
787 if( !canEdit() ) return;
789 while( !selected
.isEmpty() )
791 QModelIndex index
= selected
[0];
792 selected
.removeAt( 0 );
794 if( index
.column() != 0 ) continue;
796 PLItem
*item
= getItem( index
);
799 playlist_DeleteFromInput( p_playlist
, item
->p_input
, pl_Locked
);
806 void PLModel::recurseDelete( QList
<PLItem
*> children
, QModelIndexList
*fullList
)
808 for( int i
= children
.size() - 1; i
>= 0 ; i
-- )
810 PLItem
*item
= children
[i
];
811 if( item
->children
.size() )
812 recurseDelete( item
->children
, fullList
);
813 fullList
->removeAll( index( item
, 0 ) );
817 /******* Volume III: Sorting and searching ********/
818 void PLModel::sort( int column
, Qt::SortOrder order
)
820 sort( rootItem
->i_id
, column
, order
);
823 void PLModel::sort( int i_root_id
, int column
, Qt::SortOrder order
)
825 msg_Dbg( p_intf
, "Sorting by column %i, order %i", column
, order
);
827 int meta
= columnToMeta( column
);
828 if( meta
== COLUMN_END
) return;
830 PLItem
*item
= findById( rootItem
, i_root_id
);
832 QModelIndex qIndex
= index( item
, 0 );
833 int count
= item
->children
.size();
836 beginRemoveRows( qIndex
, 0, count
- 1 );
837 item
->removeChildren();
843 playlist_item_t
*p_root
= playlist_ItemGetById( p_playlist
,
847 playlist_RecursiveNodeSort( p_playlist
, p_root
,
848 i_column_sorting( meta
),
849 order
== Qt::AscendingOrder
?
850 ORDER_NORMAL
: ORDER_REVERSE
);
854 i_cached_id
= i_cached_input_id
= -1;
858 beginInsertRows( qIndex
, 0, count
- 1 );
859 updateChildren( item
);
863 /* if we have popup item, try to make sure that you keep that item visible */
864 if( i_popup_item
> -1 )
866 PLItem
*popupitem
= findById( rootItem
, i_popup_item
);
867 if( popupitem
) emit
currentChanged( index( popupitem
, 0 ) );
868 /* reset i_popup_item as we don't show it as selected anymore anyway */
871 else if( currentIndex().isValid() ) emit
currentChanged( currentIndex() );
874 void PLModel::search( const QString
& search_text
, const QModelIndex
& idx
, bool b_recursive
)
876 /** \todo Fire the search with a small delay ? */
879 playlist_item_t
*p_root
= playlist_ItemGetById( p_playlist
,
882 const char *psz_name
= qtu( search_text
);
883 playlist_LiveSearchUpdate( p_playlist
, p_root
, psz_name
, b_recursive
);
887 PLItem
*searchRoot
= getItem( idx
);
889 beginRemoveRows( idx
, 0, searchRoot
->children
.size() - 1 );
890 searchRoot
->removeChildren();
893 beginInsertRows( idx
, 0, searchRoot
->children
.size() - 1 );
894 updateChildren( searchRoot
);
905 /*********** Popup *********/
906 bool PLModel::popup( const QModelIndex
& index
, const QPoint
&point
, const QModelIndexList
&list
)
908 int i_id
= index
.isValid() ? itemId( index
) : rootItem
->i_id
;
911 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
, i_id
);
918 i_popup_item
= index
.isValid() ? p_item
->i_id
: -1;
919 i_popup_parent
= index
.isValid() ?
920 ( p_item
->p_parent
? p_item
->p_parent
->i_id
: -1 ) :
922 i_popup_column
= index
.column();
924 bool tree
= ( rootItem
&& rootItem
->i_id
!= p_playlist
->p_playing
->i_id
) ||
925 var_InheritBool( p_intf
, "playlist-tree" );
929 current_selection
= list
;
932 if( i_popup_item
> -1 )
934 menu
.addAction( QIcon( ":/menu/play" ), qtr(I_POP_PLAY
), this, SLOT( popupPlay() ) );
935 menu
.addAction( QIcon( ":/menu/stream" ),
936 qtr(I_POP_STREAM
), this, SLOT( popupStream() ) );
937 menu
.addAction( qtr(I_POP_SAVE
), this, SLOT( popupSave() ) );
938 menu
.addAction( QIcon( ":/menu/info" ), qtr(I_POP_INFO
), this, SLOT( popupInfo() ) );
939 menu
.addAction( QIcon( ":/type/folder-grey" ),
940 qtr( I_POP_EXPLORE
), this, SLOT( popupExplore() ) );
945 QIcon
addIcon( ":/buttons/playlist/playlist_add" );
947 if( tree
) menu
.addAction( addIcon
, qtr(I_POP_NEWFOLDER
), this, SLOT( popupAddNode() ) );
948 if( rootItem
->i_id
== THEPL
->p_playing
->i_id
)
950 menu
.addAction( addIcon
, qtr(I_PL_ADDF
), THEDP
, SLOT( simplePLAppendDialog()) );
951 menu
.addAction( addIcon
, qtr(I_PL_ADDDIR
), THEDP
, SLOT( PLAppendDir()) );
952 menu
.addAction( addIcon
, qtr(I_OP_ADVOP
), THEDP
, SLOT( PLAppendDialog()) );
954 else if( THEPL
->p_media_library
&&
955 rootItem
->i_id
== THEPL
->p_media_library
->i_id
)
957 menu
.addAction( addIcon
, qtr(I_PL_ADDF
), THEDP
, SLOT( simpleMLAppendDialog()) );
958 menu
.addAction( addIcon
, qtr(I_PL_ADDDIR
), THEDP
, SLOT( MLAppendDir() ) );
959 menu
.addAction( addIcon
, qtr(I_OP_ADVOP
), THEDP
, SLOT( MLAppendDialog() ) );
962 if( i_popup_item
> -1 )
964 menu
.addAction( QIcon( ":/buttons/playlist/playlist_remove" ),
965 qtr(I_POP_DEL
), this, SLOT( popupDel() ) );
969 sortingMenu
= new QMenu( qtr( "Sort by" ) );
970 sortingMapper
= new QSignalMapper( this );
972 for( i
= 1, j
= 1; i
< COLUMN_END
; i
<<= 1, j
++ )
974 if( i
== COLUMN_NUMBER
) continue;
975 QMenu
*m
= sortingMenu
->addMenu( qfu( psz_column_title( i
) ) );
976 QAction
*asc
= m
->addAction( qtr("Ascending") );
977 QAction
*desc
= m
->addAction( qtr("Descending") );
978 sortingMapper
->setMapping( asc
, j
);
979 sortingMapper
->setMapping( desc
, -j
);
980 CONNECT( asc
, triggered(), sortingMapper
, map() );
981 CONNECT( desc
, triggered(), sortingMapper
, map() );
983 CONNECT( sortingMapper
, mapped( int ), this, popupSort( int ) );
985 menu
.addMenu( sortingMenu
);
987 if( !menu
.isEmpty() )
989 menu
.exec( point
); return true;
994 void PLModel::popupDel()
996 doDelete( current_selection
);
999 void PLModel::popupPlay()
1003 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
1005 activateItem( p_item
);
1010 void PLModel::popupInfo()
1013 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
1017 input_item_t
* p_input
= p_item
->p_input
;
1018 vlc_gc_incref( p_input
);
1020 MediaInfoDialog
*mid
= new MediaInfoDialog( p_intf
, p_input
);
1021 vlc_gc_decref( p_input
);
1022 mid
->setParent( PlaylistDialog::getInstance( p_intf
),
1029 void PLModel::popupStream()
1031 QStringList mrls
= selectedURIs();
1032 if( !mrls
.isEmpty() )
1033 THEDP
->streamingDialog( NULL
, mrls
[0], false );
1037 void PLModel::popupSave()
1039 QStringList mrls
= selectedURIs();
1040 if( !mrls
.isEmpty() )
1041 THEDP
->streamingDialog( NULL
, mrls
[0] );
1044 void PLModel::popupExplore()
1047 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
1051 input_item_t
*p_input
= p_item
->p_input
;
1052 char *psz_meta
= input_item_GetURI( p_input
);
1056 const char *psz_access
;
1057 const char *psz_demux
;
1059 input_SplitMRL( &psz_access
, &psz_demux
, &psz_path
, psz_meta
);
1061 if( !EMPTY_STR( psz_access
) && (
1062 !strncasecmp( psz_access
, "file", 4 ) ||
1063 !strncasecmp( psz_access
, "dire", 4 ) ))
1065 QFileInfo
info( qfu( decode_URI( psz_path
) ) );
1066 QDesktopServices::openUrl(
1067 QUrl::fromLocalFile( info
.absolutePath() ) );
1076 void PLModel::popupAddNode()
1079 QString name
= QInputDialog::getText( PlaylistDialog::getInstance( p_intf
),
1080 qtr( I_NEW_DIR
), qtr( I_NEW_DIR_NAME
),
1081 QLineEdit::Normal
, QString(), &ok
);
1082 if( !ok
|| name
.isEmpty() ) return;
1084 playlist_item_t
*p_item
= playlist_ItemGetById( p_playlist
,
1088 playlist_NodeCreate( p_playlist
, qtu( name
), p_item
, PLAYLIST_END
, 0, NULL
);
1093 void PLModel::popupSort( int column
)
1095 sort( i_popup_parent
,
1096 column
> 0 ? column
- 1 : -column
- 1,
1097 column
> 0 ? Qt::AscendingOrder
: Qt::DescendingOrder
);
1100 /******************* Drag and Drop helper class ******************/
1102 PlMimeData::PlMimeData( )
1105 PlMimeData::~PlMimeData()
1107 foreach( input_item_t
*p_item
, _inputItems
)
1108 vlc_gc_decref( p_item
);
1111 void PlMimeData::appendItem( input_item_t
*p_item
)
1113 vlc_gc_incref( p_item
);
1114 _inputItems
.append( p_item
);
1117 QList
<input_item_t
*> PlMimeData::inputItems() const
1122 QStringList
PlMimeData::formats () const
1125 fmts
<< "vlc/qt-input-items";