📄 playlist_model.cpp
字号:
/***************************************************************************** * playlist_model.cpp : Manage playlist model **************************************************************************** * Copyright (C) 2006-2007 the VideoLAN team * $Id: f09a4a7abe53e0983c9722b97bd6fe5b4b523edc $ * * Authors: Clément Stenac <zorglub@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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "qt4.hpp"#include "dialogs_provider.hpp"#include "components/playlist/playlist_model.hpp"#include "dialogs/mediainfo.hpp"#include <vlc_intf_strings.h>#include "pixmaps/types/type_unknown.xpm"#include <assert.h>#include <QIcon>#include <QFont>#include <QMenu>#include <QApplication>#include <QSettings>#include "sorting.h"QIcon PLModel::icons[ITEM_TYPE_NUMBER];static int PlaylistChanged( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * );static int PlaylistNext( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * );static int ItemChanged( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * );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 *************************************************************************//* This model is called two times, for the selector and the standard panel*/PLModel::PLModel( playlist_t *_p_playlist, /* THEPL */ intf_thread_t *_p_intf, /* main Qt p_intf */ 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; i_cached_input_id = -1; i_popup_item = i_popup_parent = -1; rootItem = NULL; /* PLItem rootItem, will be set in rebuild( ) */ /* Icons initialization */#define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( QPixmap( x ) ) ADD_ICON( UNKNOWN , type_unknown_xpm ); ADD_ICON( FILE, ":/type_file" ); ADD_ICON( DIRECTORY, ":/type_directory" ); ADD_ICON( DISC, ":/disc" ); ADD_ICON( CDDA, ":/cdda" ); ADD_ICON( CARD, ":/capture-card" ); ADD_ICON( NET, ":/type_net" ); ADD_ICON( PLAYLIST, ":/type_playlist" ); ADD_ICON( NODE, ":/type_node" );#undef ADD_ICON rebuild( p_root );}PLModel::~PLModel(){ getSettings()->setValue( "qt-pl-showflags", rootItem->i_showflags ); delCallbacks(); delete rootItem;}Qt::DropActions PLModel::supportedDropActions() const{ return Qt::CopyAction; /* Why not Qt::MoveAction */}Qt::ItemFlags PLModel::flags( const QModelIndex &index ) const{ Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index ); if( index.isValid() ) return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; else return Qt::ItemIsDropEnabled | defaultFlags;}/* A list of model indexes are a playlist */QStringList PLModel::mimeTypes() const{ QStringList types; types << "vlc/playlist-item-id"; return types;}QMimeData *PLModel::mimeData( const QModelIndexList &indexes ) const{ QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream( &encodedData, QIODevice::WriteOnly ); foreach( QModelIndex index, indexes ) { if( index.isValid() && index.column() == 0 ) stream << itemId( index ); } mimeData->setData( "vlc/playlist-item-id", encodedData ); return mimeData;}/* Drop operation */bool PLModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &target ){ if( data->hasFormat( "vlc/playlist-item-id" ) ) { if( action == Qt::IgnoreAction ) return true; if( !target.isValid() ) /* We don't want to move on an invalid position */ return true; PLItem *targetItem = static_cast<PLItem*>( target.internalPointer() ); QByteArray encodedData = data->data( "vlc/playlist-item-id" ); QDataStream stream( &encodedData, QIODevice::ReadOnly ); PLItem *newParentItem; while( !stream.atEnd() ) { int i; int srcId; stream >> srcId; PL_LOCK; playlist_item_t *p_target = playlist_ItemGetById( p_playlist, targetItem->i_id, pl_Locked ); playlist_item_t *p_src = playlist_ItemGetById( p_playlist, srcId, pl_Locked ); if( !p_target || !p_src ) { PL_UNLOCK; return false; } if( p_target->i_children == -1 ) /* A leaf */ { PLItem *parentItem = targetItem->parent(); assert( parentItem ); playlist_item_t *p_parent = playlist_ItemGetById( p_playlist, parentItem->i_id, pl_Locked ); if( !p_parent ) { PL_UNLOCK; return false; } for( i = 0 ; i< p_parent->i_children ; i++ ) if( p_parent->pp_children[i] == p_target ) break; // Move the item to the element after i playlist_TreeMove( p_playlist, p_src, p_parent, i + 1 ); newParentItem = parentItem; } else { /* \todo: if we drop on a top-level node, use copy instead ? */ playlist_TreeMove( p_playlist, p_src, p_target, 0 ); i = 0; newParentItem = targetItem; } PL_UNLOCK; } /*TODO: That's not a good idea to rebuild the playlist */ rebuild(); } return true;}/* remove item with its id */void PLModel::removeItem( int i_id ){ PLItem *item = FindById( rootItem, i_id ); if( item ) item->remove( item );}/* callbacks and slots */void PLModel::addCallbacks(){ /* Some global changes happened -> Rebuild all */ var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this ); /* We went to the next item */ var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this ); /* One item has been updated */ var_AddCallback( p_playlist, "item-change", ItemChanged, this ); var_AddCallback( p_playlist, "item-append", ItemAppended, this ); var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );}void PLModel::delCallbacks(){ var_DelCallback( p_playlist, "item-change", ItemChanged, this ); var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this ); var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this ); var_DelCallback( p_playlist, "item-append", ItemAppended, this ); var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );}void PLModel::activateItem( const QModelIndex &index ){ assert( index.isValid() ); PLItem *item = static_cast<PLItem*>(index.internalPointer()); assert( item ); PL_LOCK; playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id, pl_Locked ); activateItem( p_item ); PL_UNLOCK;}/* Must be entered with lock */void PLModel::activateItem( playlist_item_t *p_item ){ if( !p_item ) return; playlist_item_t *p_parent = p_item; while( p_parent ) { if( p_parent->i_id == rootItem->i_id ) break; p_parent = p_parent->p_parent; } if( p_parent ) playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Locked, p_parent, p_item );}/****************** Base model mandatory implementations *****************/QVariant PLModel::data( const QModelIndex &index, int role ) const{ if( !index.isValid() ) return QVariant(); PLItem *item = static_cast<PLItem*>(index.internalPointer()); if( role == Qt::DisplayRole ) { return QVariant( item->columnString( index.column() ) ); } else if( role == Qt::DecorationRole && index.column() == 0 ) { /* Use to segfault here because i_type wasn't always initialized */ if( item->i_type >= 0 ) return QVariant( PLModel::icons[item->i_type] ); } else if( role == Qt::FontRole ) { if( item->b_current == true ) { QFont f; f.setBold( true ); return QVariant( f ); } } return QVariant();}bool PLModel::isCurrent( const QModelIndex &index ){ assert( index.isValid() ); return static_cast<PLItem*>(index.internalPointer())->b_current;}int PLModel::itemId( const QModelIndex &index ) const{ assert( index.isValid() ); return static_cast<PLItem*>(index.internalPointer())->i_id;}QVariant PLModel::headerData( int section, Qt::Orientation orientation, int role ) const{ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return QVariant( rootItem->columnString( section ) ); return QVariant();}QModelIndex PLModel::index( int row, int column, const QModelIndex &parent ) const{ PLItem *parentItem; if( !parent.isValid() ) parentItem = rootItem; else parentItem = static_cast<PLItem*>(parent.internalPointer()); PLItem *childItem = parentItem->child( row ); if( childItem ) return createIndex( row, column, childItem ); else return QModelIndex();}/* Return the index of a given item */QModelIndex PLModel::index( PLItem *item, int column ) const{ if( !item ) return QModelIndex(); const PLItem *parent = item->parent(); if( parent ) return createIndex( parent->children.lastIndexOf( item ),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -