Warning, file /network/falkon/src/lib/tabwidget/tabbar.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "tabbar.h"
0019 #include "tabwidget.h"
0020 #include "browserwindow.h"
0021 #include "webtab.h"
0022 #include "toolbutton.h"
0023 #include "settings.h"
0024 #include "mainapplication.h"
0025 #include "pluginproxy.h"
0026 #include "iconprovider.h"
0027 #include "tabcontextmenu.h"
0028 #include "searchenginesmanager.h"
0029 #include "tabmrumodel.h"
0030 
0031 #include <QMimeData>
0032 #include <QMouseEvent>
0033 #include <QStyleOption>
0034 #include <QApplication>
0035 #include <QTimer>
0036 #include <QRect>
0037 #include <QLabel>
0038 #include <QScrollArea>
0039 #include <QHBoxLayout>
0040 #include <QDrag>
0041 
0042 #define MIMETYPE QSL("application/falkon.tabbar.tab")
0043 
0044 class TabBarTabMetrics : public QWidget
0045 {
0046     Q_OBJECT
0047     Q_PROPERTY(int normalMaxWidth READ normalMaxWidth WRITE setNormalMaxWidth)
0048     Q_PROPERTY(int normalMinWidth READ normalMinWidth WRITE setNormalMinWidth)
0049     Q_PROPERTY(int activeMinWidth READ activeMinWidth WRITE setActiveMinWidth)
0050     Q_PROPERTY(int overflowedWidth READ overflowedWidth WRITE setOverflowedWidth)
0051     Q_PROPERTY(int pinnedWidth READ pinnedWidth WRITE setPinnedWidth)
0052 
0053 public:
0054     void init()
0055     {
0056         if (!m_metrics.isEmpty()) {
0057             return;
0058         }
0059         m_metrics[0] = 250;
0060         m_metrics[1] = 100;
0061         m_metrics[2] = 100;
0062         m_metrics[3] = 100;
0063         m_metrics[4] = -1; // Will be initialized from TabBar
0064     }
0065 
0066     int normalMaxWidth() const { return m_metrics.value(0); }
0067     void setNormalMaxWidth(int value) { m_metrics[0] = value; }
0068 
0069     int normalMinWidth() const { return m_metrics.value(1); }
0070     void setNormalMinWidth(int value) { m_metrics[1] = value; }
0071 
0072     int activeMinWidth() const { return m_metrics.value(2); }
0073     void setActiveMinWidth(int value) { m_metrics[2] = value; }
0074 
0075     int overflowedWidth() const { return m_metrics.value(3); }
0076     void setOverflowedWidth(int value) { m_metrics[3] = value; }
0077 
0078     int pinnedWidth() const { return m_metrics.value(4); }
0079     void setPinnedWidth(int value) { m_metrics[4] = value; }
0080 
0081 private:
0082     QHash<int, int> m_metrics;
0083 };
0084 
0085 Q_GLOBAL_STATIC(TabBarTabMetrics, tabMetrics)
0086 
0087 TabBar::TabBar(BrowserWindow* window, TabWidget* tabWidget)
0088     : ComboTabBar()
0089     , m_window(window)
0090     , m_tabWidget(tabWidget)
0091     , m_hideTabBarWithOneTab(false)
0092     , m_showCloseOnInactive(0)
0093     , m_normalTabWidth(0)
0094     , m_activeTabWidth(0)
0095     , m_forceHidden(false)
0096 {
0097     setObjectName(QSL("tabbar"));
0098     setElideMode(Qt::ElideRight);
0099     setFocusPolicy(Qt::NoFocus);
0100     setTabsClosable(false);
0101     setMouseTracking(true);
0102     setDocumentMode(true);
0103     setAcceptDrops(true);
0104     setDrawBase(false);
0105     setMovable(true);
0106 
0107     connect(this, &ComboTabBar::currentChanged, this, &TabBar::currentTabChanged);
0108 
0109     // ComboTabBar features
0110     setUsesScrollButtons(true);
0111     setCloseButtonsToolTip(BrowserWindow::tr("Close Tab"));
0112     connect(this, &ComboTabBar::overFlowChanged, this, &TabBar::overflowChanged);
0113 
0114     tabMetrics()->init();
0115 
0116     if (mApp->isPrivate()) {
0117         auto* privateBrowsing = new QLabel(this);
0118         privateBrowsing->setObjectName(QSL("private-browsing-icon"));
0119         privateBrowsing->setPixmap(IconProvider::privateBrowsingIcon().pixmap(16));
0120         privateBrowsing->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
0121         privateBrowsing->setFixedWidth(30);
0122         addCornerWidget(privateBrowsing, Qt::TopLeftCorner);
0123     }
0124 }
0125 
0126 void TabBar::loadSettings()
0127 {
0128     Settings settings;
0129     settings.beginGroup(QSL("Browser-Tabs-Settings"));
0130     m_hideTabBarWithOneTab = settings.value(QSL("hideTabsWithOneTab"), false).toBool();
0131     bool activateLastTab = settings.value(QSL("ActivateLastTabWhenClosingActual"), false).toBool();
0132     m_showCloseOnInactive = settings.value(QSL("showCloseOnInactiveTabs"), 0).toInt(nullptr);
0133     settings.endGroup();
0134 
0135     setSelectionBehaviorOnRemove(activateLastTab ? QTabBar::SelectPreviousTab : QTabBar::SelectRightTab);
0136     setVisible(!(count() <= 1 && m_hideTabBarWithOneTab));
0137 
0138     setUpLayout();
0139 }
0140 
0141 TabWidget* TabBar::tabWidget() const
0142 {
0143     return m_tabWidget;
0144 }
0145 
0146 void TabBar::setVisible(bool visible)
0147 {
0148     if (m_forceHidden) {
0149         ComboTabBar::setVisible(false);
0150         return;
0151     }
0152 
0153     // Make sure to honor user preference
0154     if (visible) {
0155         visible = !(count() <= 1 && m_hideTabBarWithOneTab);
0156     }
0157 
0158     ComboTabBar::setVisible(visible);
0159 }
0160 
0161 void TabBar::setForceHidden(bool hidden)
0162 {
0163     m_forceHidden = hidden;
0164     setVisible(!m_forceHidden);
0165 }
0166 
0167 void TabBar::overflowChanged(bool overflowed)
0168 {
0169     // Make sure close buttons on inactive tabs are hidden
0170     // This is needed for when leaving fullscreen from non-overflowed to overflowed state
0171     if (overflowed && m_showCloseOnInactive != 1) {
0172         setTabsClosable(false);
0173         showCloseButton(currentIndex());
0174     }
0175 }
0176 
0177 QSize TabBar::tabSizeHint(int index, bool fast) const
0178 {
0179     if (!m_window->isVisible()) {
0180         // Don't calculate it when window is not visible
0181         // It produces invalid size anyway
0182         return QSize(-1, -1);
0183     }
0184 
0185     const int pinnedTabWidth = comboTabBarPixelMetric(ComboTabBar::PinnedTabWidth);
0186     const int minTabWidth = comboTabBarPixelMetric(ComboTabBar::NormalTabMinimumWidth);
0187 
0188     QSize size = ComboTabBar::tabSizeHint(index);
0189 
0190     // The overflowed tabs have same size and we can use this fast method
0191     if (fast) {
0192         size.setWidth(index >= pinnedTabsCount() ? minTabWidth : pinnedTabWidth);
0193         return size;
0194     }
0195 
0196     auto* webTab = qobject_cast<WebTab*>(m_tabWidget->widget(index));
0197     auto* tabBar = const_cast <TabBar*>(this);
0198 
0199     if (webTab && webTab->isPinned()) {
0200         size.setWidth(pinnedTabWidth);
0201     }
0202     else {
0203         int availableWidth = mainTabBarWidth() - comboTabBarPixelMetric(ExtraReservedWidth);
0204 
0205         if (availableWidth < 0) {
0206             return QSize(-1, -1);
0207         }
0208 
0209         const int normalTabsCount = ComboTabBar::normalTabsCount();
0210         const int maxTabWidth = comboTabBarPixelMetric(ComboTabBar::NormalTabMaximumWidth);
0211 
0212         if (availableWidth >= maxTabWidth * normalTabsCount) {
0213             m_normalTabWidth = maxTabWidth;
0214             size.setWidth(m_normalTabWidth);
0215         }
0216         else if (normalTabsCount > 0) {
0217             const int minActiveTabWidth = comboTabBarPixelMetric(ComboTabBar::ActiveTabMinimumWidth);
0218 
0219             int maxWidthForTab = availableWidth / normalTabsCount;
0220             int realTabWidth = maxWidthForTab;
0221             bool adjustingActiveTab = false;
0222 
0223             if (realTabWidth < minActiveTabWidth) {
0224                 maxWidthForTab = normalTabsCount > 1 ? (availableWidth - minActiveTabWidth) / (normalTabsCount - 1) : 0;
0225                 realTabWidth = minActiveTabWidth;
0226                 adjustingActiveTab = true;
0227             }
0228 
0229             bool tryAdjusting = availableWidth >= minTabWidth * normalTabsCount;
0230 
0231             if (m_showCloseOnInactive != 1 && tabsClosable() && availableWidth < (minTabWidth + 25) * normalTabsCount) {
0232                 // Hiding close buttons to save some space
0233                 tabBar->setTabsClosable(false);
0234                 tabBar->showCloseButton(currentIndex());
0235             }
0236             if (m_showCloseOnInactive == 1) {
0237                 // Always showing close buttons
0238                 tabBar->setTabsClosable(true);
0239                 tabBar->showCloseButton(currentIndex());
0240             }
0241 
0242             if (tryAdjusting) {
0243                 m_normalTabWidth = maxWidthForTab;
0244 
0245                 // Fill any empty space (we've got from rounding) with active tab
0246                 if (index == mainTabBarCurrentIndex()) {
0247                     if (adjustingActiveTab) {
0248                         m_activeTabWidth = (availableWidth - minActiveTabWidth
0249                                             - maxWidthForTab * (normalTabsCount - 1)) + realTabWidth;
0250                     }
0251                     else {
0252                         m_activeTabWidth = (availableWidth - maxWidthForTab * normalTabsCount) + maxWidthForTab;
0253                     }
0254                     size.setWidth(m_activeTabWidth);
0255                 }
0256                 else {
0257                     size.setWidth(m_normalTabWidth);
0258                 }
0259             }
0260         }
0261 
0262         // Restore close buttons according to preferences
0263         if (m_showCloseOnInactive != 2 && !tabsClosable() && availableWidth >= (minTabWidth + 25) * normalTabsCount) {
0264             tabBar->setTabsClosable(true);
0265 
0266             // Hide close buttons on pinned tabs
0267             for (int i = 0; i < count(); ++i) {
0268                 tabBar->updatePinnedTabCloseButton(i);
0269             }
0270         }
0271     }
0272 
0273     if (index == count() - 1) {
0274         auto* lastMainActiveTab = qobject_cast<WebTab*>(m_tabWidget->widget(mainTabBarCurrentIndex()));
0275         int xForAddTabButton = cornerWidth(Qt::TopLeftCorner) + pinTabBarWidth() + normalTabsCount() * m_normalTabWidth;
0276 
0277         if (lastMainActiveTab && m_activeTabWidth > m_normalTabWidth) {
0278             xForAddTabButton += m_activeTabWidth - m_normalTabWidth;
0279         }
0280 
0281         if (QApplication::layoutDirection() == Qt::RightToLeft) {
0282             xForAddTabButton = width() - xForAddTabButton;
0283         }
0284 
0285         Q_EMIT tabBar->moveAddTabButton(xForAddTabButton);
0286     }
0287 
0288     return size;
0289 }
0290 
0291 int TabBar::comboTabBarPixelMetric(ComboTabBar::SizeType sizeType) const
0292 {
0293     switch (sizeType) {
0294     case ComboTabBar::PinnedTabWidth:
0295         return tabMetrics()->pinnedWidth() > 0 ? tabMetrics()->pinnedWidth() : 32;
0296 
0297     case ComboTabBar::ActiveTabMinimumWidth:
0298         return tabMetrics()->activeMinWidth();
0299 
0300     case ComboTabBar::NormalTabMinimumWidth:
0301         return tabMetrics()->normalMinWidth();
0302 
0303     case ComboTabBar::OverflowedTabWidth:
0304         return tabMetrics()->overflowedWidth();
0305 
0306     case ComboTabBar::NormalTabMaximumWidth:
0307         return tabMetrics()->normalMaxWidth();
0308 
0309     case ComboTabBar::ExtraReservedWidth:
0310         return m_tabWidget->extraReservedWidth();
0311 
0312     default:
0313         break;
0314     }
0315 
0316     return -1;
0317 }
0318 
0319 WebTab* TabBar::webTab(int index) const
0320 {
0321     if (index == -1) {
0322         return qobject_cast<WebTab*>(m_tabWidget->widget(currentIndex()));
0323     }
0324     return qobject_cast<WebTab*>(m_tabWidget->widget(index));
0325 }
0326 
0327 void TabBar::showCloseButton(int index)
0328 {
0329     if (!validIndex(index)) {
0330         return;
0331     }
0332 
0333     auto* webTab = qobject_cast<WebTab*>(m_tabWidget->widget(index));
0334     auto* button = qobject_cast<QAbstractButton*>(tabButton(index, closeButtonPosition()));
0335 
0336     if (button || (webTab && webTab->isPinned())) {
0337         return;
0338     }
0339 
0340     insertCloseButton(index);
0341 }
0342 
0343 void TabBar::contextMenuEvent(QContextMenuEvent* event)
0344 {
0345     if (isDragInProgress()) {
0346         return;
0347     }
0348 
0349     int index = tabAt(event->pos());
0350 
0351     TabContextMenu menu(index, m_window);
0352 
0353     // Prevent choosing first option with double rightclick
0354     const QPoint pos = event->globalPos();
0355     QPoint p(pos.x(), pos.y() + 1);
0356     menu.exec(p);
0357 }
0358 
0359 void TabBar::hideCloseButton(int index)
0360 {
0361     if (!validIndex(index) || tabsClosable()) {
0362         return;
0363     }
0364 
0365     auto* button = qobject_cast<CloseButton*>(tabButton(index, closeButtonPosition()));
0366     if (!button) {
0367         return;
0368     }
0369 
0370     setTabButton(index, closeButtonPosition(), nullptr);
0371     button->deleteLater();
0372 }
0373 
0374 void TabBar::updatePinnedTabCloseButton(int index)
0375 {
0376     if (!validIndex(index)) {
0377         return;
0378     }
0379 
0380     auto* webTab = qobject_cast<WebTab*>(m_tabWidget->widget(index));
0381     auto* button = qobject_cast<QAbstractButton*>(tabButton(index, closeButtonPosition()));
0382 
0383     bool pinned = webTab && webTab->isPinned();
0384 
0385     if (pinned) {
0386         if (button) {
0387             button->hide();
0388         }
0389     }
0390     else {
0391         if (button) {
0392             button->show();
0393         }
0394         else {
0395             showCloseButton(index);
0396         }
0397     }
0398 }
0399 
0400 void TabBar::closeTabFromButton()
0401 {
0402     QWidget* button = qobject_cast<QWidget*>(sender());
0403 
0404     int tabToClose = -1;
0405 
0406     for (int i = 0; i < count(); ++i) {
0407         if (tabButton(i, closeButtonPosition()) == button) {
0408             tabToClose = i;
0409             break;
0410         }
0411     }
0412 
0413     if (tabToClose != -1) {
0414         m_tabWidget->requestCloseTab(tabToClose);
0415     }
0416 }
0417 
0418 void TabBar::currentTabChanged(int index)
0419 {
0420     if (!validIndex(index)) {
0421         return;
0422     }
0423 
0424     // Don't hide close buttons when dragging tabs
0425     if (m_dragStartPosition.isNull() && !m_isRestoring) {
0426         showCloseButton(index);
0427         if (m_lastTab) {
0428             hideCloseButton(m_lastTab->tabIndex());
0429         }
0430         QTimer::singleShot(100, this, [this]() { ensureVisible(); });
0431     }
0432 
0433     m_lastTab = webTab(index);
0434     m_tabWidget->currentTabChanged(index);
0435 }
0436 
0437 void TabBar::setTabText(int index, const QString &text)
0438 {
0439     if (m_isRestoring) {
0440         return;
0441     }
0442 
0443     QString tabText = text;
0444 
0445     // Avoid Alt+letter shortcuts
0446     tabText.replace(QLatin1Char('&'), QLatin1String("&&"));
0447 
0448     if (WebTab* tab = webTab(index)) {
0449         if (tab->isPinned()) {
0450             tabText.clear();
0451         }
0452     }
0453 
0454     setTabToolTip(index, text);
0455     ComboTabBar::setTabText(index, tabText);
0456 }
0457 
0458 void TabBar::tabInserted(int index)
0459 {
0460     Q_UNUSED(index)
0461 
0462     // Initialize pinned tab metrics
0463     if (tabMetrics()->pinnedWidth() == -1) {
0464         QTimer::singleShot(0, this, [this]() {
0465             if (tabMetrics()->pinnedWidth() != -1) {
0466                 return;
0467             }
0468             QWidget *w = tabButton(0, iconButtonPosition());
0469             if (w && w->parentWidget()) {
0470                 const QRect wg = w->parentWidget()->geometry();
0471                 const QRect wr = QStyle::visualRect(layoutDirection(), wg, w->geometry());
0472                 tabMetrics()->setPinnedWidth(iconButtonSize().width() + wr.x() * 2);
0473                 setUpLayout();
0474             }
0475         });
0476     }
0477 
0478     setVisible(!(count() <= 1 && m_hideTabBarWithOneTab));
0479 }
0480 
0481 void TabBar::tabRemoved(int index)
0482 {
0483     Q_UNUSED(index)
0484 
0485     showCloseButton(currentIndex());
0486     setVisible(!(count() <= 1 && m_hideTabBarWithOneTab));
0487 
0488     // Make sure to move add tab button to correct position when there are no normal tabs
0489     if (normalTabsCount() == 0) {
0490         int xForAddTabButton = cornerWidth(Qt::TopLeftCorner) + pinTabBarWidth();
0491         if (QApplication::layoutDirection() == Qt::RightToLeft)
0492             xForAddTabButton = width() - xForAddTabButton;
0493         Q_EMIT moveAddTabButton(xForAddTabButton);
0494     }
0495 }
0496 
0497 void TabBar::mouseDoubleClickEvent(QMouseEvent* event)
0498 {
0499     if (mApp->plugins()->processMouseDoubleClick(Qz::ON_TabBar, this, event)) {
0500         return;
0501     }
0502 
0503     if (event->buttons() == Qt::LeftButton && emptyArea(event->position().toPoint())) {
0504         m_tabWidget->addView(QUrl(), Qz::NT_SelectedTabAtTheEnd, true);
0505         return;
0506     }
0507 
0508     ComboTabBar::mouseDoubleClickEvent(event);
0509 }
0510 
0511 void TabBar::mousePressEvent(QMouseEvent* event)
0512 {
0513     ComboTabBar::mousePressEvent(event);
0514 
0515     if (mApp->plugins()->processMousePress(Qz::ON_TabBar, this, event)) {
0516         return;
0517     }
0518 
0519     if (event->buttons() == Qt::LeftButton && !emptyArea(event->position().toPoint())) {
0520         m_dragStartPosition = event->position().toPoint();
0521     } else {
0522         m_dragStartPosition = QPoint();
0523     }
0524 }
0525 
0526 void TabBar::mouseMoveEvent(QMouseEvent* event)
0527 {
0528     ComboTabBar::mouseMoveEvent(event);
0529 
0530     if (mApp->plugins()->processMouseMove(Qz::ON_TabBar, this, event)) {
0531         return;
0532     }
0533 
0534     if (count() == 1 && mApp->windowCount() == 1) {
0535         return;
0536     }
0537 
0538     if (!m_dragStartPosition.isNull()) {
0539         int offset = 0;
0540         const int eventY = event->position().toPoint().y();
0541         if (eventY < 0) {
0542             offset = qAbs(eventY);
0543         } else if (eventY > height()) {
0544             offset = eventY - height();
0545         }
0546         if (offset > QApplication::startDragDistance() * 3) {
0547             const QPoint global = mapToGlobal(m_dragStartPosition);
0548             QWidget *w = QApplication::widgetAt(global);
0549             if (w) {
0550                 QMouseEvent mouse(QEvent::MouseButtonRelease, event->position(), w->mapFromGlobal(global), Qt::LeftButton, Qt::LeftButton, event->modifiers());
0551                 QApplication::sendEvent(w, &mouse);
0552             }
0553             auto *drag = new QDrag(this);
0554             auto *mime = new QMimeData;
0555             mime->setData(MIMETYPE, QByteArray());
0556             drag->setMimeData(mime);
0557             drag->setPixmap(tabPixmap(currentIndex()));
0558             if (drag->exec() == Qt::IgnoreAction) {
0559                 m_tabWidget->detachTab(currentIndex());
0560             }
0561             return;
0562         }
0563     }
0564 }
0565 
0566 void TabBar::mouseReleaseEvent(QMouseEvent* event)
0567 {
0568     ComboTabBar::mouseReleaseEvent(event);
0569 
0570     m_dragStartPosition = QPoint();
0571 
0572     if (mApp->plugins()->processMouseRelease(Qz::ON_TabBar, this, event)) {
0573         return;
0574     }
0575 
0576     if (!rect().contains(event->position().toPoint())) {
0577         ComboTabBar::mouseReleaseEvent(event);
0578         return;
0579     }
0580 
0581     if (event->button() == Qt::MiddleButton) {
0582         if (emptyArea(event->position().toPoint())) {
0583             m_tabWidget->addView(QUrl(), Qz::NT_SelectedTabAtTheEnd, true);
0584             return;
0585         }
0586 
0587         int id = tabAt(event->position().toPoint());
0588         if (id != -1) {
0589             m_tabWidget->requestCloseTab(id);
0590             return;
0591         }
0592     }
0593 }
0594 
0595 void TabBar::wheelEvent(QWheelEvent* event)
0596 {
0597     if (mApp->plugins()->processWheelEvent(Qz::ON_TabBar, this, event)) {
0598         return;
0599     }
0600 
0601     ComboTabBar::wheelEvent(event);
0602 }
0603 
0604 enum TabDropAction {
0605     NoAction,
0606     SelectTab,
0607     PrependTab,
0608     AppendTab
0609 };
0610 
0611 static TabDropAction tabDropAction(const QPoint &pos, const QRect &tabRect, bool allowSelect)
0612 {
0613     if (!tabRect.contains(pos)) {
0614         return NoAction;
0615     }
0616 
0617     const QPoint c = tabRect.center();
0618     const QSize csize = QSize(tabRect.width() * 0.7, tabRect.height() * 0.7);
0619     const QRect center(c.x() - csize.width() / 2, c.y() - csize.height() / 2, csize.width(), csize.height());
0620 
0621     if (allowSelect && center.contains(pos)) {
0622         return SelectTab;
0623     } else if (pos.x() < c.x()) {
0624         return PrependTab;
0625     } else {
0626         return AppendTab;
0627     }
0628 }
0629 
0630 void TabBar::dragEnterEvent(QDragEnterEvent* event)
0631 {
0632     const QMimeData* mime = event->mimeData();
0633 
0634     if (mime->hasText() || mime->hasUrls() || (mime->hasFormat(MIMETYPE) && event->source())) {
0635         event->acceptProposedAction();
0636         return;
0637     }
0638 
0639     ComboTabBar::dragEnterEvent(event);
0640 }
0641 
0642 void TabBar::dragMoveEvent(QDragMoveEvent *event)
0643 {
0644     const int index = tabAt(event->position().toPoint());
0645     const QMimeData* mime = event->mimeData();
0646 
0647     if (index == -1) {
0648         ComboTabBar::dragMoveEvent(event);
0649         return;
0650     }
0651 
0652     switch (tabDropAction(event->position().toPoint(), tabRect(index), !mime->hasFormat(MIMETYPE))) {
0653     case PrependTab:
0654         showDropIndicator(index, BeforeTab);
0655         break;
0656     case AppendTab:
0657         showDropIndicator(index, AfterTab);
0658         break;
0659     default:
0660         clearDropIndicator();
0661         break;
0662     }
0663 }
0664 
0665 void TabBar::dragLeaveEvent(QDragLeaveEvent *event)
0666 {
0667     clearDropIndicator();
0668 
0669     ComboTabBar::dragLeaveEvent(event);
0670 }
0671 
0672 void TabBar::dropEvent(QDropEvent* event)
0673 {
0674     clearDropIndicator();
0675 
0676     const QMimeData* mime = event->mimeData();
0677 
0678     if (!mime->hasText() && !mime->hasUrls() && !mime->hasFormat(MIMETYPE)) {
0679         ComboTabBar::dropEvent(event);
0680         return;
0681     }
0682 
0683     event->acceptProposedAction();
0684 
0685     auto *sourceTabBar = qobject_cast<TabBar*>(event->source());
0686 
0687     int index = tabAt(event->position().toPoint());
0688     if (index == -1) {
0689         if (mime->hasUrls()) {
0690             const auto urls = mime->urls();
0691             for (const QUrl &url : urls) {
0692                 m_tabWidget->addView(url, Qz::NT_SelectedTabAtTheEnd);
0693             }
0694         } else if (mime->hasText()) {
0695             m_tabWidget->addView(mApp->searchEnginesManager()->searchResult(mime->text()), Qz::NT_SelectedNewEmptyTab);
0696         } else if (mime->hasFormat(MIMETYPE) && sourceTabBar) {
0697             WebTab *tab = sourceTabBar->webTab();
0698             if (tab) {
0699                 sourceTabBar->m_tabWidget->detachTab(tab);
0700                 tab->setPinned(false);
0701                 m_tabWidget->addView(tab, Qz::NT_SelectedTab);
0702             }
0703         }
0704     } else {
0705         LoadRequest req;
0706         WebTab* tab = m_tabWidget->webTab(index);
0707         TabDropAction action = tabDropAction(event->position().toPoint(), tabRect(index), !mime->hasFormat(MIMETYPE));
0708         if (mime->hasUrls()) {
0709             req = mime->urls().at(0);
0710         } else if (mime->hasText()) {
0711             req = mApp->searchEnginesManager()->searchResult(mime->text());
0712         }
0713         if (action == SelectTab) {
0714             if (req.isValid()) {
0715                 tab->load(req);
0716             }
0717         } else if (action == PrependTab || action == AppendTab) {
0718             const int newIndex = action == PrependTab ? index : index + 1;
0719             if (req.isValid()) {
0720                 m_tabWidget->addView(req, QString(), Qz::NT_SelectedNewEmptyTab, false, newIndex, index < pinnedTabsCount());
0721             } else if (mime->hasFormat(MIMETYPE) && sourceTabBar) {
0722                 WebTab *tab = sourceTabBar->webTab();
0723                 if (tab) {
0724                     if (sourceTabBar == this) {
0725                         tab->moveTab(newIndex > tab->tabIndex() ? newIndex - 1 : newIndex);
0726                     } else {
0727                         sourceTabBar->m_tabWidget->detachTab(tab);
0728                         tab->setPinned(index < pinnedTabsCount());
0729                         m_tabWidget->insertView(newIndex, tab, Qz::NT_SelectedTab);
0730                     }
0731                 }
0732             }
0733         }
0734     }
0735 }
0736 
0737 void TabBar::setIsRestoring(bool restoring)
0738 {
0739     m_isRestoring = restoring;
0740 }
0741 
0742 bool TabBar::isRestoring()
0743 {
0744     return m_isRestoring;
0745 }
0746 
0747 #include "tabbar.moc"