diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 392224eef0..5c6dd6787b 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -55,7 +55,6 @@ #include #include #include -#include #include #include #include @@ -1196,12 +1195,18 @@ TabWorkArea::TabWorkArea(QWidget * parent) QObject::connect(closeBufferButton, SIGNAL(clicked()), this, SLOT(closeCurrentBuffer())); setCornerWidget(closeBufferButton, Qt::TopRightCorner); + + // setup drag'n'drop + QTabBar* tb = new DragTabBar; + connect(tb, SIGNAL(tabMoveRequested(int, int)), + this, SLOT(moveTab(int, int))); + setTabBar(tb); // make us responsible for the context menu of the tabbar - tabBar()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(tabBar(), SIGNAL(customContextMenuRequested(const QPoint &)), + tb->setContextMenuPolicy(Qt::CustomContextMenu); + connect(tb, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &))); - + setUsesScrollButtons(true); } @@ -1376,7 +1381,7 @@ void TabWorkArea::updateTabText(GuiWorkArea * wa) void TabWorkArea::showContextMenu(const QPoint & pos) { // which tab? - clicked_tab_ = tabBar()->tabAt(pos); + clicked_tab_ = static_cast(tabBar())->tabAt(pos); if (clicked_tab_ != -1) { // show tab popup QMenu popup; @@ -1391,6 +1396,113 @@ void TabWorkArea::showContextMenu(const QPoint & pos) } +void TabWorkArea::moveTab(int fromIndex, int toIndex) +{ + QWidget * w = widget(fromIndex); + QIcon icon = tabIcon(fromIndex); + QString text = tabText(fromIndex); + + setCurrentIndex(fromIndex); + removeTab(fromIndex); + insertTab(toIndex, w, icon, text); + setCurrentIndex(toIndex); +} + + +DragTabBar::DragTabBar(QWidget* parent) + : QTabBar(parent) +{ + setAcceptDrops(true); +} + + +#if QT_VERSION < 0x040300 +int DragTabBar::tabAt(QPoint const & position) const +{ + const int max = count(); + for (int i = 0; i < max; ++i) { + if (tabRect(i).contains(position)) + return i; + } + return -1; +} +#endif + + +void DragTabBar::mousePressEvent(QMouseEvent * event) +{ + if (event->button() == Qt::LeftButton) + dragStartPos_ = event->pos(); + QTabBar::mousePressEvent(event); +} + + +void DragTabBar::mouseMoveEvent(QMouseEvent * event) +{ + // If the left button isn't pressed anymore then return + if (!(event->buttons() & Qt::LeftButton)) + return; + + // If the distance is too small then return + if ((event->pos() - dragStartPos_).manhattanLength() + < QApplication::startDragDistance()) + return; + + // did we hit something after all? + int tab = tabAt(dragStartPos_); + if (tab == -1) + return; + + // simulate button release to remove highlight from button + int i = currentIndex(); + QMouseEvent me(QEvent::MouseButtonRelease, dragStartPos_, + event->button(), event->buttons(), 0); + QTabBar::mouseReleaseEvent(&me); + setCurrentIndex(i); + + // initiate Drag + QDrag * drag = new QDrag(this); + QMimeData * mimeData = new QMimeData; + // a crude way to distinguish tab-reodering drops from other ones + mimeData->setData("action", "tab-reordering") ; + drag->setMimeData(mimeData); + +#if QT_VERSION >= 0x040300 + // FIXME: gives garbage for tab != 0. + // get tab pixmap as cursor + QRect r = tabRect(tab); + QPixmap pixmap(r.size()); + render(&pixmap, r.topLeft()); + drag->setPixmap(pixmap); +#endif + + drag->exec(); +} + + +void DragTabBar::dragEnterEvent(QDragEnterEvent * event) +{ + // Only accept if it's an tab-reordering request + QMimeData const * m = event->mimeData(); + QStringList formats = m->formats(); + if (formats.contains("action") + && m->data("action") == "tab-reordering") + event->acceptProposedAction(); +} + + +void DragTabBar::dropEvent(QDropEvent * event) +{ + int fromIndex = tabAt(dragStartPos_); + int toIndex = tabAt(event->pos()); + + // Tell interested objects that + if (fromIndex != toIndex) + tabMoveRequested(fromIndex, toIndex); + event->acceptProposedAction(); +} + + } // namespace frontend } // namespace lyx diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 034bef285b..e380561df5 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -262,8 +263,6 @@ Q_SIGNALS: void lastWorkAreaRemoved(); public Q_SLOTS: - /// - void on_currentTabChanged(int index); /// close current buffer, or the one given by \c clicked_tab_ void closeCurrentBuffer(); /// close current tab, or the one given by \c clicked_tab_ @@ -272,13 +271,51 @@ public Q_SLOTS: void updateTabText(GuiWorkArea *); private Q_SLOTS: + /// + void on_currentTabChanged(int index); /// void showContextMenu(const QPoint & pos); + /// + void moveTab(int fromIndex, int toIndex); private: int clicked_tab_; }; // TabWorkArea + +class DragTabBar : public QTabBar +{ + Q_OBJECT +public: + /// + DragTabBar(QWidget * parent=0); + +#if QT_VERSION < 0x040300 + /// + int tabAt(QPoint const & position) const; +#endif + +protected: + /// + void mousePressEvent(QMouseEvent * event); + /// + void mouseMoveEvent(QMouseEvent * event); + /// + void dragEnterEvent(QDragEnterEvent * event); + /// + void dropEvent(QDropEvent * event); + +private: + /// + QPoint dragStartPos_; + /// + int dragCurrentIndex_; + +Q_SIGNALS: + /// + void tabMoveRequested(int fromIndex, int toIndex); +}; + } // namespace frontend } // namespace lyx