Commit ac471f21 authored by Clément Stenac's avatar Clément Stenac

Initial drag and drop support for Qt

parent 85f6dac5
......@@ -38,6 +38,10 @@ PLSelector::PLSelector( QWidget *p, intf_thread_t *_p_intf,
view->header()->hide();
view->setModel( model );
view->setDragEnabled(true);
view->setAcceptDrops(true);
view->setDropIndicatorShown(true);
CONNECT( view, activated( const QModelIndex& ),
this, setSource( const QModelIndex& ) );
CONNECT( view, clicked( const QModelIndex& ),
......
......@@ -56,7 +56,11 @@ StandardPLPanel::StandardPLPanel( BasePlaylistWidget *_parent,
view->header()->resizeSection( 2, 60 );
view->header()->setSortIndicatorShown( true );
view->header()->setClickable( true );
view->setSelectionMode( QAbstractItemView::ExtendedSelection );
view->setDragEnabled(true);
view->setAcceptDrops(true);
view->setDropIndicatorShown(true);
CONNECT( view, activated( const QModelIndex& ) ,
model,activateItem( const QModelIndex& ) );
......
......@@ -30,6 +30,7 @@
#include "dialogs_provider.hpp"
#include "menus.hpp"
#include <QUrl>
#include <QHBoxLayout>
#include <QSignalMapper>
#include <QMenu>
......@@ -75,3 +76,31 @@ void PlaylistDialog::dock()
QEvent *event = new QEvent( (QEvent::Type)(PLDockEvent_Type) );
QApplication::postEvent( p_intf->p_sys->p_mi, event );
}
void PlaylistDialog::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData();
foreach( QUrl url, mimeData->urls() ) {
QString s = url.toString();
if( s.length() > 0 ) {
playlist_PlaylistAdd( THEPL, qtu(s), NULL,
PLAYLIST_APPEND, PLAYLIST_END );
}
}
event->acceptProposedAction();
}
void PlaylistDialog::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void PlaylistDialog::dragMoveEvent(QDragMoveEvent *event)
{
event->acceptProposedAction();
}
void PlaylistDialog::dragLeaveEvent(QDragLeaveEvent *event)
{
event->accept();
}
......@@ -49,6 +49,12 @@ private:
void createPlMenuBar( QMenuBar *bar, intf_thread_t *p_intf );
PlaylistDialog( intf_thread_t * );
void dropEvent( QDropEvent *);
void dragEnterEvent( QDragEnterEvent * );
void dragMoveEvent( QDragMoveEvent * );
void dragLeaveEvent( QDragLeaveEvent * );
static PlaylistDialog *instance;
PLSelector *selector;
......
......@@ -36,6 +36,7 @@
#include <QPushButton>
#include <QStatusBar>
#include <QKeyEvent>
#include <QUrl>
#include <assert.h>
#include <vlc_keys.h>
......@@ -84,6 +85,8 @@ MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
settings = new QSettings( "VideoLAN", "VLC" );
settings->beginGroup( "MainWindow" );
setAcceptDrops(true);
need_components_update = false;
bgWidget = NULL; videoWidget = NULL; playlistWidget = NULL;
embeddedPlaylistWasActive = videoIsActive = false;
......@@ -137,6 +140,51 @@ MainInterface::MainInterface( intf_thread_t *_p_intf ) : QVLCMW( _p_intf )
p_intf->b_interaction = VLC_TRUE;
}
void MainInterface::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData();
/* D&D of a subtitles file, add it on the fly */
if( mimeData->urls().size() == 1 )
{
if( THEMIM->getIM()->hasInput() )
{
if( input_AddSubtitles( THEMIM->getInput(),
qtu( mimeData->urls()[0].toString() ),
VLC_TRUE ) )
{
event->acceptProposedAction();
return;
}
}
}
bool first = true;
foreach( QUrl url, mimeData->urls() ) {
QString s = url.toString();
if( s.length() > 0 ) {
playlist_PlaylistAdd( THEPL, qtu(s), NULL,
PLAYLIST_APPEND | (first ? PLAYLIST_GO:0),
PLAYLIST_END );
first = false;
}
}
event->acceptProposedAction();
}
void MainInterface::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void MainInterface::dragMoveEvent(QDragMoveEvent *event)
{
event->acceptProposedAction();
}
void MainInterface::dragLeaveEvent(QDragLeaveEvent *event)
{
event->accept();
}
MainInterface::~MainInterface()
{
settings->setValue( "playlist-embedded", playlistEmbeddedFlag );
......
......@@ -57,6 +57,10 @@ public:
int controlVideo( void *p_window, int i_query, va_list args );
protected:
void resizeEvent( QResizeEvent * );
void dropEvent( QDropEvent *);
void dragEnterEvent( QDragEnterEvent * );
void dragMoveEvent( QDragMoveEvent * );
void dragLeaveEvent( QDragLeaveEvent * );
void closeEvent( QCloseEvent *);
Ui::MainInterfaceUI ui;
friend class VolumeClickHandler;
......
......@@ -20,6 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#define PLI_NAME( p ) p ? p->p_input->psz_name : "null"
#include <assert.h>
#include <QIcon>
......@@ -98,7 +99,7 @@ void PLItem::insertChild( PLItem *item, int i_pos, bool signal )
assert( model );
if( signal )
model->beginInsertRows( model->index( this , 0 ), i_pos, i_pos );
children.append( item );
children.insert( i_pos, item );
if( signal )
model->endInsertRows();
}
......@@ -181,6 +182,115 @@ PLModel::~PLModel()
delete rootItem;
}
Qt::DropActions PLModel::supportedDropActions() const
{
return Qt::CopyAction;
}
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;
}
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;
}
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;
PLItem *targetItem;
if( target.isValid() )
targetItem = static_cast<PLItem*>( target.internalPointer() );
else
targetItem = rootItem;
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 );
playlist_item_t *p_src = playlist_ItemGetById( p_playlist, srcId );
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 );
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;
playlist_TreeMove( p_playlist, p_src, p_parent, i );
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;
}
/* Remove from source */
PLItem *srcItem = FindByInput( rootItem, p_src->p_input->i_id );
srcItem->remove( srcItem );
/* Display at new destination */
PLItem *newItem = new PLItem( p_src, newParentItem, this );
newParentItem->insertChild( newItem, i, true );
UpdateTreeItem( p_src, newItem, true );
if( p_src->i_children != -1 )
UpdateNodeChildren( newItem );
PL_UNLOCK;
}
}
return true;
}
void PLModel::addCallbacks()
{
/* Some global changes happened -> Rebuild all */
......@@ -229,7 +339,7 @@ void PLModel::activateItem( playlist_item_t *p_item )
/****************** Base model mandatory implementations *****************/
QVariant PLModel::data(const QModelIndex &index, int role) const
{
assert( index.isValid() );
if(!index.isValid() ) return QVariant();
PLItem *item = static_cast<PLItem*>(index.internalPointer());
if( role == Qt::DisplayRole )
{
......@@ -262,12 +372,6 @@ int PLModel::itemId( const QModelIndex &index ) const
return static_cast<PLItem*>(index.internalPointer())->i_id;
}
Qt::ItemFlags PLModel::flags(const QModelIndex &index) const
{
if( !index.isValid() ) return Qt::ItemIsEnabled;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant PLModel::headerData( int section, Qt::Orientation orientation,
int role) const
{
......@@ -449,7 +553,7 @@ void PLModel::customEvent( QEvent *event )
{
int type = event->type();
if( type != ItemUpdate_Type && type != ItemAppend_Type &&
type != ItemDelete_Type )
type != ItemDelete_Type && type != PLUpdate_Type )
return;
PLEvent *ple = static_cast<PLEvent *>(event);
......@@ -458,8 +562,10 @@ void PLModel::customEvent( QEvent *event )
ProcessInputItemUpdate( ple->i_id );
else if( type == ItemAppend_Type )
ProcessItemAppend( ple->p_add );
else
else if( type == ItemDelete_Type )
ProcessItemRemoval( ple->i_id );
else
rebuild();
}
/**** Events processing ****/
......@@ -669,6 +775,7 @@ void PLModel::sort( int column, Qt::SortOrder order )
case 0: i_mode = SORT_TITLE_NODES_FIRST;break;
case 1: i_mode = SORT_ARTIST;break;
case 2: i_mode = SORT_DURATION; break;
default: i_mode = SORT_TITLE_NODES_FIRST; break;
}
if( p_root )
playlist_RecursiveNodeSort( p_playlist, p_root, i_mode,
......@@ -756,7 +863,8 @@ static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t oval, vlc_value_t nval, void *param )
{
PLModel *p_model = (PLModel *) param;
// p_model->b_need_update = VLC_TRUE;
PLEvent *event = new PLEvent( PLUpdate_Type, 0 );
QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
return VLC_SUCCESS;
}
......
......@@ -27,6 +27,7 @@
#include <QModelIndex>
#include <QObject>
#include <QEvent>
#include <QMimeData>
#include <vlc/vlc.h>
#include <vlc/input.h>
......@@ -72,6 +73,7 @@ private:
static int ItemUpdate_Type = QEvent::User + 2;
static int ItemDelete_Type = QEvent::User + 3;
static int ItemAppend_Type = QEvent::User + 4;
static int PLUpdate_Type = QEvent::User + 5;
class PLEvent : public QEvent
{
......@@ -122,6 +124,13 @@ public:
void search( QString search );
void sort( int column, Qt::SortOrder order );
/* DnD handling */
Qt::DropActions supportedDropActions() const;
QMimeData* mimeData(const QModelIndexList &indexes) const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &target);
QStringList mimeTypes() const;
void sendArt( QString url );
private:
void addCallbacks();
......
......@@ -482,6 +482,7 @@ int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item,
/* Attach to new parent */
INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item );
p_item->p_parent = p_node;
return VLC_SUCCESS;
}
......
......@@ -430,6 +430,7 @@ playlist_item_t *playlist_GetNextLeaf( playlist_t *p_playlist,
{
vlc_bool_t b_ena_ok = VLC_TRUE, b_unplayed_ok = VLC_TRUE;
p_next = GetNextItem( p_playlist, p_root, p_next );
PL_DEBUG( "Got next item %s, testing suitability", PLI_NAME(p_next) );
if( !p_next || p_next == p_root )
break;
if( p_next->i_children == -1 )
......@@ -520,7 +521,8 @@ playlist_item_t *GetNextItem( playlist_t *p_playlist,
p_parent = p_item->p_parent;
else
p_parent = p_root;
PL_DEBUG( "Parent %s has %i children", PLI_NAME(p_parent),
p_parent->i_children );
for( i= 0 ; i < p_parent->i_children ; i++ )
{
if( p_item == NULL || p_parent->pp_children[i] == p_item )
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment