diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 88725ce40..103d3102a 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -492,11 +492,31 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro // Get the list of rows that were moved QList source_rows; + Playlist* source_playlist = NULL; + QDataStream stream(data->data(kRowsMimetype)); + stream >> source_playlist; stream >> source_rows; qStableSort(source_rows); // Make sure we take them in order - undo_stack_->push(new PlaylistUndoCommands::MoveItems(this, source_rows, row)); + if (source_playlist == this) { + // Dragged from this playlist - rearrange the items + undo_stack_->push(new PlaylistUndoCommands::MoveItems(this, source_rows, row)); + } else { + // Drag from a different playlist + PlaylistItemList items; + foreach (int row, source_rows) + items << source_playlist->item_at(row); + undo_stack_->push(new PlaylistUndoCommands::InsertItems(this, items, row)); + + // Remove the items from the source playlist if it was a move event + if (action == Qt::MoveAction) { + foreach (int row, source_rows) { + source_playlist->undo_stack()->push( + new PlaylistUndoCommands::RemoveItems(source_playlist, row, 1)); + } + } + } } else if (data->hasUrls()) { // URL list dragged from the file list or some other app InsertUrls(data->urls(), false, row); @@ -708,6 +728,7 @@ QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const { QBuffer buf; buf.open(QIODevice::WriteOnly); QDataStream stream(&buf); + stream << this; stream << rows; buf.close(); @@ -1099,3 +1120,13 @@ void Playlist::QueueLayoutChanged() { emit dataChanged(index, index); } } + +QDataStream& operator <<(QDataStream& s, const Playlist* p) { + s.writeRawData(reinterpret_cast(&p), sizeof(p)); + return s; +} + +QDataStream& operator >>(QDataStream& s, Playlist*& p) { + s.readRawData(reinterpret_cast(&p), sizeof(p)); + return s; +} diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index fe55c8fc9..c535497ad 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -240,4 +240,7 @@ class Playlist : public QAbstractListModel { QUndoStack* undo_stack_; }; +QDataStream& operator <<(QDataStream&, const Playlist*); +QDataStream& operator >>(QDataStream&, Playlist*&); + #endif // PLAYLIST_H diff --git a/src/playlist/playlistcontainer.cpp b/src/playlist/playlistcontainer.cpp index a5abbed2b..2da98c6a1 100644 --- a/src/playlist/playlistcontainer.cpp +++ b/src/playlist/playlistcontainer.cpp @@ -110,6 +110,7 @@ void PlaylistContainer::ClearFilter() { void PlaylistContainer::SetManager(PlaylistManager *manager) { manager_ = manager; + ui_->tab_bar->SetManager(manager); connect(ui_->tab_bar, SIGNAL(CurrentIdChanged(int)), manager, SLOT(SetCurrentPlaylist(int))); diff --git a/src/playlist/playlisttabbar.cpp b/src/playlist/playlisttabbar.cpp index 82de03adc..0d3052160 100644 --- a/src/playlist/playlisttabbar.cpp +++ b/src/playlist/playlisttabbar.cpp @@ -14,19 +14,27 @@ along with Clementine. If not, see . */ +#include "playlist.h" +#include "playlistmanager.h" #include "playlisttabbar.h" +#include "songmimedata.h" +#include "radio/radiomimedata.h" #include "ui/iconloader.h" #include #include #include +#include PlaylistTabBar::PlaylistTabBar(QWidget *parent) : QTabBar(parent), + manager_(NULL), menu_(new QMenu(this)), menu_index_(-1), suppress_current_changed_(false) { + setAcceptDrops(true); + remove_ = menu_->addAction(IconLoader::Load("list-remove"), tr("Remove playlist"), this, SLOT(Remove())); rename_ = menu_->addAction(IconLoader::Load("edit-rename"), tr("Rename playlist..."), this, SLOT(Rename())); save_ = menu_->addAction(IconLoader::Load("document-save"), tr("Save playlist..."), this, SLOT(Save())); @@ -44,6 +52,10 @@ void PlaylistTabBar::SetActions( new_ = new_playlist; } +void PlaylistTabBar::SetManager(PlaylistManager *manager) { + manager_ = manager; +} + void PlaylistTabBar::contextMenuEvent(QContextMenuEvent* e) { menu_index_ = tabAt(e->pos()); rename_->setEnabled(menu_index_ != -1); @@ -156,3 +168,52 @@ void PlaylistTabBar::TabMoved() { } emit PlaylistOrderChanged(ids); } + +void PlaylistTabBar::dragEnterEvent(QDragEnterEvent* e) { + if (e->mimeData()->hasUrls() || + e->mimeData()->hasFormat(Playlist::kRowsMimetype) || + qobject_cast(e->mimeData()) || + qobject_cast(e->mimeData())) { + e->acceptProposedAction(); + } +} + +void PlaylistTabBar::dragMoveEvent(QDragMoveEvent* e) { + drag_hover_tab_ = tabAt(e->pos()); + + if (drag_hover_tab_ == -1) { + e->setDropAction(Qt::IgnoreAction); + e->ignore(); + drag_hover_timer_.stop(); + } else { + e->setDropAction(Qt::CopyAction); + e->accept(tabRect(drag_hover_tab_)); + + if (!drag_hover_timer_.isActive()) + drag_hover_timer_.start(kDragHoverTimeout, this); + } +} + +void PlaylistTabBar::dragLeaveEvent(QDragLeaveEvent*) { + drag_hover_timer_.stop(); +} + +void PlaylistTabBar::timerEvent(QTimerEvent* e) { + QTabBar::timerEvent(e); + + if (e->timerId() == drag_hover_timer_.timerId()) { + drag_hover_timer_.stop(); + if (drag_hover_tab_ != -1) + setCurrentIndex(drag_hover_tab_); + } +} + +void PlaylistTabBar::dropEvent(QDropEvent* e) { + if (drag_hover_tab_ == -1) { + e->ignore(); + return; + } + + setCurrentIndex(drag_hover_tab_); + manager_->current()->dropMimeData(e->mimeData(), e->proposedAction(), -1, 0, QModelIndex()); +} diff --git a/src/playlist/playlisttabbar.h b/src/playlist/playlisttabbar.h index 3332e0931..fb861a0e7 100644 --- a/src/playlist/playlisttabbar.h +++ b/src/playlist/playlisttabbar.h @@ -17,8 +17,11 @@ #ifndef PLAYLISTTABBAR_H #define PLAYLISTTABBAR_H +#include #include +class PlaylistManager; + class QMenu; class PlaylistTabBar : public QTabBar { @@ -27,7 +30,10 @@ class PlaylistTabBar : public QTabBar { public: PlaylistTabBar(QWidget *parent = 0); + static const int kDragHoverTimeout = 500; + void SetActions(QAction* new_playlist, QAction* load_playlist); + void SetManager(PlaylistManager* manager); // We use IDs to refer to tabs so the tabs can be moved around (and their // indexes change). @@ -49,6 +55,16 @@ signals: void Save(int id); void PlaylistOrderChanged(const QList& ids); +protected: + void contextMenuEvent(QContextMenuEvent* e); + void mouseReleaseEvent(QMouseEvent* e); + void mouseDoubleClickEvent(QMouseEvent* e); + void dragEnterEvent(QDragEnterEvent* e); + void dragMoveEvent(QDragMoveEvent* e); + void dragLeaveEvent(QDragLeaveEvent* e); + void dropEvent(QDropEvent* e); + void timerEvent(QTimerEvent *); + private slots: void CurrentIndexChanged(int index); void Rename(); @@ -56,12 +72,9 @@ private slots: void TabMoved(); void Save(); -protected: - void contextMenuEvent(QContextMenuEvent* e); - void mouseReleaseEvent(QMouseEvent* e); - void mouseDoubleClickEvent(QMouseEvent* e); - private: + PlaylistManager* manager_; + QMenu* menu_; int menu_index_; QAction* new_; @@ -69,6 +82,9 @@ private: QAction* remove_; QAction* save_; + QBasicTimer drag_hover_timer_; + int drag_hover_tab_; + bool suppress_current_changed_; };