Commit 615c9fdd authored by Waqar Ahmed's avatar Waqar Ahmed Committed by Christoph Cullmann
Browse files

Allow DND of tabs among viewspaces

BUG: 426768
parent 16019ddf
......@@ -92,6 +92,7 @@ target_sources(
kateviewmanager.cpp
kateviewspace.cpp
katewaiter.cpp
tabmimedata.cpp
katecommandbar.cpp
commandmodel.cpp
......
......@@ -8,12 +8,17 @@
#include "katetabbar.h"
#include "kateapp.h"
#include "tabmimedata.h"
#include <QApplication>
#include <QDrag>
#include <QIcon>
#include <QMimeData>
#include <QPainter>
#include <QPixmap>
#include <QResizeEvent>
#include <QStyleOptionTab>
#include <QStylePainter>
#include <QWheelEvent>
#include <KAcceleratorManager>
......@@ -160,6 +165,13 @@ void KateTabBar::mousePressEvent(QMouseEvent *event)
if (!isActive()) {
Q_EMIT activateViewSpaceRequested();
}
if (event->button() == Qt::LeftButton && tabAt(event->pos()) != -1) {
dragStartPos = event->pos();
} else {
dragStartPos = {};
}
QTabBar::mousePressEvent(event);
// handle close for middle mouse button
......@@ -171,6 +183,59 @@ void KateTabBar::mousePressEvent(QMouseEvent *event)
}
}
void KateTabBar::mouseMoveEvent(QMouseEvent *event)
{
if (dragStartPos.isNull()) {
QTabBar::mouseMoveEvent(event);
return;
}
if ((event->pos() - dragStartPos).manhattanLength() < QApplication::startDragDistance()) {
QTabBar::mouseMoveEvent(event);
return;
}
if (rect().contains(event->pos())) {
return QTabBar::mouseMoveEvent(event);
}
QDrag *drag = new QDrag(this);
int tab = tabAt(dragStartPos);
QRect rect = tabRect(tab);
QPixmap p(rect.size());
p.setDevicePixelRatio(this->devicePixelRatioF());
p.fill(Qt::transparent);
// For some reason initStyleOption with tabIdx directly
// wasn't working, so manually set some stuff
QStyleOptionTabV4 opt;
initStyleOption(&opt, 0);
opt.text = tabText(tab);
opt.state = QStyle::State_Selected | QStyle::State_Raised;
opt.tabIndex = tab;
opt.features = QStyleOptionTab::TabFeature::HasFrame;
QStylePainter paint(&p, this);
paint.drawControl(QStyle::CE_TabBarTab, opt);
paint.end();
auto parentViewSpace = qobject_cast<KateViewSpace *>(parentWidget());
Q_ASSERT(parentViewSpace);
auto mime = new TabMimeData(parentViewSpace, tabDocument(tab), tab);
drag->setMimeData(mime);
drag->setPixmap(p);
QPoint hp;
hp.setX(dragStartPos.x() - rect.x());
drag->setHotSpot(hp);
dragStartPos = {};
drag->exec();
}
void KateTabBar::contextMenuEvent(QContextMenuEvent *ev)
{
int id = tabAt(ev->pos());
......
......@@ -122,6 +122,8 @@ protected:
//! Override to request making the tab bar active.
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *) override;
//! Request context menu
void contextMenuEvent(QContextMenuEvent *ev) override;
......@@ -167,6 +169,8 @@ private:
* is a bit strange tab replacement a few times
*/
std::unordered_map<KTextEditor::Document *, std::pair<quint64, bool>> m_docToLruCounterAndHasTab;
QPoint dragStartPos;
};
#endif // KATE_TAB_BAR_H
......@@ -783,6 +783,15 @@ void KateViewManager::closeView(KTextEditor::View *view)
}
}
void KateViewManager::moveViewToViewSpace(KateViewSpace *dest, KateViewSpace *src, KTextEditor::Document *doc)
{
// We always have an active view at this point which is what we are moving
Q_ASSERT(activeView());
auto view = src->takeView(doc);
dest->addView(view);
setActiveSpace(dest);
}
void KateViewManager::splitViewSpace(KateViewSpace *vs, // = 0
Qt::Orientation o) // = Qt::Horizontal
{
......
......@@ -75,6 +75,8 @@ public:
void closeView(KTextEditor::View *view);
KateMainWindow *mainWindow();
void moveViewToViewSpace(KateViewSpace *dest, KateViewSpace *src, KTextEditor::Document *doc);
private Q_SLOTS:
void activateView(KTextEditor::View *view);
void activateSpace(KTextEditor::View *v);
......
......@@ -15,6 +15,7 @@
#include "katesessionmanager.h"
#include "kateupdatedisabler.h"
#include "kateviewmanager.h"
#include "tabmimedata.h"
#include <KActionCollection>
#include <KAcceleratorManager>
......@@ -26,6 +27,7 @@
#include <QHelpEvent>
#include <QMenu>
#include <QMessageBox>
#include <QRubberBand>
#include <QStackedWidget>
#include <QToolButton>
#include <QToolTip>
......@@ -129,11 +131,16 @@ KateViewSpace::KateViewSpace(KateViewManager *viewManager, QWidget *parent, cons
connect(this, &KateViewSpace::viewSpaceEmptied, m_viewManager, &KateViewManager::onViewSpaceEmptied);
// we accept drops (tabs from other viewspaces / windows)
setAcceptDrops(true);
// init the bars...
statusBarToggled();
tabBarToggled();
}
KateViewSpace::~KateViewSpace() = default;
bool KateViewSpace::eventFilter(QObject *obj, QEvent *event)
{
QToolButton *button = qobject_cast<QToolButton *>(obj);
......@@ -397,6 +404,7 @@ void KateViewSpace::registerDocument(KTextEditor::Document *doc)
connect(m_tabBar, &KateTabBar::currentChanged, this, &KateViewSpace::changeView);
}
void KateViewSpace::closeDocument(KTextEditor::Document *doc)
{
// If this is the only view of the document,
......@@ -423,6 +431,64 @@ void KateViewSpace::closeDocument(KTextEditor::Document *doc)
}
}
void KateViewSpace::dragEnterEvent(QDragEnterEvent *e)
{
auto mimeData = qobject_cast<const TabMimeData *>(e->mimeData());
if (mimeData && this != mimeData->sourceVS && !hasDocument(mimeData->doc)) {
m_dropIndicator.reset(new QRubberBand(QRubberBand::Rectangle, this));
m_dropIndicator->setGeometry(rect());
m_dropIndicator->show();
e->acceptProposedAction();
return;
}
QWidget::dragEnterEvent(e);
}
void KateViewSpace::dragLeaveEvent(QDragLeaveEvent *e)
{
m_dropIndicator.reset();
QWidget::dragLeaveEvent(e);
}
void KateViewSpace::dropEvent(QDropEvent *e)
{
if (auto mimeData = qobject_cast<const TabMimeData *>(e->mimeData())) {
m_viewManager->moveViewToViewSpace(this, mimeData->sourceVS, mimeData->doc);
m_dropIndicator.reset();
e->accept();
return;
}
QWidget::dropEvent(e);
}
bool KateViewSpace::hasDocument(KTextEditor::Document *doc) const
{
return m_registeredDocuments.contains(doc) && (m_docToView.find(doc) != m_docToView.end());
}
KTextEditor::View *KateViewSpace::takeView(KTextEditor::Document *doc)
{
auto it = m_docToView.find(doc);
if (it == m_docToView.end()) {
return nullptr;
}
auto *view = it->second;
stack->removeWidget(view);
m_tabBar->removeDocument(doc);
documentDestroyed(doc);
return view;
}
void KateViewSpace::addView(KTextEditor::View *v)
{
registerDocument(v->document());
m_docToView[v->document()] = v;
// We must not already have this widget
Q_ASSERT(stack->indexOf(v) == -1);
stack->addWidget(v);
showView(v);
}
void KateViewSpace::documentDestroyed(QObject *doc)
{
/**
......
......@@ -31,6 +31,8 @@ class KateViewSpace : public QWidget
public:
explicit KateViewSpace(KateViewManager *, QWidget *parent = nullptr, const char *name = nullptr);
~KateViewSpace();
/**
* Returns \e true, if this view space is currently the active view space.
*/
......@@ -82,6 +84,24 @@ public:
*/
void closeDocument(KTextEditor::Document *doc);
/*
* Does this viewspace contain @p doc
*/
bool hasDocument(KTextEditor::Document *doc) const;
/**
* Removes @p doc from this space and returns the associated
* view
* Used for dnd
*/
KTextEditor::View *takeView(KTextEditor::Document *doc);
/**
* Adds @p view to this space
* Used for dnd to add a view from another viewspace
*/
void addView(KTextEditor::View *v);
/**
* Event filter to catch events from view space tool buttons.
*/
......@@ -146,6 +166,12 @@ public:
void addPositionToHistory(const QUrl &url, KTextEditor::Cursor, bool calledExternally = false);
// END Location History Stuff
protected:
// DND
void dragEnterEvent(QDragEnterEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override;
Q_SIGNALS:
void viewSpaceEmptied(KateViewSpace *vs);
......@@ -256,6 +282,9 @@ private:
// go forward in history button (only visible when the tab bar is visible)
QToolButton *m_historyForward;
// rubber band to indicate drag and drop
std::unique_ptr<class QRubberBand> m_dropIndicator;
friend class LocationHistoryTest;
};
......
#include "tabmimedata.h"
TabMimeData::TabMimeData(KateViewSpace *vs, KTextEditor::Document *d, int sourceTabIdx)
: QMimeData()
, sourceVS(vs)
, doc(d)
, tabIdx(sourceTabIdx)
{
}
#ifndef KATE_TAB_MIME_DATA_H
#define KATE_TAB_MIME_DATA_H
#include <QMimeData>
#include "kateviewspace.h"
namespace KTextEditor
{
class Document;
}
class TabMimeData : public QMimeData
{
Q_OBJECT
public:
TabMimeData(KateViewSpace *vs, KTextEditor::Document *d, int sourceTabIdx);
KateViewSpace *const sourceVS;
KTextEditor::Document *const doc;
const int tabIdx;
};
#endif
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