diff --git a/src/libs/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp index f2f95863..dfc03491 100644 --- a/src/libs/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -29,7 +29,7 @@ #include "searchitemdelegate.h" #include "settingsdialog.h" #include "qxtglobalshortcut/qxtglobalshortcut.h" -#include "widgets/webview.h" +#include "widgets/webviewtab.h" #include #include @@ -50,9 +50,8 @@ #include #include #include -#include #include -#include +#include using namespace Zeal; using namespace Zeal::WidgetUi; @@ -74,9 +73,7 @@ struct TabState searchModel = new Registry::SearchModel(); tocModel = new Registry::SearchModel(); - webPage = new QWebPage(); - webPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); - webPage->setNetworkAccessManager(Core::Application::instance()->networkManager()); + widget = new WebViewTab(); } TabState(const TabState &other) @@ -85,15 +82,11 @@ struct TabState , expansions(other.expansions) , searchScrollPosition(other.searchScrollPosition) , tocScrollPosition(other.tocScrollPosition) - , zoomLevel(other.zoomLevel) { searchModel = new Registry::SearchModel(*other.searchModel); tocModel = new Registry::SearchModel(*other.tocModel); - webPage = new QWebPage(); - webPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); - webPage->setNetworkAccessManager(Core::Application::instance()->networkManager()); - + widget = new WebViewTab(); restoreHistory(other.saveHistory()); } @@ -101,36 +94,31 @@ struct TabState { delete searchModel; delete tocModel; - // deleteLater() prevents crashing on quit (#577) - webPage->deleteLater(); + + widget->deleteLater(); } void restoreHistory(const QByteArray &array) const { QDataStream stream(array); - stream >> *webPage->history(); + stream >> *widget->history(); } QByteArray saveHistory() const { QByteArray array; QDataStream stream(&array, QIODevice::WriteOnly); - stream << *webPage->history(); + stream << *widget->history(); return array; } - QUrl url() const { - return webPage->mainFrame()->url(); - } - - void loadUrl(const QUrl &url) + void goToStartPage() { - webPage->mainFrame()->load(url); - } - - QString title() const - { - return webPage->mainFrame()->title(); + if (Core::Application::instance()->settings()->isAdDisabled) { + widget->load(QUrl(WelcomePageNoAdUrl)); + } else { + widget->load(QUrl(WelcomePageUrl)); + } } QString searchQuery; @@ -145,8 +133,7 @@ struct TabState Registry::SearchModel *tocModel = nullptr; int tocScrollPosition = 0; - QWebPage *webPage = nullptr; - int zoomLevel = WebView::defaultZoomLevel(); + WebViewTab *widget = nullptr; }; } // namespace WidgetUi @@ -195,7 +182,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : // Edit ui->actionFind->setShortcut(QKeySequence::Find); - connect(ui->actionFind, &QAction::triggered, ui->webView, &WebViewTab::showSearchBar); + connect(ui->actionFind, &QAction::triggered, this, [this]() { + currentTab()->showSearchBar(); + }); connect(ui->actionPreferences, &QAction::triggered, [this]() { m_globalShortcut->setEnabled(false); @@ -208,8 +197,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : addAction(ui->actionBack); ui->actionForward->setShortcut(QKeySequence::Forward); addAction(ui->actionForward); - connect(ui->actionBack, &QAction::triggered, ui->webView, &WebViewTab::back); - connect(ui->actionForward, &QAction::triggered, ui->webView, &WebViewTab::forward); + connect(ui->actionBack, &QAction::triggered, this, [this]() { currentTab()->back(); }); + connect(ui->actionForward, &QAction::triggered, this, [this]() { currentTab()->forward(); }); // Tools Menu connect(ui->actionDocsets, &QAction::triggered, [this]() { @@ -260,7 +249,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_backMenu = new QMenu(ui->backButton); connect(m_backMenu, &QMenu::aboutToShow, this, [this]() { m_backMenu->clear(); - QWebHistory *history = currentTabState()->webPage->history(); + QWebHistory *history = currentTab()->history(); QList items = history->backItems(10); // TODO: [Qt 5.6] //for (auto it = items.crbegin(); it != items.crend(); ++it) { @@ -279,7 +268,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_forwardMenu = new QMenu(ui->forwardButton); connect(m_forwardMenu, &QMenu::aboutToShow, this, [this]() { m_forwardMenu->clear(); - QWebHistory *history = currentTabState()->webPage->history(); + QWebHistory *history = currentTab()->history(); for (const QWebHistoryItem &item: history->forwardItems(10)) { const QIcon icon = docsetIcon(docsetName(item.url())); // TODO: [Qt 5.6] @@ -314,34 +303,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->treeView, &QTreeView::activated, this, &MainWindow::openDocset); connect(ui->tocListView, &QListView::activated, this, &MainWindow::openDocset); - connect(ui->webView, &WebViewTab::urlChanged, [this](const QUrl &url) { - const QString name = docsetName(url); - m_tabBar->setTabIcon(m_tabBar->currentIndex(), docsetIcon(name)); - - Registry::Docset *docset = m_application->docsetRegistry()->docset(name); - if (docset) - currentTabState()->tocModel->setResults(docset->relatedLinks(url)); - - ui->actionBack->setEnabled(ui->webView->canGoBack()); - ui->actionForward->setEnabled(ui->webView->canGoForward()); - }); - - connect(ui->webView, &WebViewTab::titleChanged, [this](const QString &title) { - if (title.isEmpty()) - return; - - setWindowTitle(QStringLiteral("%1 - Zeal").arg(title)); - m_tabBar->setTabText(m_tabBar->currentIndex(), title); - m_tabBar->setTabToolTip(m_tabBar->currentIndex(), title); - }); - - connect(ui->webView, &WebViewTab::linkClicked, [this](const QUrl &url) { - const QString message = tr("Do you want to open an external link?
URL: %1"); - int ret = QMessageBox::question(this, QStringLiteral("Zeal"), message.arg(url.toString())); - if (ret == QMessageBox::Yes) - QDesktopServices::openUrl(url); - }); - connect(m_application->docsetRegistry(), &Registry::DocsetRegistry::searchCompleted, this, [this](const QList &results) { currentTabState()->searchModel->setResults(results); @@ -361,14 +322,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : tabState->searchModel->removeSearchResultWithName(name); } - if (docsetName(tabState->url()) == name) { + if (docsetName(tabState->widget->url()) == name) { tabState->tocModel->setResults(); // TODO: Add custom 'Page has been removed' page. - if (m_settings->isAdDisabled) { - tabState->loadUrl(QUrl(WelcomePageNoAdUrl)); - } else { - tabState->loadUrl(QUrl(WelcomePageUrl)); - } + tabState->goToStartPage(); } // TODO: Cleanup history @@ -431,7 +388,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->actionCloseTab, &QAction::triggered, this, [this]() { closeTab(); }); connect(ui->openUrlButton, &QPushButton::clicked, [this]() { - const QUrl url(ui->webView->page()->history()->currentItem().url()); + const QUrl url(currentTab()->url()); if (url.scheme() != QLatin1String("qrc")) QDesktopServices::openUrl(url); }); @@ -488,8 +445,8 @@ void MainWindow::openDocset(const QModelIndex &index) if (url.isNull()) return; - ui->webView->load(url.toUrl()); - ui->webView->focus(); + currentTab()->load(url.toUrl()); + currentTab()->focus(); } QString MainWindow::docsetName(const QUrl &url) const @@ -524,16 +481,25 @@ void MainWindow::closeTab(int index) if (index == -1) return; - delete m_tabStates.takeAt(index); + TabState *state = m_tabStates.takeAt(index); + ui->webViewStack->removeWidget(state->widget); + // Handle the tab bar last to avoid currentChanged signal coming too early. m_tabBar->removeTab(index); + delete state; + if (m_tabStates.isEmpty()) createTab(); } void MainWindow::moveTab(int from, int to) { m_tabStates.swap(from, to); + + const QSignalBlocker blocker(ui->webViewStack); + QWidget *w = ui->webViewStack->widget(from); + ui->webViewStack->removeWidget(w); + ui->webViewStack->insertWidget(to, w); } void MainWindow::createTab(int index) @@ -543,18 +509,11 @@ void MainWindow::createTab(int index) else if (index == -1) index = m_tabStates.size(); - using Registry::SearchModel; - TabState *newTab = new TabState(); - connect(newTab->searchModel, &SearchModel::updated, this, &MainWindow::queryCompleted); - connect(newTab->tocModel, &SearchModel::updated, this, &MainWindow::syncToc); + TabState *newState = new TabState(); + newState->goToStartPage(); - if (m_settings->isAdDisabled) { - newTab->loadUrl(QUrl(WelcomePageNoAdUrl)); - } else { - newTab->loadUrl(QUrl(WelcomePageUrl)); - } - - m_tabStates.insert(index, newTab); + m_tabStates.insert(index, newState); + ui->webViewStack->insertWidget(index, newState->widget); m_tabBar->insertTab(index, tr("Loading...")); m_tabBar->setCurrentIndex(index); @@ -569,14 +528,12 @@ void MainWindow::duplicateTab(int index) TabState *tabState = m_tabStates.at(index); syncTabState(tabState); - using Registry::SearchModel; - TabState *newTab = new TabState(*tabState); - connect(newTab->searchModel, &SearchModel::updated, this, &MainWindow::queryCompleted); - connect(newTab->tocModel, &SearchModel::updated, this, &MainWindow::syncToc); + TabState *newState = new TabState(*tabState); ++index; - m_tabStates.insert(index, newTab); - m_tabBar->insertTab(index, newTab->title()); + m_tabStates.insert(index, newState); + ui->webViewStack->insertWidget(index, newState->widget); + m_tabBar->insertTab(index, newState->widget->title()); m_tabBar->setCurrentIndex(index); } @@ -612,6 +569,73 @@ TabState *MainWindow::currentTabState() const return m_tabStates.at(m_tabBar->currentIndex()); } +WebViewTab *MainWindow::currentTab() const +{ + return qobject_cast(ui->webViewStack->currentWidget()); +} + +void MainWindow::attachTab(TabState *tabState) +{ + using Registry::SearchModel; + connect(tabState->searchModel, &SearchModel::updated, this, &MainWindow::queryCompleted); + connect(tabState->tocModel, &SearchModel::updated, this, &MainWindow::syncToc); + + connect(tabState->widget, &WebViewTab::urlChanged, this, [this, tabState](const QUrl &url) { + const QString name = docsetName(url); + m_tabBar->setTabIcon(m_tabBar->currentIndex(), docsetIcon(name)); + + Registry::Docset *docset = m_application->docsetRegistry()->docset(name); + if (docset) + tabState->tocModel->setResults(docset->relatedLinks(url)); + + ui->actionBack->setEnabled(tabState->widget->canGoBack()); + ui->actionForward->setEnabled(tabState->widget->canGoForward()); + }); + + connect(tabState->widget, &WebViewTab::titleChanged, this, [this](const QString &title) { + if (title.isEmpty()) + return; + + setWindowTitle(QStringLiteral("%1 - Zeal").arg(title)); + m_tabBar->setTabText(m_tabBar->currentIndex(), title); + m_tabBar->setTabToolTip(m_tabBar->currentIndex(), title); + }); + + connect(tabState->widget, &WebViewTab::linkClicked, this, [this](const QUrl &url) { + const QString message = tr("Do you want to open an external link?
URL: %1"); + int ret = QMessageBox::question(this, QStringLiteral("Zeal"), message.arg(url.toString())); + if (ret == QMessageBox::Yes) + QDesktopServices::openUrl(url); + }); + + ui->lineEdit->setText(tabState->searchQuery); + ui->tocListView->setModel(tabState->tocModel); + + syncTreeView(); + syncToc(); + + // Bring back the selections and expansions + ui->treeView->blockSignals(true); + for (const QModelIndex &selection: tabState->selections) + ui->treeView->selectionModel()->select(selection, QItemSelectionModel::Select); + for (const QModelIndex &expandedIndex: tabState->expansions) + ui->treeView->expand(expandedIndex); + ui->treeView->blockSignals(false); + + ui->actionBack->setEnabled(tabState->widget->canGoBack()); + ui->actionForward->setEnabled(tabState->widget->canGoForward()); + + ui->treeView->verticalScrollBar()->setValue(tabState->searchScrollPosition); + ui->tocListView->verticalScrollBar()->setValue(tabState->tocScrollPosition); +} + +void MainWindow::detachTab(TabState *tabState) +{ + tabState->searchModel->disconnect(this); + tabState->tocModel->disconnect(this); + tabState->widget->disconnect(this); +} + // Sets up the search box autocompletions. void MainWindow::setupSearchBoxCompletions() { @@ -653,34 +677,15 @@ void MainWindow::setupTabBar() = static_cast(m_tabBar->property(PreviousTabState).value()); if (m_tabStates.contains(previousTabState)) { syncTabState(previousTabState); + detachTab(previousTabState); } // Load current tab state TabState *tabState = m_tabStates.at(index); m_tabBar->setProperty(PreviousTabState, qVariantFromValue(static_cast(tabState))); + attachTab(tabState); - ui->lineEdit->setText(tabState->searchQuery); - ui->tocListView->setModel(tabState->tocModel); - - syncTreeView(); - syncToc(); - - // Bring back the selections and expansions - ui->treeView->blockSignals(true); - for (const QModelIndex &selection: tabState->selections) - ui->treeView->selectionModel()->select(selection, QItemSelectionModel::Select); - for (const QModelIndex &expandedIndex: tabState->expansions) - ui->treeView->expand(expandedIndex); - ui->treeView->blockSignals(false); - - ui->webView->setPage(tabState->webPage); - ui->webView->setZoomLevel(tabState->zoomLevel); - - ui->actionBack->setEnabled(ui->webView->canGoBack()); - ui->actionForward->setEnabled(ui->webView->canGoForward()); - - ui->treeView->verticalScrollBar()->setValue(tabState->searchScrollPosition); - ui->tocListView->verticalScrollBar()->setValue(tabState->tocScrollPosition); + ui->webViewStack->setCurrentIndex(index); }); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); connect(m_tabBar, &QTabBar::tabMoved, this, &MainWindow::moveTab); @@ -757,7 +762,6 @@ void MainWindow::syncTabState(TabState *tabState) tabState->selections = ui->treeView->selectionModel()->selectedIndexes(); tabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); tabState->tocScrollPosition = ui->tocListView->verticalScrollBar()->value(); - tabState->zoomLevel = ui->webView->zoomLevel(); } void MainWindow::bringToFront() @@ -776,6 +780,7 @@ void MainWindow::changeEvent(QEvent *event) && event->type() == QEvent::WindowStateChange && isMinimized()) { hide(); } + QMainWindow::changeEvent(event); } diff --git a/src/libs/ui/mainwindow.h b/src/libs/ui/mainwindow.h index 2d02f7e2..65a10c36 100644 --- a/src/libs/ui/mainwindow.h +++ b/src/libs/ui/mainwindow.h @@ -52,6 +52,8 @@ namespace Ui { class MainWindow; } // namespace Ui +class WebViewTab; + struct TabState; class MainWindow : public QMainWindow @@ -89,6 +91,10 @@ private: void setupTabBar(); TabState *currentTabState() const; + WebViewTab *currentTab() const; + + void attachTab(TabState *tabState); + void detachTab(TabState *tabState); QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; diff --git a/src/libs/ui/mainwindow.ui b/src/libs/ui/mainwindow.ui index fd8d30a4..1bac88c1 100644 --- a/src/libs/ui/mainwindow.ui +++ b/src/libs/ui/mainwindow.ui @@ -159,14 +159,7 @@ - - - - 0 - 0 - - - + @@ -180,7 +173,7 @@ 0 0 900 - 22 + 20 @@ -326,12 +319,6 @@ QLineEdit
ui/widgets/searchedit.h
- - WebViewTab - QWidget -
ui/widgets/webviewtab.h
- 1 -
ToolBarFrame QWidget diff --git a/src/libs/ui/widgets/webview.cpp b/src/libs/ui/widgets/webview.cpp index 8e977df5..88f3e532 100644 --- a/src/libs/ui/widgets/webview.cpp +++ b/src/libs/ui/widgets/webview.cpp @@ -25,6 +25,8 @@ #include "../mainwindow.h" +#include + #include #include #include @@ -34,6 +36,9 @@ using namespace Zeal::WidgetUi; WebView::WebView(QWidget *parent) : QWebView(parent) { + setAttribute(Qt::WA_AcceptTouchEvents, false); + page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); + page()->setNetworkAccessManager(Core::Application::instance()->networkManager()); } int WebView::zoomLevel() const diff --git a/src/libs/ui/widgets/webviewtab.cpp b/src/libs/ui/widgets/webviewtab.cpp index 055dabce..4d816f3d 100644 --- a/src/libs/ui/widgets/webviewtab.cpp +++ b/src/libs/ui/widgets/webviewtab.cpp @@ -32,40 +32,43 @@ #include #include #include +#include using namespace Zeal::WidgetUi; WebViewTab::WebViewTab(QWidget *parent) : QWidget(parent), - m_searchLineEdit(new QLineEdit(this)), - m_webView(new WebView(this)) + m_searchLineEdit(new QLineEdit(this)) { - m_webView->setAttribute(Qt::WA_AcceptTouchEvents, false); + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); m_searchLineEdit->hide(); m_searchLineEdit->installEventFilter(this); connect(m_searchLineEdit, &QLineEdit::textChanged, this, &WebViewTab::find); - connect(m_webView, &QWebView::loadFinished, [&](bool ok) { + m_webView = new WebView(); + connect(m_webView, &QWebView::loadFinished, this, [this](bool ok) { Q_UNUSED(ok) moveLineEdit(); }); - connect(m_webView, &QWebView::urlChanged, this, &WebViewTab::urlChanged); - connect(m_webView, &QWebView::titleChanged, this, &WebViewTab::titleChanged); - connect(m_webView, &QWebView::linkClicked, this, &WebViewTab::linkClicked); -} - -void WebViewTab::setPage(QWebPage *page) -{ - m_webView->setPage(page); - - connect(page, &QWebPage::linkHovered, [&](const QString &link) { + connect(m_webView->page(), &QWebPage::linkHovered, [this](const QString &link) { if (link.startsWith(QLatin1String("file:")) || link.startsWith(QLatin1String("qrc:"))) return; setToolTip(link); }); + + connect(m_webView, &QWebView::linkClicked, this, &WebViewTab::linkClicked); + connect(m_webView, &QWebView::titleChanged, this, &WebViewTab::titleChanged); + connect(m_webView, &QWebView::urlChanged, this, &WebViewTab::urlChanged); + + layout->addWidget(m_webView); + + setLayout(layout); + } int WebViewTab::zoomLevel() const @@ -114,11 +117,6 @@ void WebViewTab::focus() m_webView->setFocus(); } -QWebPage *WebViewTab::page() const -{ - return m_webView->page(); -} - QSize WebViewTab::sizeHint() const { return m_webView->sizeHint(); @@ -160,6 +158,21 @@ bool WebViewTab::canGoForward() const return m_webView->history()->canGoForward(); } +QString WebViewTab::title() const +{ + return m_webView->title(); +} + +QUrl WebViewTab::url() const +{ + return m_webView->url(); +} + +QWebHistory *WebViewTab::history() const +{ + return m_webView->history(); +} + void WebViewTab::keyPressEvent(QKeyEvent *event) { switch (event->key()) { diff --git a/src/libs/ui/widgets/webviewtab.h b/src/libs/ui/widgets/webviewtab.h index 9df103d4..fc40209a 100644 --- a/src/libs/ui/widgets/webviewtab.h +++ b/src/libs/ui/widgets/webviewtab.h @@ -27,7 +27,7 @@ #include class QLineEdit; -class QWebPage; +class QWebHistory; namespace Zeal { namespace WidgetUi { @@ -43,10 +43,13 @@ public: void load(const QUrl &url); void focus(); QSize sizeHint() const override; - QWebPage *page() const; bool canGoBack() const; bool canGoForward() const; - void setPage(QWebPage *page); + + QString title() const; + QUrl url() const; + + QWebHistory *history() const; int zoomLevel() const; void setZoomLevel(int level); @@ -54,9 +57,9 @@ public: bool eventFilter(QObject *object, QEvent *event) override; signals: - void urlChanged(const QUrl &url); - void titleChanged(const QString &title); void linkClicked(const QUrl &url); + void titleChanged(const QString &title); + void urlChanged(const QUrl &url); public slots: void back();