i_cached_id = -1;
i_cached_input_id = -1;
i_popup_item = i_popup_parent = -1;
+ sortingMenu = NULL;
rootItem = NULL; /* PLItem rootItem, will be set in rebuild( ) */
#undef ADD_ICON
rebuild( p_root );
- CONNECT( THEMIM->getIM(), metaChanged( input_item_t *),
- this, processInputItemUpdate( input_item_t *) );
- CONNECT( THEMIM, inputChanged( input_thread_t * ),
- this, processInputItemUpdate( input_thread_t* ) );
+ DCONNECT( THEMIM->getIM(), metaChanged( input_item_t *),
+ this, processInputItemUpdate( input_item_t *) );
+ DCONNECT( THEMIM, inputChanged( input_thread_t * ),
+ this, processInputItemUpdate( input_thread_t* ) );
CONNECT( THEMIM, playlistItemAppended( int, int ),
this, processItemAppend( int, int ) );
CONNECT( THEMIM, playlistItemRemoved( int ),
PLModel::~PLModel()
{
delete rootItem;
+ delete sortingMenu;
}
Qt::DropActions PLModel::supportedDropActions() const
QStringList PLModel::mimeTypes() const
{
QStringList types;
- types << "vlc/qt-playlist-item";
+ types << "vlc/qt-input-items";
return types;
}
+bool modelIndexLessThen( const QModelIndex &i1, const QModelIndex &i2 )
+{
+ if( !i1.isValid() || !i2.isValid() ) return false;
+ PLItem *item1 = static_cast<PLItem*>( i1.internalPointer() );
+ PLItem *item2 = static_cast<PLItem*>( i2.internalPointer() );
+ if( item1->parent() == item2->parent() ) return i1.row() < i2.row();
+ else return *item1 < *item2;
+}
+
QMimeData *PLModel::mimeData( const QModelIndexList &indexes ) const
{
- QMimeData *mimeData = new QMimeData();
- QByteArray encodedData;
- QDataStream stream( &encodedData, QIODevice::WriteOnly );
+ PlMimeData *plMimeData = new PlMimeData();
QModelIndexList list;
foreach( const QModelIndex &index, indexes ) {
list.append(index);
}
- qSort(list);
+ qSort(list.begin(), list.end(), modelIndexLessThen);
+ PLItem *item = NULL;
foreach( const QModelIndex &index, list ) {
- PLItem *item = getItem( index );
- stream.writeRawData( (char*) &item, sizeof( PLItem* ) );
+ if( item )
+ {
+ PLItem *testee = getItem( index );
+ while( testee->parent() )
+ {
+ if( testee->parent() == item ||
+ testee->parent() == item->parent() ) break;
+ testee = testee->parent();
+ }
+ if( testee->parent() == item ) continue;
+ item = getItem( index );
+ }
+ else
+ item = getItem( index );
+
+ plMimeData->appendItem( item->p_input );
}
- mimeData->setData( "vlc/qt-playlist-item", encodedData );
- return mimeData;
+
+ return plMimeData;
}
/* Drop operation */
bool PLModel::dropMimeData( const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent )
{
- if( data->hasFormat( "vlc/qt-playlist-item" ) )
+ const PlMimeData *plMimeData = qobject_cast<const PlMimeData*>( data );
+ if( plMimeData )
{
if( action == Qt::IgnoreAction )
return true;
- PLItem *parentItem = parent.isValid() ? getItem( parent ) : rootItem;
-
PL_LOCK;
playlist_item_t *p_parent =
- playlist_ItemGetById( p_playlist, parentItem->i_id );
+ playlist_ItemGetById( p_playlist, itemId( parent ) );
if( !p_parent || p_parent->i_children == -1 )
{
PL_UNLOCK;
copy = true;
PL_UNLOCK;
- QByteArray encodedData = data->data( "vlc/qt-playlist-item" );
if( copy )
- dropAppendCopy( encodedData, parentItem );
+ dropAppendCopy( plMimeData, getItem( parent ) );
else
- dropMove( encodedData, parentItem, row );
+ dropMove( plMimeData, getItem( parent ), row );
}
return true;
}
-void PLModel::dropAppendCopy( QByteArray& data, PLItem *target )
+void PLModel::dropAppendCopy( const PlMimeData *plMimeData, PLItem *target )
{
- QDataStream stream( &data, QIODevice::ReadOnly );
-
PL_LOCK;
+
playlist_item_t *p_parent =
- playlist_ItemGetById( p_playlist, target->i_id );
- while( !stream.atEnd() )
+ playlist_ItemGetByInput( p_playlist, target->p_input );
+ if( !p_parent ) return;
+
+ bool b_flat = p_parent == p_playlist->p_playing &&
+ !var_InheritBool( p_intf, "playlist-tree" );
+
+ QList<input_item_t*> inputItems = plMimeData->inputItems();
+ foreach( input_item_t* p_input, inputItems )
{
- PLItem *item;
- stream.readRawData( (char*)&item, sizeof(PLItem*) );
- playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id );
+ playlist_item_t *p_item = playlist_ItemGetByInput( p_playlist, p_input );
if( !p_item ) continue;
- input_item_t *p_input = p_item->p_input;
- playlist_AddExt ( p_playlist,
- p_input->psz_uri, p_input->psz_name,
- 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_playing,
- true );
+
+ recursiveAppendCopy( p_playlist, p_item, p_parent, b_flat );
}
+
PL_UNLOCK;
}
-void PLModel::dropMove( QByteArray& data, PLItem *target, int row )
+/* Must be entered WITH playlist lock! */
+void PLModel::recursiveAppendCopy( playlist_t *p_playlist, playlist_item_t *source,
+ playlist_item_t *target, bool b_flat )
+{
+ input_item_t *srcInput = source->p_input;
+
+ if( !(source->i_children != -1 && b_flat) )
+ {
+ vlc_mutex_lock( &srcInput->lock );
+ input_item_t *newInput =
+ input_item_NewWithType( VLC_OBJECT(p_playlist),
+ srcInput->psz_uri, srcInput->psz_name,
+ srcInput->i_options, srcInput->ppsz_options,
+ srcInput->optflagc, srcInput->i_duration,
+ srcInput->i_type );
+ vlc_mutex_unlock( &srcInput->lock );
+
+ if( source->i_children != -1 )
+ target = playlist_NodeCreate( p_playlist, newInput->psz_name, target, 0, newInput );
+ else
+ playlist_NodeAddInput( p_playlist, newInput, target,
+ PLAYLIST_APPEND | PLAYLIST_SPREPARSE,
+ PLAYLIST_END, pl_Locked );
+ }
+ for( int i = 0; i < source->i_children; i++ )
+ recursiveAppendCopy( p_playlist, source->pp_children[i], target, b_flat );
+}
+
+void PLModel::dropMove( const PlMimeData * plMimeData, PLItem *target, int row )
{
- QDataStream stream( &data, QIODevice::ReadOnly );
+ QList<input_item_t*> inputItems = plMimeData->inputItems();
QList<PLItem*> model_items;
- QList<int> ids;
- int new_pos = row == -1 ? target->children.size() : row;
+ playlist_item_t *pp_items[inputItems.size()];
+
+ PL_LOCK;
+
+ playlist_item_t *p_parent =
+ playlist_ItemGetByInput( p_playlist, target->p_input );
+
+ if( !p_parent || row > p_parent->i_children )
+ {
+ PL_UNLOCK; return;
+ }
+
+ int new_pos = row == -1 ? p_parent->i_children : row;
int model_pos = new_pos;
- while( !stream.atEnd() )
+ int i = 0;
+
+ foreach( input_item_t *p_input, inputItems )
{
- PLItem *item;
- stream.readRawData( (char*)&item, sizeof(PLItem*) );
+ playlist_item_t *p_item = playlist_ItemGetByInput( p_playlist, p_input );
+ if( !p_item ) continue;
+
+ PLItem *item = findByInput( rootItem, p_input->i_id );
+ if( !item ) continue;
- /* better not try to move a node into itself: */
+ /* Better not try to move a node into itself.
+ Abort the whole operation in that case,
+ because it is ambiguous. */
PLItem *climber = target;
while( climber )
{
- if( climber == item ) break;
+ if( climber == item )
+ {
+ PL_UNLOCK; return;
+ }
climber = climber->parentItem;
}
- if( climber ) continue;
if( item->parentItem == target &&
- target->children.indexOf( item ) < model_pos )
+ target->children.indexOf( item ) < new_pos )
model_pos--;
- ids.append( item->i_id );
model_items.append( item );
-
- takeItem( item );
+ pp_items[i] = p_item;
+ i++;
}
- int count = ids.size();
- if( count )
+
+ if( model_items.isEmpty() )
{
- playlist_item_t *pp_items[count];
+ PL_UNLOCK; return;
+ }
- PL_LOCK;
- for( int i = 0; i < count; i++ )
- {
- playlist_item_t *p_item = playlist_ItemGetById( p_playlist, ids[i] );
- if( !p_item )
- {
- PL_UNLOCK;
- return;
- }
- pp_items[i] = p_item;
- }
- playlist_item_t *p_parent =
- playlist_ItemGetById( p_playlist, target->i_id );
- playlist_TreeMoveMany( p_playlist, count, pp_items, p_parent,
- new_pos );
- PL_UNLOCK;
+ playlist_TreeMoveMany( p_playlist, i, pp_items, p_parent, new_pos );
- insertChildren( target, model_items, model_pos );
- }
+ PL_UNLOCK;
+
+ foreach( PLItem *item, model_items )
+ takeItem( item );
+
+ insertChildren( target, model_items, model_pos );
}
/* remove item with its id */
return QVariant( QBrush( Qt::gray ) );
}
else if( role == IsCurrentRole ) return QVariant( isCurrent( index ) );
+ else if( role == IsLeafNodeRole )
+ {
+ QVariant isLeaf;
+ PL_LOCK;
+ playlist_item_t *plItem =
+ playlist_ItemGetById( p_playlist, item->i_id );
+
+ if( plItem )
+ isLeaf = plItem->i_children == -1;
+ PL_UNLOCK;
+ return isLeaf;
+ }
return QVariant();
}
{
if( !item ) return;
- if( item->i_id == i_cached_id ) i_cached_id = -1;
+ i_cached_id = -1;
i_cached_input_id = -1;
if( item->parentItem ) {
if( i_popup_item > -1 )
{
menu.addAction( QIcon( ":/menu/play" ), qtr(I_POP_PLAY), this, SLOT( popupPlay() ) );
- menu.addAction( QIcon( ":/buttons/playlist/playlist_remove" ),
- qtr(I_POP_DEL), this, SLOT( popupDel() ) );
- menu.addSeparator();
menu.addAction( QIcon( ":/menu/stream" ),
qtr(I_POP_STREAM), this, SLOT( popupStream() ) );
menu.addAction( qtr(I_POP_SAVE), this, SLOT( popupSave() ) );
- menu.addSeparator();
menu.addAction( QIcon( ":/menu/info" ), qtr(I_POP_INFO), this, SLOT( popupInfo() ) );
menu.addAction( QIcon( ":/type/folder-grey" ),
qtr( I_POP_EXPLORE ), this, SLOT( popupExplore() ) );
+ menu.addSeparator();
}
if( canEdit() )
{
}
if( i_popup_item > -1 )
{
+ menu.addAction( QIcon( ":/buttons/playlist/playlist_remove" ),
+ qtr(I_POP_DEL), this, SLOT( popupDel() ) );
menu.addSeparator();
- QMenu *sort_menu = menu.addMenu( qtr( "Sort by" ) + QString(" ") +
- qfu( psz_column_title( columnToMeta( index.column() ) ) ) );
- sort_menu->addAction( qtr( "Ascending" ),
- this, SLOT( popupSortAsc() ) );
- sort_menu->addAction( qtr( "Descending" ),
- this, SLOT( popupSortDesc() ) );
+ if( !sortingMenu )
+ {
+ sortingMenu = new QMenu( qtr( "Sort by" ) );
+ sortingMapper = new QSignalMapper( this );
+ int i, j;
+ for( i = 1, j = 1; i < COLUMN_END; i <<= 1, j++ )
+ {
+ if( i == COLUMN_NUMBER ) continue;
+ QMenu *m = sortingMenu->addMenu( qfu( psz_column_title( i ) ) );
+ QAction *asc = m->addAction( qtr("Ascending") );
+ QAction *desc = m->addAction( qtr("Descending") );
+ sortingMapper->setMapping( asc, j );
+ sortingMapper->setMapping( desc, -j );
+ CONNECT( asc, triggered(), sortingMapper, map() );
+ CONNECT( desc, triggered(), sortingMapper, map() );
+ }
+ CONNECT( sortingMapper, mapped( int ), this, popupSort( int ) );
+ }
+ menu.addMenu( sortingMenu );
}
if( !menu.isEmpty() )
{
!strncasecmp( psz_access, "file", 4 ) ||
!strncasecmp( psz_access, "dire", 4 ) ))
{
- QFileInfo info( qfu( psz_path ) );
+ QFileInfo info( qfu( decode_URI( psz_path ) ) );
QDesktopServices::openUrl(
QUrl::fromLocalFile( info.absolutePath() ) );
}
PL_UNLOCK;
}
-void PLModel::popupSortAsc()
+void PLModel::popupSort( int column )
+{
+ sort( i_popup_parent,
+ column > 0 ? column - 1 : -column - 1,
+ column > 0 ? Qt::AscendingOrder : Qt::DescendingOrder );
+}
+
+/******************* Drag and Drop helper class ******************/
+
+PlMimeData::PlMimeData( )
+{ }
+
+PlMimeData::~PlMimeData()
+{
+ foreach( input_item_t *p_item, _inputItems )
+ vlc_gc_decref( p_item );
+}
+
+void PlMimeData::appendItem( input_item_t *p_item )
+{
+ vlc_gc_incref( p_item );
+ _inputItems.append( p_item );
+}
+
+QList<input_item_t*> PlMimeData::inputItems() const
{
- sort( i_popup_parent, i_popup_column, Qt::AscendingOrder );
+ return _inputItems;
}
-void PLModel::popupSortDesc()
+QStringList PlMimeData::formats () const
{
- sort( i_popup_parent, i_popup_column, Qt::DescendingOrder );
+ QStringList fmts;
+ fmts << "vlc/qt-input-items";
+ return fmts;
}