mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-20 10:46:35 +01:00
TabManager: Support moving tabs between windows by drag & drop.
This commit is contained in:
parent
bad3a76a2e
commit
48c409fa76
@ -31,6 +31,7 @@
|
||||
#include "tldextractor/tldextractor.h"
|
||||
#include "tabmanagerdelegate.h"
|
||||
#include "tabcontextmenu.h"
|
||||
#include "tabbar.h"
|
||||
|
||||
#include <QDesktopWidget>
|
||||
#include <QDialogButtonBox>
|
||||
@ -38,6 +39,7 @@
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
#include <QMimeData>
|
||||
|
||||
|
||||
TLDExtractor* TabManagerWidget::s_tldExtractor = 0;
|
||||
@ -59,6 +61,7 @@ TabManagerWidget::TabManagerWidget(BrowserWindow* mainClass, QWidget* parent, bo
|
||||
}
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->treeWidget->setSelectionMode(QTreeWidget::SingleSelection);
|
||||
ui->treeWidget->setUniformRowHeights(true);
|
||||
ui->treeWidget->setColumnCount(2);
|
||||
ui->treeWidget->header()->hide();
|
||||
@ -85,6 +88,7 @@ TabManagerWidget::TabManagerWidget(BrowserWindow* mainClass, QWidget* parent, bo
|
||||
connect(ui->filterBar, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
|
||||
connect(ui->treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(onItemActivated(QTreeWidgetItem*,int)));
|
||||
connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
|
||||
connect(ui->treeWidget, SIGNAL(requestRefreshTree()), this, SLOT(delayedRefreshTree()));
|
||||
}
|
||||
|
||||
TabManagerWidget::~TabManagerWidget()
|
||||
@ -178,6 +182,8 @@ void TabManagerWidget::refreshTree()
|
||||
}
|
||||
|
||||
ui->treeWidget->clear();
|
||||
ui->treeWidget->setEnableDragTabs(m_groupType == GroupByWindow);
|
||||
|
||||
QTreeWidgetItem* currentTabItem = nullptr;
|
||||
|
||||
if (m_groupType == GroupByHost) {
|
||||
@ -527,18 +533,8 @@ void TabManagerWidget::closeSelectedTabs(const QHash<BrowserWindow*, WebTab*> &t
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidget::detachSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
static void detachTabsTo(BrowserWindow* targetWindow, const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
{
|
||||
// TODO: use TabWidget::detachTab()
|
||||
if (tabsHash.isEmpty() ||
|
||||
(tabsHash.uniqueKeys().size() == 1 &&
|
||||
tabsHash.size() == tabsHash.keys().at(0)->tabWidget()->count())) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserWindow* newWindow = mApp->createWindow(Qz::BW_OtherRestoredWindow);
|
||||
newWindow->move(mApp->desktop()->availableGeometry(this).topLeft() + QPoint(30, 30));
|
||||
|
||||
const QList<BrowserWindow*> &windows = tabsHash.uniqueKeys();
|
||||
foreach (BrowserWindow* mainWindow, windows) {
|
||||
const QList<WebTab*> &tabs = tabsHash.values(mainWindow);
|
||||
@ -550,11 +546,25 @@ void TabManagerWidget::detachSelectedTabs(const QHash<BrowserWindow*, WebTab*> &
|
||||
mainWindow = 0;
|
||||
}
|
||||
|
||||
newWindow->tabWidget()->addView(webTab);
|
||||
targetWindow->tabWidget()->addView(webTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabManagerWidget::detachSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
{
|
||||
if (tabsHash.isEmpty() ||
|
||||
(tabsHash.uniqueKeys().size() == 1 &&
|
||||
tabsHash.size() == tabsHash.keys().at(0)->tabWidget()->count())) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowserWindow* newWindow = mApp->createWindow(Qz::BW_OtherRestoredWindow);
|
||||
newWindow->move(mApp->desktop()->availableGeometry(this).topLeft() + QPoint(30, 30));
|
||||
|
||||
detachTabsTo(newWindow, tabsHash);
|
||||
}
|
||||
|
||||
bool TabManagerWidget::bookmarkSelectedTabs(const QHash<BrowserWindow*, WebTab*> &tabsHash)
|
||||
{
|
||||
QDialog* dialog = new QDialog(getWindow(), Qt::WindowStaysOnTopHint | Qt::MSWindowsFixedSizeDialogHint);
|
||||
@ -624,7 +634,7 @@ QTreeWidgetItem* TabManagerWidget::groupByDomainName(bool useHostName)
|
||||
QString domain = domainFromUrl(webTab->url(), useHostName);
|
||||
|
||||
if (!tabsGroupedByDomain.contains(domain)) {
|
||||
TabItem* groupItem = new TabItem(ui->treeWidget, 0, false);
|
||||
TabItem* groupItem = new TabItem(ui->treeWidget, false, false, 0, false);
|
||||
groupItem->setTitle(domain);
|
||||
groupItem->setIsActiveOrCaption(true);
|
||||
|
||||
@ -633,7 +643,7 @@ QTreeWidgetItem* TabManagerWidget::groupByDomainName(bool useHostName)
|
||||
|
||||
QTreeWidgetItem* groupItem = tabsGroupedByDomain.value(domain);
|
||||
|
||||
TabItem* tabItem = new TabItem(ui->treeWidget, groupItem);
|
||||
TabItem* tabItem = new TabItem(ui->treeWidget, false, true, groupItem);
|
||||
tabItem->setBrowserWindow(mainWin);
|
||||
tabItem->setWebTab(webTab);
|
||||
|
||||
@ -673,7 +683,7 @@ QTreeWidgetItem* TabManagerWidget::groupByWindow()
|
||||
|
||||
for (int win = 0; win < windows.count(); ++win) {
|
||||
BrowserWindow* mainWin = windows.at(win);
|
||||
TabItem* winItem = new TabItem(ui->treeWidget);
|
||||
TabItem* winItem = new TabItem(ui->treeWidget, true, false);
|
||||
winItem->setBrowserWindow(mainWin);
|
||||
winItem->setText(0, tr("Window %1").arg(QString::number(win + 1)));
|
||||
winItem->setToolTip(0, tr("Double click to switch"));
|
||||
@ -687,7 +697,7 @@ QTreeWidgetItem* TabManagerWidget::groupByWindow()
|
||||
m_webPage = 0;
|
||||
continue;
|
||||
}
|
||||
TabItem* tabItem = new TabItem(ui->treeWidget, winItem);
|
||||
TabItem* tabItem = new TabItem(ui->treeWidget, true, true, winItem);
|
||||
tabItem->setBrowserWindow(mainWin);
|
||||
tabItem->setWebTab(webTab);
|
||||
|
||||
@ -716,14 +726,29 @@ BrowserWindow* TabManagerWidget::getWindow()
|
||||
}
|
||||
}
|
||||
|
||||
TabItem::TabItem(QTreeWidget* treeWidget, QTreeWidgetItem* parent, bool addToTree)
|
||||
TabItem::TabItem(QTreeWidget* treeWidget, bool supportDrag, bool isTab, QTreeWidgetItem* parent, bool addToTree)
|
||||
: QObject()
|
||||
, QTreeWidgetItem(addToTree ? (parent ? parent : treeWidget->invisibleRootItem()) : 0, 1)
|
||||
, m_treeWidget(treeWidget)
|
||||
, m_window(0)
|
||||
, m_webTab(0)
|
||||
, m_isTab(isTab)
|
||||
{
|
||||
setFlags(flags() | (parent ? Qt::ItemIsUserCheckable : Qt::ItemIsUserCheckable | Qt::ItemIsTristate));
|
||||
Qt::ItemFlags flgs = flags() | (parent ? Qt::ItemIsUserCheckable : Qt::ItemIsUserCheckable | Qt::ItemIsTristate);
|
||||
|
||||
if (supportDrag) {
|
||||
if (isTab) {
|
||||
flgs |= Qt::ItemIsDragEnabled | Qt::ItemNeverHasChildren;
|
||||
flgs &= ~Qt::ItemIsDropEnabled;
|
||||
}
|
||||
else {
|
||||
flgs |= Qt::ItemIsDropEnabled;
|
||||
flgs &= ~Qt::ItemIsDragEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
setFlags(flgs);
|
||||
|
||||
setCheckState(0, Qt::Unchecked);
|
||||
}
|
||||
|
||||
@ -807,3 +832,122 @@ void TabItem::setIsSavedTab(bool yes)
|
||||
{
|
||||
setData(0, SavedRole, yes ? QVariant(true) : QVariant());
|
||||
}
|
||||
|
||||
bool TabItem::isTab() const
|
||||
{
|
||||
return m_isTab;
|
||||
}
|
||||
|
||||
TabTreeWidget::TabTreeWidget(QWidget *parent)
|
||||
: QTreeWidget(parent)
|
||||
{
|
||||
invisibleRootItem()->setFlags(invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled);
|
||||
}
|
||||
|
||||
Qt::DropActions TabTreeWidget::supportedDropActions() const
|
||||
{
|
||||
return Qt::MoveAction | Qt::CopyAction;
|
||||
}
|
||||
|
||||
#define MIMETYPE QLatin1String("application/qupzilla.tabs")
|
||||
|
||||
QStringList TabTreeWidget::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types.append(MIMETYPE);
|
||||
return types;
|
||||
}
|
||||
|
||||
QMimeData *TabTreeWidget::mimeData(const QList<QTreeWidgetItem*> items) const
|
||||
{
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
QByteArray encodedData;
|
||||
|
||||
QDataStream stream(&encodedData, QIODevice::WriteOnly);
|
||||
|
||||
if (items.size() > 0) {
|
||||
TabItem* tabItem = static_cast<TabItem*>(items.at(0));
|
||||
if (!tabItem || !tabItem->isTab())
|
||||
return 0;
|
||||
|
||||
stream << (quintptr) tabItem->window() << (quintptr) tabItem->webTab();
|
||||
|
||||
mimeData->setData(MIMETYPE, encodedData);
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TabTreeWidget::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
|
||||
{
|
||||
if (action == Qt::IgnoreAction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TabItem* parentItem = static_cast<TabItem*>(parent);
|
||||
|
||||
if (!data->hasFormat(MIMETYPE) || !parentItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_ASSERT(!parentItem->isTab());
|
||||
|
||||
BrowserWindow* targetWindow = parentItem->window();
|
||||
|
||||
QByteArray encodedData = data->data(MIMETYPE);
|
||||
QDataStream stream(&encodedData, QIODevice::ReadOnly);
|
||||
|
||||
if (!stream.atEnd()) {
|
||||
quintptr webTabPtr;
|
||||
quintptr windowPtr;
|
||||
|
||||
stream >> windowPtr >> webTabPtr;
|
||||
|
||||
WebTab* webTab = (WebTab*) webTabPtr;
|
||||
BrowserWindow* window = (BrowserWindow*) windowPtr;
|
||||
|
||||
if (window == targetWindow) {
|
||||
if (index > 0 && webTab->tabIndex() < index)
|
||||
--index;
|
||||
|
||||
if (webTab->isPinned() && index >= targetWindow->tabWidget()->pinnedTabsCount())
|
||||
index = targetWindow->tabWidget()->pinnedTabsCount() - 1;
|
||||
|
||||
if (!webTab->isPinned() && index < targetWindow->tabWidget()->pinnedTabsCount())
|
||||
index = targetWindow->tabWidget()->pinnedTabsCount();
|
||||
|
||||
if (index != webTab->tabIndex()) {
|
||||
targetWindow->tabWidget()->tabBar()->moveTab(webTab->tabIndex(), index);
|
||||
|
||||
if (!webTab->isCurrentTab())
|
||||
emit requestRefreshTree();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!webTab->isPinned()) {
|
||||
QHash<BrowserWindow*, WebTab*> tabsHash;
|
||||
tabsHash.insert(window, webTab);
|
||||
|
||||
detachTabsTo(targetWindow, tabsHash);
|
||||
|
||||
if (index < targetWindow->tabWidget()->pinnedTabsCount())
|
||||
index = targetWindow->tabWidget()->pinnedTabsCount();
|
||||
|
||||
targetWindow->tabWidget()->tabBar()->moveTab(webTab->tabIndex(), index);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TabTreeWidget::setEnableDragTabs(bool enable)
|
||||
{
|
||||
setDragEnabled(enable);
|
||||
setAcceptDrops(enable);
|
||||
viewport()->setAcceptDrops(enable);
|
||||
setDropIndicatorShown(enable);
|
||||
}
|
||||
|
@ -35,6 +35,25 @@ class WebTab;
|
||||
class WebView;
|
||||
class TLDExtractor;
|
||||
|
||||
class TabTreeWidget : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TabTreeWidget(QWidget* parent = 0);
|
||||
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
QStringList mimeTypes() const;
|
||||
QMimeData* mimeData(const QList<QTreeWidgetItem*> items) const;
|
||||
bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action);
|
||||
|
||||
void setEnableDragTabs(bool enable);
|
||||
|
||||
signals:
|
||||
void requestRefreshTree();
|
||||
|
||||
};
|
||||
|
||||
class TabManagerWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -107,7 +126,7 @@ public:
|
||||
SavedRole = Qt::UserRole + 2
|
||||
};
|
||||
|
||||
TabItem(QTreeWidget* treeWidget, QTreeWidgetItem* parent = 0, bool addToTree = true);
|
||||
TabItem(QTreeWidget* treeWidget, bool supportDrag = true, bool isTab = true, QTreeWidgetItem* parent = 0, bool addToTree = true);
|
||||
|
||||
BrowserWindow* window() const;
|
||||
void setBrowserWindow(BrowserWindow* window);
|
||||
@ -115,6 +134,8 @@ public:
|
||||
WebTab* webTab() const;
|
||||
void setWebTab(WebTab* webTab);
|
||||
|
||||
bool isTab() const;
|
||||
|
||||
public slots:
|
||||
void updateIcon();
|
||||
void setTitle(const QString& title);
|
||||
@ -125,6 +146,7 @@ private:
|
||||
QTreeWidget* m_treeWidget;
|
||||
BrowserWindow* m_window;
|
||||
WebTab* m_webTab;
|
||||
bool m_isTab;
|
||||
};
|
||||
|
||||
#endif // TABMANAGERWIDGET_H
|
||||
|
@ -33,7 +33,7 @@
|
||||
<widget class="LineEdit" name="filterBar"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<widget class="TabTreeWidget" name="treeWidget">
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
@ -52,6 +52,11 @@
|
||||
<extends>QLineEdit</extends>
|
||||
<header>lineedit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TabTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>tabmanagerwidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>treeWidget</tabstop>
|
||||
|
Loading…
Reference in New Issue
Block a user