1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 18:56:34 +01:00

TabBar: Add support for drag&drop tabs to other windows

Also it is possible to detach tab by dragging it outside of tabbar.

BUG: 386672
This commit is contained in:
David Rosca 2018-01-01 14:59:15 +01:00
parent fe396e64ff
commit 21ca9adf6b
3 changed files with 84 additions and 31 deletions

View File

@ -1,6 +1,6 @@
/* ============================================================ /* ============================================================
* Falkon - Qt web browser * Falkon - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com> * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,7 +28,6 @@
#include "tabcontextmenu.h" #include "tabcontextmenu.h"
#include "searchenginesmanager.h" #include "searchenginesmanager.h"
#include <QMenu>
#include <QMimeData> #include <QMimeData>
#include <QMouseEvent> #include <QMouseEvent>
#include <QStyleOption> #include <QStyleOption>
@ -38,6 +37,9 @@
#include <QLabel> #include <QLabel>
#include <QScrollArea> #include <QScrollArea>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QDrag>
#define MIMETYPE QSL("application/qupzilla.tabbar.tab")
TabBar::TabBar(BrowserWindow* window, TabWidget* tabWidget) TabBar::TabBar(BrowserWindow* window, TabWidget* tabWidget)
: ComboTabBar() : ComboTabBar()
@ -454,9 +456,8 @@ void TabBar::mousePressEvent(QMouseEvent* event)
} }
if (event->buttons() == Qt::LeftButton && !emptyArea(event->pos())) { if (event->buttons() == Qt::LeftButton && !emptyArea(event->pos())) {
m_dragStartPosition = mapFromGlobal(event->globalPos()); m_dragStartPosition = event->pos();
} } else {
else {
m_dragStartPosition = QPoint(); m_dragStartPosition = QPoint();
} }
@ -469,12 +470,38 @@ void TabBar::mouseMoveEvent(QMouseEvent* event)
return; return;
} }
if (!m_dragStartPosition.isNull() && m_tabWidget->buttonAddTab()->isVisible()) { if (!m_dragStartPosition.isNull()) {
if (m_tabWidget->buttonAddTab()->isVisible()) {
int manhattanLength = (event->pos() - m_dragStartPosition).manhattanLength(); int manhattanLength = (event->pos() - m_dragStartPosition).manhattanLength();
if (manhattanLength > QApplication::startDragDistance()) { if (manhattanLength > QApplication::startDragDistance()) {
m_tabWidget->buttonAddTab()->hide(); m_tabWidget->buttonAddTab()->hide();
} }
} }
int offset = 0;
const int eventY = event->pos().y();
if (eventY < 0) {
offset = qAbs(eventY);
} else if (eventY > height()) {
offset = eventY - height();
}
if (count() > 1 && offset > QApplication::startDragDistance()) {
const QPoint global = mapToGlobal(m_dragStartPosition);
QWidget *w = QApplication::widgetAt(global);
if (w) {
QMouseEvent mouse(QEvent::MouseButtonRelease, w->mapFromGlobal(global), Qt::LeftButton, Qt::LeftButton, event->modifiers());
QApplication::sendEvent(w, &mouse);
}
QDrag *drag = new QDrag(this);
QMimeData *mime = new QMimeData;
mime->setData(MIMETYPE, QByteArray());
drag->setMimeData(mime);
drag->setPixmap(tabPixmap(currentIndex()));
if (drag->exec() == Qt::IgnoreAction) {
m_tabWidget->detachTab(currentIndex());
}
return;
}
}
ComboTabBar::mouseMoveEvent(event); ComboTabBar::mouseMoveEvent(event);
} }
@ -528,7 +555,7 @@ enum TabDropAction {
AppendTab AppendTab
}; };
static TabDropAction tabDropAction(const QPoint &pos, const QRect &tabRect) static TabDropAction tabDropAction(const QPoint &pos, const QRect &tabRect, bool allowSelect)
{ {
if (!tabRect.contains(pos)) { if (!tabRect.contains(pos)) {
return NoAction; return NoAction;
@ -538,7 +565,7 @@ static TabDropAction tabDropAction(const QPoint &pos, const QRect &tabRect)
const QSize csize = QSize(tabRect.width() * 0.7, tabRect.height() * 0.7); const QSize csize = QSize(tabRect.width() * 0.7, tabRect.height() * 0.7);
const QRect center(c.x() - csize.width() / 2, c.y() - csize.height() / 2, csize.width(), csize.height()); const QRect center(c.x() - csize.width() / 2, c.y() - csize.height() / 2, csize.width(), csize.height());
if (center.contains(pos)) { if (allowSelect && center.contains(pos)) {
return SelectTab; return SelectTab;
} else if (pos.x() < c.x()) { } else if (pos.x() < c.x()) {
return PrependTab; return PrependTab;
@ -551,7 +578,7 @@ void TabBar::dragEnterEvent(QDragEnterEvent* event)
{ {
const QMimeData* mime = event->mimeData(); const QMimeData* mime = event->mimeData();
if (mime->hasText() || mime->hasUrls()) { if (mime->hasText() || mime->hasUrls() || mime->hasFormat(MIMETYPE)) {
event->acceptProposedAction(); event->acceptProposedAction();
return; return;
} }
@ -559,22 +586,17 @@ void TabBar::dragEnterEvent(QDragEnterEvent* event)
ComboTabBar::dragEnterEvent(event); ComboTabBar::dragEnterEvent(event);
} }
void TabBar::dragLeaveEvent(QDragLeaveEvent *event)
{
clearDropIndicator();
ComboTabBar::dragLeaveEvent(event);
}
void TabBar::dragMoveEvent(QDragMoveEvent *event) void TabBar::dragMoveEvent(QDragMoveEvent *event)
{ {
const int index = tabAt(event->pos()); const int index = tabAt(event->pos());
if (index == -1) { const QMimeData* mime = event->mimeData();
if (index == -1 || (mime->hasFormat(MIMETYPE) && event->source() == this)) {
ComboTabBar::dragMoveEvent(event); ComboTabBar::dragMoveEvent(event);
return; return;
} }
switch (tabDropAction(event->pos(), tabRect(index))) { switch (tabDropAction(event->pos(), tabRect(index), !mime->hasFormat(MIMETYPE))) {
case PrependTab: case PrependTab:
showDropIndicator(index, BeforeTab); showDropIndicator(index, BeforeTab);
break; break;
@ -587,17 +609,32 @@ void TabBar::dragMoveEvent(QDragMoveEvent *event)
} }
} }
void TabBar::dragLeaveEvent(QDragLeaveEvent *event)
{
clearDropIndicator();
ComboTabBar::dragLeaveEvent(event);
}
void TabBar::dropEvent(QDropEvent* event) void TabBar::dropEvent(QDropEvent* event)
{ {
clearDropIndicator(); clearDropIndicator();
const QMimeData* mime = event->mimeData(); const QMimeData* mime = event->mimeData();
if (!mime->hasText() && !mime->hasUrls()) { if (!mime->hasText() && !mime->hasUrls() && !mime->hasFormat(MIMETYPE)) {
ComboTabBar::dropEvent(event); ComboTabBar::dropEvent(event);
return; return;
} }
event->acceptProposedAction();
if (mime->hasFormat(MIMETYPE) && event->source() == this) {
return;
}
TabBar *sourceTabBar = qobject_cast<TabBar*>(event->source());
int index = tabAt(event->pos()); int index = tabAt(event->pos());
if (index == -1) { if (index == -1) {
if (mime->hasUrls()) { if (mime->hasUrls()) {
@ -606,24 +643,39 @@ void TabBar::dropEvent(QDropEvent* event)
} }
} else if (mime->hasText()) { } else if (mime->hasText()) {
m_tabWidget->addView(mApp->searchEnginesManager()->searchResult(mime->text()), Qz::NT_SelectedNewEmptyTab); m_tabWidget->addView(mApp->searchEnginesManager()->searchResult(mime->text()), Qz::NT_SelectedNewEmptyTab);
} else if (mime->hasFormat(MIMETYPE) && sourceTabBar) {
WebTab *tab = sourceTabBar->webTab();
if (tab) {
sourceTabBar->m_tabWidget->detachTab(tab);
tab->setPinned(false);
m_tabWidget->addView(tab, Qz::NT_SelectedTab);
} }
} }
else { } else {
LoadRequest req; LoadRequest req;
WebTab* tab = m_window->weView(index)->webTab(); WebTab* tab = m_window->weView(index)->webTab();
TabDropAction action = tabDropAction(event->pos(), tabRect(index)); TabDropAction action = tabDropAction(event->pos(), tabRect(index), !mime->hasFormat(MIMETYPE));
if (mime->hasUrls()) { if (mime->hasUrls()) {
req = mime->urls().at(0); req = mime->urls().at(0);
} else if (mime->hasText()) { } else if (mime->hasText()) {
req = mApp->searchEnginesManager()->searchResult(mime->text()); req = mApp->searchEnginesManager()->searchResult(mime->text());
} }
if (action == SelectTab) { if (action == SelectTab) {
if (tab->isRestored()) { if (tab->isRestored() && !req.isEmpty()) {
tab->webView()->load(req); tab->webView()->load(req);
} }
} else if (action == PrependTab || action == AppendTab) { } else if (action == PrependTab || action == AppendTab) {
const int newIndex = action == PrependTab ? index : index + 1; const int newIndex = action == PrependTab ? index : index + 1;
m_tabWidget->addView(req, QString(), Qz::NT_SelectedNewEmptyTab, false, newIndex, index <= pinnedTabsCount()); if (!req.isEmpty()) {
m_tabWidget->addView(req, QString(), Qz::NT_SelectedNewEmptyTab, false, newIndex, index < pinnedTabsCount());
} else if (mime->hasFormat(MIMETYPE) && sourceTabBar) {
WebTab *tab = sourceTabBar->webTab();
if (tab) {
sourceTabBar->m_tabWidget->detachTab(tab);
tab->setPinned(index < pinnedTabsCount());
m_tabWidget->insertView(newIndex, tab, Qz::NT_SelectedTab);
}
}
} }
} }
} }

View File

@ -1,6 +1,6 @@
/* ============================================================ /* ============================================================
* Falkon - Qt web browser * Falkon - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com> * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -70,8 +70,8 @@ private:
void mouseReleaseEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent* event);
void dragEnterEvent(QDragEnterEvent* event); void dragEnterEvent(QDragEnterEvent* event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dragMoveEvent(QDragMoveEvent *event); void dragMoveEvent(QDragMoveEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dropEvent(QDropEvent* event); void dropEvent(QDropEvent* event);
QSize tabSizeHint(int index, bool fast) const; QSize tabSizeHint(int index, bool fast) const;

View File

@ -386,7 +386,7 @@ int TabWidget::addView(WebTab *tab, const Qz::NewTabPositionFlags &openFlags)
int TabWidget::insertView(int index, WebTab *tab, const Qz::NewTabPositionFlags &openFlags) int TabWidget::insertView(int index, WebTab *tab, const Qz::NewTabPositionFlags &openFlags)
{ {
m_locationBars->addWidget(tab->locationBar()); m_locationBars->addWidget(tab->locationBar());
int newIndex = insertTab(index, tab, QString()); int newIndex = insertTab(index, tab, QString(), tab->isPinned());
tab->attach(m_window); tab->attach(m_window);
if (openFlags.testFlag(Qz::NT_SelectedTab)) { if (openFlags.testFlag(Qz::NT_SelectedTab)) {
@ -661,11 +661,12 @@ void TabWidget::detachTab(int index)
{ {
WebTab* tab = weTab(index); WebTab* tab = weTab(index);
if (tab->isPinned() || count() == 1) { if (count() < 2) {
return; return;
} }
detachTab(tab); detachTab(tab);
tab->setPinned(false);
BrowserWindow* window = mApp->createWindow(Qz::BW_NewWindow); BrowserWindow* window = mApp->createWindow(Qz::BW_NewWindow);
window->setStartTab(tab); window->setStartTab(tab);