diff --git a/src/lib/tabwidget/tabwidget.cpp b/src/lib/tabwidget/tabwidget.cpp index eed51134..87d93211 100644 --- a/src/lib/tabwidget/tabwidget.cpp +++ b/src/lib/tabwidget/tabwidget.cpp @@ -1,846 +1,853 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2017 David Rosca * * 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #include "tabwidget.h" #include "tabbar.h" #include "tabbedwebview.h" #include "webpage.h" #include "browserwindow.h" #include "mainapplication.h" #include "webtab.h" #include "clickablelabel.h" #include "closedtabsmanager.h" #include "locationbar.h" #include "settings.h" #include "datapaths.h" #include "qzsettings.h" #include "qztools.h" #include "tabicon.h" #include #include #include #include #include #include #include AddTabButton::AddTabButton(TabWidget* tabWidget, TabBar* tabBar) : ToolButton(tabBar) , m_tabBar(tabBar) , m_tabWidget(tabWidget) { setObjectName("tabwidget-button-addtab"); setAutoRaise(true); setFocusPolicy(Qt::NoFocus); setAcceptDrops(true); setToolTip(TabWidget::tr("New Tab")); } void AddTabButton::wheelEvent(QWheelEvent* event) { m_tabBar->wheelEvent(event); } void AddTabButton::mouseReleaseEvent(QMouseEvent* event) { if (event->button() == Qt::MiddleButton && rect().contains(event->pos())) { m_tabWidget->addTabFromClipboard(); } ToolButton::mouseReleaseEvent(event); } void AddTabButton::dragEnterEvent(QDragEnterEvent* event) { const QMimeData* mime = event->mimeData(); if (mime->hasUrls()) { event->acceptProposedAction(); return; } ToolButton::dragEnterEvent(event); } void AddTabButton::dropEvent(QDropEvent* event) { const QMimeData* mime = event->mimeData(); if (!mime->hasUrls()) { ToolButton::dropEvent(event); return; } foreach (const QUrl &url, mime->urls()) { m_tabWidget->addView(url, Qz::NT_SelectedNewEmptyTab); } } void MenuTabs::mouseReleaseEvent(QMouseEvent* event) { if (event->button() == Qt::MiddleButton) { QAction* action = actionAt(event->pos()); if (action && action->isEnabled()) { WebTab* tab = qobject_cast(qvariant_cast(action->data())); if (tab) { emit closeTab(tab->tabIndex()); action->setEnabled(false); event->accept(); } } } QMenu::mouseReleaseEvent(event); } TabWidget::TabWidget(BrowserWindow* window, QWidget* parent) : TabStackedWidget(parent) , m_window(window) , m_locationBars(new QStackedWidget) , m_closedTabsManager(new ClosedTabsManager) , m_lastTabIndex(-1) , m_lastBackgroundTabIndex(-1) { setObjectName(QSL("tabwidget")); m_tabBar = new TabBar(m_window, this); setTabBar(m_tabBar); connect(this, SIGNAL(currentChanged(int)), m_window, SLOT(refreshHistory())); connect(this, &TabWidget::changed, mApp, &MainApplication::changeOccurred); connect(this, &TabStackedWidget::pinStateChanged, this, &TabWidget::changed); connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(requestCloseTab(int))); connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int))); connect(m_tabBar, SIGNAL(moveAddTabButton(int)), this, SLOT(moveAddTabButton(int))); connect(mApp, SIGNAL(settingsReloaded()), this, SLOT(loadSettings())); m_menuTabs = new MenuTabs(this); connect(m_menuTabs, SIGNAL(closeTab(int)), this, SLOT(requestCloseTab(int))); m_menuClosedTabs = new QMenu(this); // AddTab button displayed next to last tab m_buttonAddTab = new AddTabButton(this, m_tabBar); connect(m_buttonAddTab, SIGNAL(clicked()), m_window, SLOT(addTab())); // AddTab button displayed outside tabbar (as corner widget) m_buttonAddTab2 = new AddTabButton(this, m_tabBar); m_buttonAddTab2->setProperty("outside-tabbar", true); m_buttonAddTab2->hide(); connect(m_buttonAddTab2, SIGNAL(clicked()), m_window, SLOT(addTab())); // ClosedTabs button displayed as a permanent corner widget m_buttonClosedTabs = new ToolButton(m_tabBar); m_buttonClosedTabs->setObjectName("tabwidget-button-closedtabs"); m_buttonClosedTabs->setMenu(m_menuClosedTabs); m_buttonClosedTabs->setPopupMode(QToolButton::InstantPopup); m_buttonClosedTabs->setToolTip(tr("Closed tabs")); m_buttonClosedTabs->setAutoRaise(true); m_buttonClosedTabs->setFocusPolicy(Qt::NoFocus); m_buttonClosedTabs->setShowMenuInside(true); connect(m_buttonClosedTabs, SIGNAL(aboutToShowMenu()), this, SLOT(aboutToShowClosedTabsMenu())); // ListTabs button is showed only when tabbar overflows m_buttonListTabs = new ToolButton(m_tabBar); m_buttonListTabs->setObjectName("tabwidget-button-opentabs"); m_buttonListTabs->setMenu(m_menuTabs); m_buttonListTabs->setPopupMode(QToolButton::InstantPopup); m_buttonListTabs->setToolTip(tr("List of tabs")); m_buttonListTabs->setAutoRaise(true); m_buttonListTabs->setFocusPolicy(Qt::NoFocus); m_buttonListTabs->setShowMenuInside(true); m_buttonListTabs->hide(); connect(m_buttonListTabs, SIGNAL(aboutToShowMenu()), this, SLOT(aboutToShowTabsMenu())); m_tabBar->addCornerWidget(m_buttonAddTab2, Qt::TopRightCorner); m_tabBar->addCornerWidget(m_buttonClosedTabs, Qt::TopRightCorner); m_tabBar->addCornerWidget(m_buttonListTabs, Qt::TopRightCorner); connect(m_tabBar, SIGNAL(overFlowChanged(bool)), this, SLOT(tabBarOverFlowChanged(bool))); loadSettings(); } void TabWidget::loadSettings() { Settings settings; settings.beginGroup("Browser-Tabs-Settings"); m_dontCloseWithOneTab = settings.value("dontCloseWithOneTab", false).toBool(); m_showClosedTabsButton = settings.value("showClosedTabsButton", false).toBool(); m_newTabAfterActive = settings.value("newTabAfterActive", true).toBool(); m_newEmptyTabAfterActive = settings.value("newEmptyTabAfterActive", false).toBool(); settings.endGroup(); settings.beginGroup("Web-URL-Settings"); m_urlOnNewTab = settings.value("newTabUrl", "falkon:speeddial").toUrl(); settings.endGroup(); m_tabBar->loadSettings(); updateClosedTabsButton(); } WebTab* TabWidget::weTab() { return weTab(currentIndex()); } WebTab* TabWidget::weTab(int index) { return qobject_cast(widget(index)); } TabIcon* TabWidget::tabIcon(int index) { return weTab(index)->tabIcon(); } bool TabWidget::validIndex(int index) const { return index >= 0 && index < count(); } void TabWidget::updateClosedTabsButton() { if (!m_showClosedTabsButton) { m_buttonClosedTabs->hide(); } m_buttonClosedTabs->setEnabled(canRestoreTab()); } bool TabWidget::isCurrentTabFresh() const { return m_currentTabFresh; } void TabWidget::setCurrentTabFresh(bool currentTabFresh) { m_currentTabFresh = currentTabFresh; } void TabWidget::tabBarOverFlowChanged(bool overflowed) { // Show buttons inside tabbar m_buttonAddTab->setVisible(!overflowed); // Show buttons displayed outside tabbar (corner widgets) m_buttonAddTab2->setVisible(overflowed); m_buttonListTabs->setVisible(overflowed); m_buttonClosedTabs->setVisible(m_showClosedTabsButton); } void TabWidget::moveAddTabButton(int posX) { int posY = (m_tabBar->height() - m_buttonAddTab->height()) / 2; if (QApplication::layoutDirection() == Qt::RightToLeft) { posX = qMax(posX - m_buttonAddTab->width(), 0); } else { posX = qMin(posX, m_tabBar->width() - m_buttonAddTab->width()); } m_buttonAddTab->move(posX, posY); } void TabWidget::aboutToShowTabsMenu() { m_menuTabs->clear(); for (int i = 0; i < count(); i++) { WebTab* tab = weTab(i); if (!tab || tab->isPinned()) { continue; } QAction* action = new QAction(this); action->setIcon(tab->icon()); if (i == currentIndex()) { QFont f = action->font(); f.setBold(true); action->setFont(f); } QString title = tab->title(); title.replace(QLatin1Char('&'), QLatin1String("&&")); action->setText(QzTools::truncatedText(title, 40)); action->setData(QVariant::fromValue(qobject_cast(tab))); connect(action, SIGNAL(triggered()), this, SLOT(actionChangeIndex())); m_menuTabs->addAction(action); } } void TabWidget::aboutToShowClosedTabsMenu() { m_menuClosedTabs->clear(); int i = 0; const QLinkedList closedTabs = closedTabsManager()->allClosedTabs(); foreach (const ClosedTabsManager::Tab &tab, closedTabs) { const QString title = QzTools::truncatedText(tab.title, 40); QAction* act = m_menuClosedTabs->addAction(tab.icon, title, this, SLOT(restoreClosedTab())); act->setData(i++); } if (m_menuClosedTabs->isEmpty()) { m_menuClosedTabs->addAction(tr("Empty"))->setEnabled(false); } else { m_menuClosedTabs->addSeparator(); m_menuClosedTabs->addAction(tr("Restore All Closed Tabs"), this, SLOT(restoreAllClosedTabs())); m_menuClosedTabs->addAction(tr("Clear list"), this, SLOT(clearClosedTabsList())); } } void TabWidget::actionChangeIndex() { if (QAction* action = qobject_cast(sender())) { WebTab* tab = qobject_cast(qvariant_cast(action->data())); if (tab) { m_tabBar->ensureVisible(tab->tabIndex()); setCurrentIndex(tab->tabIndex()); } } } int TabWidget::addView(const LoadRequest &req, const Qz::NewTabPositionFlags &openFlags, bool selectLine, bool pinned) { return addView(req, QString(), openFlags, selectLine, -1, pinned); } int TabWidget::addView(const LoadRequest &req, const QString &title, const Qz::NewTabPositionFlags &openFlags, bool selectLine, int position, bool pinned) { QUrl url = req.url(); m_lastTabIndex = currentIndex(); m_currentTabFresh = false; if (url.isEmpty() && !(openFlags & Qz::NT_CleanTab)) { url = m_urlOnNewTab; } bool openAfterActive = m_newTabAfterActive && !(openFlags & Qz::NT_TabAtTheEnd); if (openFlags == Qz::NT_SelectedNewEmptyTab && m_newEmptyTabAfterActive) { openAfterActive = true; } if (openAfterActive && position == -1) { // If we are opening newBgTab from pinned tab, make sure it won't be // opened between other pinned tabs if (openFlags & Qz::NT_NotSelectedTab && m_lastBackgroundTabIndex != -1) { position = m_lastBackgroundTabIndex + 1; } else { position = qMax(currentIndex() + 1, m_tabBar->pinnedTabsCount()); } } WebTab* webTab = new WebTab(m_window); webTab->locationBar()->showUrl(url); m_locationBars->addWidget(webTab->locationBar()); int index = insertTab(position == -1 ? count() : position, webTab, QString(), pinned); webTab->attach(m_window); if (!title.isEmpty()) { m_tabBar->setTabText(index, title); } if (openFlags & Qz::NT_SelectedTab) { setCurrentIndex(index); } else { m_lastBackgroundTabIndex = index; } connect(webTab->webView(), SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); connect(webTab->webView(), SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); connect(webTab->webView(), SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); connect(webTab->webView(), &WebView::urlChanged, this, [this](const QUrl &url) { if (url != m_urlOnNewTab) m_currentTabFresh = false; }); if (url.isValid() && url != req.url()) { LoadRequest r(req); r.setUrl(url); webTab->webView()->load(r); } else if (req.url().isValid()) { webTab->webView()->load(req); } if (selectLine && m_window->locationBar()->text().isEmpty()) { m_window->locationBar()->setFocus(); } // Make sure user notice opening new background tabs if (!(openFlags & Qz::NT_SelectedTab)) { m_tabBar->ensureVisible(index); } emit changed(); return index; } int TabWidget::addView(WebTab* tab) { m_locationBars->addWidget(tab->locationBar()); int index = addTab(tab, QString()); tab->attach(m_window); connect(tab->webView(), SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); connect(tab->webView(), SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); connect(tab->webView(), SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); return index; } void TabWidget::addTabFromClipboard() { QString selectionClipboard = QApplication::clipboard()->text(QClipboard::Selection); QUrl guessedUrl = QUrl::fromUserInput(selectionClipboard); if (!guessedUrl.isEmpty()) { addView(guessedUrl, Qz::NT_SelectedNewEmptyTab); } } void TabWidget::closeTab(int index) { if (index == -1) index = currentIndex(); WebTab *webTab = weTab(index); if (!webTab || !validIndex(index)) return; TabbedWebView *webView = webTab->webView(); // Save tab url and history if (webView->url().toString() != QL1S("falkon:restore")) m_closedTabsManager->saveTab(webTab, index); m_locationBars->removeWidget(webView->webTab()->locationBar()); disconnect(webView, SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); disconnect(webView, SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); disconnect(webView, SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); m_lastBackgroundTabIndex = -1; if (m_menuTabs->isVisible()) { QAction* labelAction = m_menuTabs->actions().last(); //~ singular Currently you have %n opened tab //~ plural Currently you have %n opened tabs labelAction->setText(tr("Currently you have %n opened tab(s)", "", count() - 1)); } removeTab(index); webTab->deleteLater(); updateClosedTabsButton(); emit changed(); } void TabWidget::requestCloseTab(int index) { if (index == -1) index = currentIndex(); WebTab *webTab = weTab(index); if (!webTab || !validIndex(index)) return; TabbedWebView *webView = webTab->webView(); // Don't close restore page! if (webView->url().toString() == QL1S("falkon:restore") && mApp->restoreManager()) return; // This would close last tab, so we close the window instead if (count() == 1) { // If we are not closing window upon closing last tab, let's just load new-tab-url if (m_dontCloseWithOneTab) { if (webView->url() == m_urlOnNewTab) { // We don't want to accumulate more than one closed tab, if user tries // to close the last tab multiple times m_closedTabsManager->takeLastClosedTab(); } webView->load(m_urlOnNewTab); return; } m_window->close(); return; } webView->triggerPageAction(QWebEnginePage::RequestClose); } void TabWidget::currentTabChanged(int index) { if (!validIndex(index)) return; m_lastBackgroundTabIndex = -1; m_lastTabIndex = index; m_currentTabFresh = false; WebTab* webTab = weTab(index); webTab->tabActivated(); LocationBar* locBar = webTab->locationBar(); if (locBar && m_locationBars->indexOf(locBar) != -1) { m_locationBars->setCurrentWidget(locBar); } m_window->currentTabChanged(); emit changed(); } void TabWidget::tabMoved(int before, int after) { Q_UNUSED(before) Q_UNUSED(after) m_lastBackgroundTabIndex = -1; m_lastTabIndex = before; emit changed(); } void TabWidget::setCurrentIndex(int index) { m_lastTabIndex = currentIndex(); TabStackedWidget::setCurrentIndex(index); } void TabWidget::nextTab() { QKeyEvent fakeEvent(QKeyEvent::KeyPress, Qt::Key_Tab, Qt::ControlModifier); keyPressEvent(&fakeEvent); } void TabWidget::previousTab() { QKeyEvent fakeEvent(QKeyEvent::KeyPress, Qt::Key_Backtab, QFlags(Qt::ControlModifier + Qt::ShiftModifier)); keyPressEvent(&fakeEvent); } int TabWidget::normalTabsCount() const { return m_tabBar->normalTabsCount(); } int TabWidget::pinnedTabsCount() const { return m_tabBar->pinnedTabsCount(); } void TabWidget::reloadTab(int index) { if (!validIndex(index)) { return; } weTab(index)->reload(); } int TabWidget::lastTabIndex() const { return m_lastTabIndex; } int TabWidget::extraReservedWidth() const { return m_buttonAddTab->width(); } TabBar* TabWidget::tabBar() const { return m_tabBar; } ClosedTabsManager* TabWidget::closedTabsManager() const { return m_closedTabsManager; } void TabWidget::reloadAllTabs() { for (int i = 0; i < count(); i++) { reloadTab(i); } } void TabWidget::stopTab(int index) { if (!validIndex(index)) { return; } weTab(index)->stop(); } void TabWidget::closeAllButCurrent(int index) { if (!validIndex(index)) { return; } WebTab* akt = weTab(index); foreach (WebTab* tab, allTabs(false)) { int tabIndex = tab->tabIndex(); if (akt == widget(tabIndex)) { continue; } requestCloseTab(tabIndex); } } void TabWidget::closeToRight(int index) { if (!validIndex(index)) { return; } foreach (WebTab* tab, allTabs(false)) { int tabIndex = tab->tabIndex(); if (index >= tabIndex) { continue; } requestCloseTab(tabIndex); } } void TabWidget::closeToLeft(int index) { if (!validIndex(index)) { return; } foreach (WebTab* tab, allTabs(false)) { int tabIndex = tab->tabIndex(); if (index <= tabIndex) { continue; } requestCloseTab(tabIndex); } } -void TabWidget::detachTab(int index) +void TabWidget::detachTab(WebTab* tab) { - WebTab* tab = weTab(index); - - if (tab->isPinned() || count() == 1) { - return; - } + Q_ASSERT(tab); m_locationBars->removeWidget(tab->locationBar()); disconnect(tab->webView(), SIGNAL(wantsCloseTab(int)), this, SLOT(closeTab(int))); disconnect(tab->webView(), SIGNAL(urlChanged(QUrl)), this, SIGNAL(changed())); disconnect(tab->webView(), SIGNAL(ipChanged(QString)), m_window->ipLabel(), SLOT(setText(QString))); tab->detach(); +} + +void TabWidget::detachTab(int index) +{ + WebTab* tab = weTab(index); + + if (tab->isPinned() || count() == 1) { + return; + } + + detachTab(tab); BrowserWindow* window = mApp->createWindow(Qz::BW_NewWindow); window->setStartTab(tab); } int TabWidget::duplicateTab(int index) { if (!validIndex(index)) { return -1; } WebTab* webTab = weTab(index); int id = addView(QUrl(), webTab->title(), Qz::NT_CleanNotSelectedTab); weTab(id)->p_restoreTab(webTab->url(), webTab->historyData(), webTab->zoomLevel()); return id; } void TabWidget::restoreClosedTab(QObject* obj) { if (!obj) { obj = sender(); } if (!m_closedTabsManager->isClosedTabAvailable()) { return; } ClosedTabsManager::Tab tab; QAction* action = qobject_cast(obj); if (action && action->data().toInt() != 0) { tab = m_closedTabsManager->takeTabAt(action->data().toInt()); } else { tab = m_closedTabsManager->takeLastClosedTab(); } if (tab.position < 0) { return; } int index = addView(QUrl(), tab.title, Qz::NT_CleanSelectedTab, false, tab.position); WebTab* webTab = weTab(index); webTab->p_restoreTab(tab.url, tab.history, tab.zoomLevel); updateClosedTabsButton(); } void TabWidget::restoreAllClosedTabs() { if (!m_closedTabsManager->isClosedTabAvailable()) { return; } const QLinkedList &closedTabs = m_closedTabsManager->allClosedTabs(); foreach (const ClosedTabsManager::Tab &tab, closedTabs) { int index = addView(QUrl(), tab.title, Qz::NT_CleanSelectedTab); WebTab* webTab = weTab(index); webTab->p_restoreTab(tab.url, tab.history, tab.zoomLevel); } clearClosedTabsList(); } void TabWidget::clearClosedTabsList() { m_closedTabsManager->clearList(); updateClosedTabsButton(); } bool TabWidget::canRestoreTab() const { return m_closedTabsManager->isClosedTabAvailable(); } QStackedWidget* TabWidget::locationBars() const { return m_locationBars; } ToolButton* TabWidget::buttonClosedTabs() const { return m_buttonClosedTabs; } AddTabButton* TabWidget::buttonAddTab() const { return m_buttonAddTab; } QList TabWidget::allTabs(bool withPinned) { QList allTabs; for (int i = 0; i < count(); i++) { WebTab* tab = weTab(i); if (!tab || (!withPinned && tab->isPinned())) { continue; } allTabs.append(tab); } return allTabs; } QByteArray TabWidget::saveState() { int currentTabIndex = 0; QVector tabList; for (int i = 0; i < count(); ++i) { WebTab* webTab = weTab(i); if (!webTab) continue; WebTab::SavedTab tab(webTab); if (!tab.isValid()) continue; tabList.append(tab); if (webTab->isCurrentTab()) currentTabIndex = tabList.size() - 1; } QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << tabList.count(); foreach (const WebTab::SavedTab &tab, tabList) { stream << tab; } stream << currentTabIndex; return data; } bool TabWidget::restoreState(const QVector &tabs, int currentTab) { for (int i = 0; i < tabs.size(); ++i) { WebTab::SavedTab tab = tabs.at(i); int index = addView(QUrl(), Qz::NT_CleanSelectedTab, false, tab.isPinned); weTab(index)->restoreTab(tab); if (tab.isPinned) m_tabBar->updatePinnedTabCloseButton(index); } setCurrentIndex(currentTab); QTimer::singleShot(0, m_tabBar, SLOT(ensureVisible(int,int))); // WebTab is restoring state on showEvent weTab()->hide(); weTab()->show(); return true; } void TabWidget::closeRecoveryTab() { foreach (WebTab* tab, allTabs(false)) { if (tab->url().toString() == QLatin1String("falkon:restore")) { closeTab(tab->tabIndex()); } } } TabWidget::~TabWidget() { delete m_closedTabsManager; } diff --git a/src/lib/tabwidget/tabwidget.h b/src/lib/tabwidget/tabwidget.h index f5c267a8..5427d876 100644 --- a/src/lib/tabwidget/tabwidget.h +++ b/src/lib/tabwidget/tabwidget.h @@ -1,172 +1,174 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2010-2014 David Rosca +* Copyright (C) 2010-2017 David Rosca * * 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #ifndef TABWIDGET_H #define TABWIDGET_H #include #include #include "tabstackedwidget.h" #include "toolbutton.h" #include "loadrequest.h" #include "webtab.h" #include "qzcommon.h" class QMenu; class TabBar; class TabIcon; class TabWidget; class BrowserWindow; class TabbedWebView; class ClosedTabsManager; class FALKON_EXPORT AddTabButton : public ToolButton { public: explicit AddTabButton(TabWidget* tabWidget, TabBar* tabBar); private: void wheelEvent(QWheelEvent* event); void mouseReleaseEvent(QMouseEvent* event); void dragEnterEvent(QDragEnterEvent* event); void dropEvent(QDropEvent* event); TabBar* m_tabBar; TabWidget* m_tabWidget; }; class FALKON_EXPORT MenuTabs : public QMenu { Q_OBJECT public: explicit MenuTabs(QWidget* parent = 0) : QMenu(parent) {} signals: void closeTab(int); private: void mouseReleaseEvent(QMouseEvent* event); }; class FALKON_EXPORT TabWidget : public TabStackedWidget { Q_OBJECT public: explicit TabWidget(BrowserWindow* mainclass, QWidget* parent = 0); ~TabWidget(); QByteArray saveState(); bool restoreState(const QVector &tabs, int currentTab); void closeRecoveryTab(); void setCurrentIndex(int index); void nextTab(); void previousTab(); void currentTabChanged(int index); int normalTabsCount() const; int pinnedTabsCount() const; int lastTabIndex() const; int extraReservedWidth() const; TabBar* tabBar() const; ClosedTabsManager* closedTabsManager() const; QList allTabs(bool withPinned = true); bool canRestoreTab() const; bool isCurrentTabFresh() const; void setCurrentTabFresh(bool currentTabFresh); QStackedWidget* locationBars() const; ToolButton* buttonClosedTabs() const; AddTabButton* buttonAddTab() const; + void detachTab(WebTab* tab); + public slots: int addView(const LoadRequest &req, const Qz::NewTabPositionFlags &openFlags, bool selectLine = false, bool pinned = false); int addView(const LoadRequest &req, const QString &title = tr("New tab"), const Qz::NewTabPositionFlags &openFlags = Qz::NT_SelectedTab, bool selectLine = false, int position = -1, bool pinned = false); int addView(WebTab* tab); void addTabFromClipboard(); int duplicateTab(int index); // Force close tab void closeTab(int index = -1); // Request close tab (may be rejected) void requestCloseTab(int index = -1); void reloadTab(int index); void reloadAllTabs(); void stopTab(int index); void closeAllButCurrent(int index); void closeToRight(int index); void closeToLeft(int index); void detachTab(int index); void restoreClosedTab(QObject* obj = 0); void restoreAllClosedTabs(); void clearClosedTabsList(); void moveAddTabButton(int posX); void tabBarOverFlowChanged(bool overflowed); signals: void changed(); private slots: void loadSettings(); void aboutToShowTabsMenu(); void aboutToShowClosedTabsMenu(); void actionChangeIndex(); void tabMoved(int before, int after); private: WebTab* weTab(); WebTab* weTab(int index); TabIcon* tabIcon(int index); bool validIndex(int index) const; void updateClosedTabsButton(); BrowserWindow* m_window; TabBar* m_tabBar; QStackedWidget* m_locationBars; ClosedTabsManager* m_closedTabsManager; MenuTabs* m_menuTabs; ToolButton* m_buttonListTabs; QMenu* m_menuClosedTabs; ToolButton* m_buttonClosedTabs; AddTabButton* m_buttonAddTab; AddTabButton* m_buttonAddTab2; int m_lastTabIndex; int m_lastBackgroundTabIndex; bool m_dontCloseWithOneTab; bool m_showClosedTabsButton; bool m_newTabAfterActive; bool m_newEmptyTabAfterActive; QUrl m_urlOnNewTab; bool m_currentTabFresh; }; #endif // TABWIDGET_H diff --git a/src/plugins/TabManager/tabmanagerwidget.cpp b/src/plugins/TabManager/tabmanagerwidget.cpp index 61f51bea..385daa42 100644 --- a/src/plugins/TabManager/tabmanagerwidget.cpp +++ b/src/plugins/TabManager/tabmanagerwidget.cpp @@ -1,814 +1,809 @@ /* ============================================================ * TabManager plugin for Falkon * Copyright (C) 2013-2017 S. Razi Alavizadeh * * 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #include "tabmanagerwidget.h" #include "ui_tabmanagerwidget.h" #include "mainapplication.h" #include "browserwindow.h" #include "webtab.h" #include "webpage.h" #include "tabbedwebview.h" #include "tabwidget.h" #include "locationbar.h" #include "bookmarkstools.h" #include "bookmarkitem.h" #include "bookmarks.h" #include "tabmanagerplugin.h" #include "tldextractor/tldextractor.h" #include "tabmanagerdelegate.h" #include "tabcontextmenu.h" #include #include #include #include #include #include TLDExtractor* TabManagerWidget::s_tldExtractor = 0; TabManagerWidget::TabManagerWidget(BrowserWindow* mainClass, QWidget* parent, bool defaultWidget) : QWidget(parent) , ui(new Ui::TabManagerWidget) , m_window(mainClass) , m_webPage(0) , m_isRefreshing(false) , m_refreshBlocked(false) , m_waitForRefresh(false) , m_isDefaultWidget(defaultWidget) { if(s_tldExtractor == 0) { s_tldExtractor = TLDExtractor::instance(); s_tldExtractor->setDataSearchPaths(QStringList() << TabManagerPlugin::settingsPath()); } ui->setupUi(this); ui->treeWidget->setUniformRowHeights(true); ui->treeWidget->setColumnCount(2); ui->treeWidget->header()->hide(); ui->treeWidget->header()->setStretchLastSection(false); ui->treeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch); ui->treeWidget->header()->setSectionResizeMode(1, QHeaderView::Fixed); ui->treeWidget->header()->resizeSection(1, 16); ui->treeWidget->setExpandsOnDoubleClick(false); ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui->treeWidget->installEventFilter(this); ui->filterBar->installEventFilter(this); QPushButton* closeButton = new QPushButton(ui->filterBar); closeButton->setFlat(true); closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton)); ui->filterBar->addWidget(closeButton, LineEdit::RightSide); ui->filterBar->hide(); ui->treeWidget->setItemDelegate(new TabManagerDelegate(ui->treeWidget)); connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(filterBarClosed())); 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))); } TabManagerWidget::~TabManagerWidget() { delete ui; } void TabManagerWidget::setGroupType(GroupType type) { m_groupType = type; } QString TabManagerWidget::domainFromUrl(const QUrl &url, bool useHostName) { QString appendString = QL1S(":"); QString urlString = url.toString(); if (url.scheme() == "file") { return tr("Local File System:"); } else if (url.scheme() == "falkon" || urlString.isEmpty()) { return tr("Falkon:"); } else if (url.scheme() == "ftp") { appendString.prepend(tr(" [FTP]")); } QString host = url.host(); if (host.isEmpty()) { return urlString.append(appendString); } if (useHostName || host.contains(QRegExp("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$"))) { if (host.startsWith("www.", Qt::CaseInsensitive)) { host.remove(0, 4); } return host.append(appendString); } else { const QString registeredDomain = s_tldExtractor->registrableDomain(host); if (!registeredDomain.isEmpty()) { host = registeredDomain; } return host.append(appendString); } } void TabManagerWidget::delayedRefreshTree(WebPage* p) { if (m_refreshBlocked || m_waitForRefresh) { return; } if (m_isRefreshing && !p) { return; } m_webPage = p; m_waitForRefresh = true; QTimer::singleShot(50, this, SLOT(refreshTree())); } void TabManagerWidget::refreshTree() { if (m_refreshBlocked) { return; } if (m_isRefreshing && !m_webPage) { return; } // store selected items QList selectedTabs; for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* winItem = ui->treeWidget->topLevelItem(i); if (winItem->checkState(0) == Qt::Unchecked) { continue; } for (int j = 0; j < winItem->childCount(); ++j) { TabItem* tabItem = static_cast(winItem->child(j)); if (!tabItem || tabItem->checkState(0) == Qt::Unchecked) { continue; } selectedTabs << tabItem->webTab(); } } ui->treeWidget->clear(); QTreeWidgetItem* currentTabItem = nullptr; if (m_groupType == GroupByHost) { currentTabItem = groupByDomainName(true); } else if (m_groupType == GroupByDomain) { currentTabItem = groupByDomainName(); } else { // fallback to GroupByWindow m_groupType = GroupByWindow; currentTabItem = groupByWindow(); } // restore selected items for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* winItem = ui->treeWidget->topLevelItem(i); for (int j = 0; j < winItem->childCount(); ++j) { TabItem* tabItem = static_cast(winItem->child(j)); if (tabItem && selectedTabs.contains(tabItem->webTab())) { tabItem->setCheckState(0, Qt::Checked); } } } filterChanged(m_filterText, true); ui->treeWidget->expandAll(); if (currentTabItem) ui->treeWidget->scrollToItem(currentTabItem, QAbstractItemView::EnsureVisible); m_isRefreshing = false; m_waitForRefresh = false; } void TabManagerWidget::onItemActivated(QTreeWidgetItem* item, int column) { TabItem* tabItem = static_cast(item); if (!tabItem) { return; } BrowserWindow* mainWindow = tabItem->window(); QWidget* tabWidget = tabItem->webTab(); if (column == 1) { if (item->childCount() > 0) QMetaObject::invokeMethod(mainWindow ? mainWindow : mApp->getWindow(), "addTab"); else if (tabWidget && mainWindow) mainWindow->tabWidget()->requestCloseTab(mainWindow->tabWidget()->indexOf(tabWidget)); return; } if (!mainWindow) { return; } if (mainWindow->isMinimized()) { mainWindow->showNormal(); } else { mainWindow->show(); } mainWindow->activateWindow(); mainWindow->raise(); mainWindow->weView()->setFocus(); if (tabWidget && tabWidget != mainWindow->tabWidget()->currentWidget()) { mainWindow->tabWidget()->setCurrentIndex(mainWindow->tabWidget()->indexOf(tabWidget)); } } bool TabManagerWidget::isTabSelected() { bool selected = false; for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(i); if (parentItem->checkState(0) != Qt::Unchecked) { selected = true; break; } } return selected; } void TabManagerWidget::customContextMenuRequested(const QPoint &pos) { QMenu* menu = nullptr; TabItem* item = static_cast(ui->treeWidget->itemAt(pos)); if (item) { BrowserWindow* mainWindow = item->window(); QWidget* tabWidget = item->webTab(); if (mainWindow && tabWidget) { int index = mainWindow->tabWidget()->indexOf(tabWidget); // if items are not grouped by Window then actions "Close Other Tabs", // "Close Tabs To The Bottom" and "Close Tabs To The Top" // are ambiguous and should be hidden. menu = new TabContextMenu(index, Qt::Vertical, mainWindow, mainWindow->tabWidget(), m_groupType == GroupByWindow); menu->addSeparator(); } } if (!menu) menu = new QMenu; menu->setAttribute(Qt::WA_DeleteOnClose); QAction* action; QMenu groupTypeSubmenu(tr("Group by")); action = groupTypeSubmenu.addAction(tr("&Window"), this, SLOT(changeGroupType())); action->setData(GroupByWindow); action->setCheckable(true); action->setChecked(m_groupType == GroupByWindow); action = groupTypeSubmenu.addAction(tr("&Domain"), this, SLOT(changeGroupType())); action->setData(GroupByDomain); action->setCheckable(true); action->setChecked(m_groupType == GroupByDomain); action = groupTypeSubmenu.addAction(tr("&Host"), this, SLOT(changeGroupType())); action->setData(GroupByHost); action->setCheckable(true); action->setChecked(m_groupType == GroupByHost); menu->addMenu(&groupTypeSubmenu); if (m_isDefaultWidget) { menu->addAction(QIcon(":/tabmanager/data/side-by-side.png"), tr("&Show side by side"), this, SIGNAL(showSideBySide()))->setObjectName("sideBySide"); } menu->addSeparator(); if (isTabSelected()) { menu->addAction(QIcon(":/tabmanager/data/tab-detach.png"), tr("&Detach checked tabs"), this, SLOT(processActions()))->setObjectName("detachSelection"); menu->addAction(QIcon(":/tabmanager/data/tab-bookmark.png"), tr("Book&mark checked tabs"), this, SLOT(processActions()))->setObjectName("bookmarkSelection"); menu->addAction(QIcon(":/tabmanager/data/tab-close.png"), tr("&Close checked tabs"), this, SLOT(processActions()))->setObjectName("closeSelection"); } menu->exec(ui->treeWidget->viewport()->mapToGlobal(pos)); } void TabManagerWidget::filterChanged(const QString &filter, bool force) { if (force || filter != m_filterText) { m_filterText = filter.simplified(); ui->treeWidget->itemDelegate()->setProperty("filterText", m_filterText); if (m_filterText.isEmpty()) { for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(i); for (int j = 0; j < parentItem->childCount(); ++j) { QTreeWidgetItem* childItem = parentItem->child(j); childItem->setHidden(false); } parentItem->setHidden(false); parentItem->setExpanded(true); } return; } const QRegularExpression filterRegExp(filter.simplified().replace(QChar(' '), QLatin1String(".*")) .append(QLatin1String(".*")).prepend(QLatin1String(".*")), QRegularExpression::CaseInsensitiveOption); for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* parentItem = ui->treeWidget->topLevelItem(i); int visibleChildCount = 0; for (int j = 0; j < parentItem->childCount(); ++j) { TabItem* childItem = static_cast(parentItem->child(j)); if (!childItem) { continue; } if (childItem->text(0).contains(filterRegExp) || childItem->webTab()->url().toString().simplified().contains(filterRegExp)) { ++visibleChildCount; childItem->setHidden(false); } else { childItem->setHidden(true); } } if (visibleChildCount == 0) { parentItem->setHidden(true); } else { parentItem->setHidden(false); parentItem->setExpanded(true); } } } } void TabManagerWidget::filterBarClosed() { ui->filterBar->clear(); ui->filterBar->hide(); ui->treeWidget->setFocusProxy(0); ui->treeWidget->setFocus(); } bool TabManagerWidget::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); const QString text = keyEvent->text().simplified(); if (obj == ui->treeWidget) { // switch to tab/window on enter if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) { onItemActivated(ui->treeWidget->currentItem(), 0); return QObject::eventFilter(obj, event); } if (!text.isEmpty() || ((keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() == Qt::Key_F)) { ui->filterBar->show(); ui->treeWidget->setFocusProxy(ui->filterBar); ui->filterBar->setFocus(); if (!text.isEmpty() && text.at(0).isPrint()) { ui->filterBar->setText(ui->filterBar->text() + text); } return true; } } else if (obj == ui->filterBar) { bool isNavigationOrActionKey = keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_PageDown || keyEvent->key() == Qt::Key_PageUp || keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return; // send scroll or action press key to treeWidget if (isNavigationOrActionKey) { QKeyEvent ev(QKeyEvent::KeyPress, keyEvent->key(), keyEvent->modifiers()); QApplication::sendEvent(ui->treeWidget, &ev); return false; } } } if (obj == ui->treeWidget && (event->type() == QEvent::Resize || event->type() == QEvent::Show)) ui->treeWidget->setColumnHidden(1, ui->treeWidget->viewport()->width() < 150); return QObject::eventFilter(obj, event); } void TabManagerWidget::processActions() { if (!sender()) { return; } m_refreshBlocked = true; QHash selectedTabs; const QString &command = sender()->objectName(); for (int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { QTreeWidgetItem* winItem = ui->treeWidget->topLevelItem(i); if (winItem->checkState(0) == Qt::Unchecked) { continue; } for (int j = 0; j < winItem->childCount(); ++j) { TabItem* tabItem = static_cast(winItem->child(j)); if (!tabItem || tabItem->checkState(0) == Qt::Unchecked) { continue; } BrowserWindow* mainWindow = tabItem->window(); WebTab* webTab = tabItem->webTab(); // current supported actions are not applied to pinned tabs if (webTab->isPinned()) { tabItem->setCheckState(0, Qt::Unchecked); continue; } if (command == "closeSelection") { if (webTab->url().toString() == "falkon:restore") { continue; } selectedTabs.insertMulti(mainWindow, webTab); } else if (command == "detachSelection" || command == "bookmarkSelection") { selectedTabs.insertMulti(mainWindow, webTab); } } winItem->setCheckState(0, Qt::Unchecked); } if (!selectedTabs.isEmpty()) { if (command == "closeSelection") { closeSelectedTabs(selectedTabs); } else if (command == "detachSelection") { detachSelectedTabs(selectedTabs); } else if (command == "bookmarkSelection") { bookmarkSelectedTabs(selectedTabs); } } m_refreshBlocked = false; delayedRefreshTree(); } void TabManagerWidget::changeGroupType() { QAction* action = qobject_cast(sender()); if (action) { int type = action->data().toInt(); if (m_groupType != GroupType(type)) { m_groupType = GroupType(type); delayedRefreshTree(); emit groupTypeChanged(m_groupType); } } } void TabManagerWidget::closeSelectedTabs(const QHash &tabsHash) { if (tabsHash.isEmpty()) { return; } const QList &windows = tabsHash.uniqueKeys(); foreach (BrowserWindow* mainWindow, windows) { QList tabs = tabsHash.values(mainWindow); foreach (WebTab* webTab, tabs) { mainWindow->tabWidget()->requestCloseTab(webTab->tabIndex()); } } } void TabManagerWidget::detachSelectedTabs(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); foreach (WebTab* webTab, tabs) { - mainWindow->tabWidget()->locationBars()->removeWidget(webTab->locationBar()); + mainWindow->tabWidget()->detachTab(webTab); - disconnect(webTab->webView(), SIGNAL(wantsCloseTab(int)), mainWindow->tabWidget(), SLOT(closeTab(int))); - disconnect(webTab->webView(), SIGNAL(changed()), mainWindow->tabWidget(), SIGNAL(changed())); - disconnect(webTab->webView(), SIGNAL(ipChanged(QString)), mainWindow->ipLabel(), SLOT(setText(QString))); - - webTab->detach(); if (mainWindow && mainWindow->tabWidget()->count() == 0) { mainWindow->close(); mainWindow = 0; } newWindow->tabWidget()->addView(webTab); } } } bool TabManagerWidget::bookmarkSelectedTabs(const QHash &tabsHash) { QDialog* dialog = new QDialog(getWindow(), Qt::WindowStaysOnTopHint | Qt::MSWindowsFixedSizeDialogHint); QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, dialog); QLabel* label = new QLabel(dialog); BookmarksFoldersButton* folderButton = new BookmarksFoldersButton(dialog); QDialogButtonBox* box = new QDialogButtonBox(dialog); box->addButton(QDialogButtonBox::Ok); box->addButton(QDialogButtonBox::Cancel); QObject::connect(box, SIGNAL(rejected()), dialog, SLOT(reject())); QObject::connect(box, SIGNAL(accepted()), dialog, SLOT(accept())); layout->addWidget(label); layout->addWidget(folderButton); layout->addWidget(box); label->setText(tr("Choose folder for bookmarks:")); dialog->setWindowTitle(tr("Bookmark Selected Tabs")); QSize size = dialog->size(); size.setWidth(350); dialog->resize(size); dialog->exec(); if (dialog->result() == QDialog::Rejected) { return false; } foreach (WebTab* tab, tabsHash) { if (!tab->url().isEmpty()) { BookmarkItem* bookmark = new BookmarkItem(BookmarkItem::Url); bookmark->setTitle(tab->title()); bookmark->setUrl(tab->url()); mApp->bookmarks()->addBookmark(folderButton->selectedFolder(), bookmark); } } delete dialog; return true; } QTreeWidgetItem* TabManagerWidget::groupByDomainName(bool useHostName) { QTreeWidgetItem* currentTabItem = nullptr; QList windows = mApp->windows(); int currentWindowIdx = windows.indexOf(getWindow()); if (currentWindowIdx == -1) { // getWindow() instance is closing return nullptr; } QMap tabsGroupedByDomain; for (int win = 0; win < windows.count(); ++win) { BrowserWindow* mainWin = windows.at(win); QList tabs = mainWin->tabWidget()->allTabs(); for (int tab = 0; tab < tabs.count(); ++tab) { WebTab* webTab = tabs.at(tab); if (webTab->webView() && m_webPage == webTab->webView()->page()) { m_webPage = 0; continue; } QString domain = domainFromUrl(webTab->url(), useHostName); if (!tabsGroupedByDomain.contains(domain)) { TabItem* groupItem = new TabItem(ui->treeWidget, 0, false); groupItem->setTitle(domain); groupItem->setIsActiveOrCaption(true); tabsGroupedByDomain.insert(domain, groupItem); } QTreeWidgetItem* groupItem = tabsGroupedByDomain.value(domain); TabItem* tabItem = new TabItem(ui->treeWidget, groupItem); tabItem->setBrowserWindow(mainWin); tabItem->setWebTab(webTab); if (webTab == mainWin->weView()->webTab()) { tabItem->setIsActiveOrCaption(true); if (mainWin == getWindow()) currentTabItem = tabItem; } tabItem->updateIcon(); tabItem->setTitle(webTab->title()); } } ui->treeWidget->insertTopLevelItems(0, tabsGroupedByDomain.values()); return currentTabItem; } QTreeWidgetItem* TabManagerWidget::groupByWindow() { QTreeWidgetItem* currentTabItem = nullptr; QList windows = mApp->windows(); int currentWindowIdx = windows.indexOf(getWindow()); if (currentWindowIdx == -1) { return nullptr; } m_isRefreshing = true; if (!m_isDefaultWidget) { windows.move(currentWindowIdx, 0); currentWindowIdx = 0; } for (int win = 0; win < windows.count(); ++win) { BrowserWindow* mainWin = windows.at(win); TabItem* winItem = new TabItem(ui->treeWidget); winItem->setBrowserWindow(mainWin); winItem->setText(0, tr("Window %1").arg(QString::number(win + 1))); winItem->setToolTip(0, tr("Double click to switch")); winItem->setIsActiveOrCaption(win == currentWindowIdx); QList tabs = mainWin->tabWidget()->allTabs(); for (int tab = 0; tab < tabs.count(); ++tab) { WebTab* webTab = tabs.at(tab); if (webTab->webView() && m_webPage == webTab->webView()->page()) { m_webPage = 0; continue; } TabItem* tabItem = new TabItem(ui->treeWidget, winItem); tabItem->setBrowserWindow(mainWin); tabItem->setWebTab(webTab); if (webTab == mainWin->weView()->webTab()) { tabItem->setIsActiveOrCaption(true); if (mainWin == getWindow()) currentTabItem = tabItem; } tabItem->updateIcon(); tabItem->setTitle(webTab->title()); } } return currentTabItem; } BrowserWindow* TabManagerWidget::getWindow() { if (m_isDefaultWidget || !m_window) { return mApp->getWindow(); } else { return m_window.data(); } } TabItem::TabItem(QTreeWidget* treeWidget, QTreeWidgetItem* parent, bool addToTree) : QObject() , QTreeWidgetItem(addToTree ? (parent ? parent : treeWidget->invisibleRootItem()) : 0, 1) , m_treeWidget(treeWidget) , m_window(0) , m_webTab(0) { setFlags(flags() | (parent ? Qt::ItemIsUserCheckable : Qt::ItemIsUserCheckable | Qt::ItemIsTristate)); setCheckState(0, Qt::Unchecked); } BrowserWindow* TabItem::window() const { return m_window; } void TabItem::setBrowserWindow(BrowserWindow* window) { m_window = window; } WebTab* TabItem::webTab() const { return m_webTab; } void TabItem::setWebTab(WebTab* webTab) { m_webTab = webTab; if (m_webTab->isRestored()) setIsActiveOrCaption(m_webTab->isCurrentTab()); else setIsSavedTab(true); connect(m_webTab->webView()->page(), SIGNAL(audioMutedChanged(bool)), this, SLOT(updateIcon())); connect(m_webTab->webView()->page(), SIGNAL(loadFinished(bool)), this, SLOT(updateIcon())); connect(m_webTab->webView()->page(), SIGNAL(loadStarted()), this, SLOT(updateIcon())); connect(m_webTab->webView(), SIGNAL(titleChanged(QString)), this, SLOT(setTitle(QString))); connect(m_webTab->webView(), SIGNAL(iconChanged(QIcon)), this, SLOT(updateIcon())); } void TabItem::updateIcon() { if (!m_webTab) return; if (!m_webTab->isLoading()) { if (!m_webTab->isPinned()) { if (m_webTab->isMuted()) { setIcon(0, QIcon::fromTheme(QSL("audio-volume-muted"), QIcon(QSL(":icons/other/audiomuted.svg")))); } else if (!m_webTab->isMuted() && m_webTab->webView()->page()->recentlyAudible()) { setIcon(0, QIcon::fromTheme(QSL("audio-volume-high"), QIcon(QSL(":icons/other/audioplaying.svg")))); } else { setIcon(0, m_webTab->icon()); } } else { setIcon(0, QIcon(":tabmanager/data/tab-pinned.png")); } if (m_webTab->isRestored()) setIsActiveOrCaption(m_webTab->isCurrentTab()); else setIsSavedTab(true); } else { setIcon(0, QIcon(":tabmanager/data/tab-loading.png")); setIsActiveOrCaption(m_webTab->isCurrentTab()); } } void TabItem::setTitle(const QString &title) { setText(0, title); setToolTip(0, title); } void TabItem::setIsActiveOrCaption(bool yes) { setData(0, ActiveOrCaptionRole, yes ? QVariant(true) : QVariant()); setIsSavedTab(false); } void TabItem::setIsSavedTab(bool yes) { setData(0, SavedRole, yes ? QVariant(true) : QVariant()); }