]> git.sesse.net Git - vlc/commitdiff
Initial drag and drop support for Qt
authorClément Stenac <zorglub@videolan.org>
Sat, 14 Oct 2006 16:44:55 +0000 (16:44 +0000)
committerClément Stenac <zorglub@videolan.org>
Sat, 14 Oct 2006 16:44:55 +0000 (16:44 +0000)
modules/gui/qt4/components/playlist/selector.cpp
modules/gui/qt4/components/playlist/standardpanel.cpp
modules/gui/qt4/dialogs/playlist.cpp
modules/gui/qt4/dialogs/playlist.hpp
modules/gui/qt4/main_interface.cpp
modules/gui/qt4/main_interface.hpp
modules/gui/qt4/playlist_model.cpp
modules/gui/qt4/playlist_model.hpp
src/playlist/item.c
src/playlist/tree.c

index 347e7c7b4794d472187f1e16f47a73e45278d950..ea0f7d21e99af821b1ea66829987c4e119ebe841 100644 (file)
@@ -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& ),
index 74f6b4893304e5b79e24d6a393d52d38d63fdfaf..57b4b69311de286c73b554c6a1eb0cde92f2c001 100644 (file)
@@ -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& ) );
index 0cbc2bea7d383799a484b6788021cc21be16c907..47457438aa1180ec2037aa8f54cd1d1359b9384d 100644 (file)
@@ -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();
+}
+
+
index c2ef45a2979f2e7b70787a459993b6888bb632bb..ab84f503ddafaaf76b86efabd89fdc80aa76fd5f 100644 (file)
@@ -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;
index 1688a229612d0488128f373a358363d9a225bdb0..341170aca25b2eb7cf40715d9c9b10f5067c5c49 100644 (file)
@@ -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 );
index 2905c14e1ad202b420cdd1e526d5af3a59731ac4..ed4b8d07f0ca6e7555134272652047147a2009ec 100644 (file)
@@ -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;
index 2cfacba81f1606d5e3603a7f82f9702402b0c479..be360f5bc2b0468b165f93631f5bc4b6bc36b59e 100644 (file)
@@ -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;
 }
 
index d7cbf652cc9c00754f242209ffc72fccc9a65f83..68a7340e3a4eae68c86f968f717e396033ba97bc 100644 (file)
@@ -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();
index ee600bf5ddb8ba171cf778fa1c7441d9739ad963..96f4b1481b11d3fb363ad9de29c062ee8acf9b6c 100644 (file)
@@ -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;
 }
index 95efa4ed55dca5f0dc0e2d99ac3d36fa9aba5b6b..39ef9e1e71aac1cb0209d083e060f62fb09bd257 100644 (file)
@@ -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 )