diff --git a/src/plugins/TabManager/tabmanagerwidget.cpp b/src/plugins/TabManager/tabmanagerwidget.cpp index 385daa42a..552730da5 100644 --- a/src/plugins/TabManager/tabmanagerwidget.cpp +++ b/src/plugins/TabManager/tabmanagerwidget.cpp @@ -31,6 +31,7 @@ #include "tldextractor/tldextractor.h" #include "tabmanagerdelegate.h" #include "tabcontextmenu.h" +#include "tabbar.h" #include #include @@ -38,6 +39,7 @@ #include #include #include +#include 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 &t } } -void TabManagerWidget::detachSelectedTabs(const QHash &tabsHash) +static void detachTabsTo(BrowserWindow* targetWindow, const QHash &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 &windows = tabsHash.uniqueKeys(); foreach (BrowserWindow* mainWindow, windows) { const QList &tabs = tabsHash.values(mainWindow); @@ -550,11 +546,25 @@ void TabManagerWidget::detachSelectedTabs(const QHash & mainWindow = 0; } - newWindow->tabWidget()->addView(webTab); + targetWindow->tabWidget()->addView(webTab); } } } +void TabManagerWidget::detachSelectedTabs(const QHash &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 &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 items) const +{ + QMimeData* mimeData = new QMimeData(); + QByteArray encodedData; + + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + if (items.size() > 0) { + TabItem* tabItem = static_cast(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(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 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); +} diff --git a/src/plugins/TabManager/tabmanagerwidget.h b/src/plugins/TabManager/tabmanagerwidget.h index fba2a96e9..4562afeb6 100644 --- a/src/plugins/TabManager/tabmanagerwidget.h +++ b/src/plugins/TabManager/tabmanagerwidget.h @@ -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 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 diff --git a/src/plugins/TabManager/tabmanagerwidget.ui b/src/plugins/TabManager/tabmanagerwidget.ui index bc63423f0..378f3009c 100644 --- a/src/plugins/TabManager/tabmanagerwidget.ui +++ b/src/plugins/TabManager/tabmanagerwidget.ui @@ -33,7 +33,7 @@ - + false @@ -52,6 +52,11 @@ QLineEdit
lineedit.h
+ + TabTreeWidget + QTreeWidget +
tabmanagerwidget.h
+
treeWidget