void DocsetRegistry::loadDocset(const QString &path) { auto watcher = new QFutureWatcher<Docset *>(); connect(watcher, &QFutureWatcher<Docset *>::finished, this, [this, watcher] { QScopedPointer<QFutureWatcher<Docset *>, QScopedPointerDeleteLater> guard(watcher); Docset *docset = watcher->result(); // TODO: Emit error if (!docset->isValid()) { qWarning("Could not load docset from '%s'. Reinstall the docset.", qPrintable(docset->path())); delete docset; return; } docset->setFuzzySearchEnabled(m_fuzzySearchEnabled); const QString name = docset->name(); if (m_docsets.contains(name)) { unloadDocset(name); } m_docsets[name] = docset; emit docsetLoaded(name); }); watcher->setFuture(QtConcurrent::run([path] { return new Docset(path); })); }
void SettingsDialog::processDocsetList(const QJsonArray &list) { for (const QJsonValue &v : list) { QJsonObject docsetJson = v.toObject(); DocsetMetadata metadata(docsetJson); m_availableDocsets.insert(metadata.name(), metadata); } /// TODO: Move into dedicated method for (const DocsetMetadata &metadata : m_availableDocsets) { QListWidgetItem *listItem = new QListWidgetItem(metadata.icon(), metadata.title(), ui->availableDocsetList); listItem->setData(ListModel::DocsetNameRole, metadata.name()); listItem->setCheckState(Qt::Unchecked); if (m_docsetRegistry->contains(metadata.name())) { listItem->setHidden(true); Docset *docset = m_docsetRegistry->docset(metadata.name()); if (metadata.latestVersion() != docset->version() || (metadata.latestVersion() == docset->version() && metadata.revision() > docset->revision())) { docset->hasUpdate = true; ui->updateAllDocsetsButton->setEnabled(true); } } } ui->installedDocsetList->reset(); if (!m_availableDocsets.isEmpty()) ui->downloadableGroup->show(); }
void DocsetRegistry::_addDocset(const QString &path) { Docset *docset = new Docset(path); // TODO: Emit error if (!docset->isValid()) { qWarning("Could not load docset from '%s'. Please reinstall the docset.", qPrintable(path)); delete docset; return; } const QString name = docset->name(); if (m_docsets.contains(name)) remove(name); m_docsets[name] = docset; emit docsetAdded(name); }
MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_application(app), m_settings(app->settings()), m_zealListModel(new ListModel(app->docsetRegistry(), this)), m_settingsDialog(new SettingsDialog(app, m_zealListModel, this)), m_globalShortcut(new QxtGlobalShortcut(m_settings->showShortcut, this)) { ui->setupUi(this); connect(m_settings, &Core::Settings::updated, this, &MainWindow::applySettings); m_tabBar = new QTabBar(this); m_tabBar->installEventFilter(this); setWindowIcon(QIcon::fromTheme(QStringLiteral("zeal"), QIcon(QStringLiteral(":/zeal.ico")))); if (m_settings->showSystrayIcon) createTrayIcon(); // initialise key grabber connect(m_globalShortcut, &QxtGlobalShortcut::activated, this, &MainWindow::toggleWindow); QShortcut *focusSearch = new QShortcut(QKeySequence(QStringLiteral("Ctrl+K")), this); focusSearch->setContext(Qt::ApplicationShortcut); connect(focusSearch, &QShortcut::activated, ui->lineEdit, static_cast<void (SearchEdit::*)()>(&SearchEdit::setFocus)); restoreGeometry(m_settings->windowGeometry); ui->splitter->restoreState(m_settings->verticalSplitterGeometry); m_zealNetworkManager = new NetworkAccessManager(this); #ifdef USE_WEBENGINE /// FIXME AngularJS workaround (zealnetworkaccessmanager.cpp) #else ui->webView->page()->setNetworkAccessManager(m_zealNetworkManager); #endif // menu if (QKeySequence(QKeySequence::Quit) != QKeySequence(QStringLiteral("Ctrl+Q"))) { ui->actionQuit->setShortcuts(QList<QKeySequence>{QKeySequence(QStringLiteral("Ctrl+Q")), QKeySequence::Quit}); } else { // Quit == Ctrl+Q - don't set the same sequence twice because it causes // "QAction::eventFilter: Ambiguous shortcut overload: Ctrl+Q" ui->actionQuit->setShortcuts(QList<QKeySequence>{QKeySequence::Quit}); } connect(ui->actionQuit, &QAction::triggered, qApp, &QCoreApplication::quit); connect(ui->actionOptions, &QAction::triggered, [=]() { m_globalShortcut->setEnabled(false); m_settingsDialog->exec(); m_globalShortcut->setEnabled(true); }); ui->actionBack->setShortcut(QKeySequence::Back); addAction(ui->actionBack); ui->actionForward->setShortcut(QKeySequence::Forward); addAction(ui->actionForward); connect(ui->actionBack, &QAction::triggered, this, &MainWindow::back); connect(ui->actionForward, &QAction::triggered, this, &MainWindow::forward); // Help Menu connect(ui->actionReportProblem, &QAction::triggered, [this]() { QDesktopServices::openUrl(QStringLiteral("https://github.com/zealdocs/zeal/issues")); }); connect(ui->actionCheckForUpdate, &QAction::triggered, m_application, &Core::Application::checkForUpdate); connect(ui->actionAboutZeal, &QAction::triggered, [this]() { QScopedPointer<AboutDialog> dialog(new AboutDialog(this)); dialog->exec(); }); connect(ui->actionAboutQt, &QAction::triggered, [this]() { QMessageBox::aboutQt(this); }); // Update check connect(m_application, &Core::Application::updateCheckError, [this](const QString &message) { QMessageBox::warning(this, QStringLiteral("Zeal"), message); }); connect(m_application, &Core::Application::updateCheckDone, [this](const QString &version) { if (version.isEmpty()) { QMessageBox::information(this, QStringLiteral("Zeal"), tr("You are using the latest Zeal version.")); return; } const int ret = QMessageBox::information(this, QStringLiteral("Zeal"), QString(tr("A new version <b>%1</b> is available. Open download page?")).arg(version), QMessageBox::Yes, QMessageBox::No); if (ret == QMessageBox::Yes) QDesktopServices::openUrl(QStringLiteral("https://zealdocs.org/download.html")); }); m_backMenu = new QMenu(ui->backButton); ui->backButton->setMenu(m_backMenu); m_forwardMenu = new QMenu(ui->forwardButton); ui->forwardButton->setMenu(m_forwardMenu); displayViewActions(); // treeView and lineEdit ui->lineEdit->setTreeView(ui->treeView); ui->lineEdit->setFocus(); setupSearchBoxCompletions(); SearchItemDelegate *delegate = new SearchItemDelegate(ui->treeView); connect(ui->lineEdit, &QLineEdit::textChanged, [delegate](const QString &text) { delegate->setHighlight(Zeal::SearchQuery::fromString(text).query()); }); ui->treeView->setItemDelegate(delegate); createTab(); /// FIXME: QTabBar does not emit currentChanged() after the first addTab() call reloadTabState(); connect(ui->treeView, &QTreeView::clicked, [this](const QModelIndex &index) { m_treeViewClicked = true; ui->treeView->activated(index); }); connect(ui->sections, &QListView::clicked, [this](const QModelIndex &index) { m_treeViewClicked = true; ui->sections->activated(index); }); connect(ui->treeView, &QTreeView::activated, this, &MainWindow::openDocset); connect(ui->sections, &QListView::activated, this, &MainWindow::openDocset); connect(ui->forwardButton, &QPushButton::clicked, this, &MainWindow::forward); connect(ui->backButton, &QPushButton::clicked, this, &MainWindow::back); connect(ui->webView, &SearchableWebView::urlChanged, [this](const QUrl &url) { const QString name = docsetName(url); m_tabBar->setTabIcon(m_tabBar->currentIndex(), docsetIcon(name)); Docset *docset = m_application->docsetRegistry()->docset(name); if (docset) m_searchState->sectionsList->setResults(docset->relatedLinks(url)); displayViewActions(); }); connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &) { displayViewActions(); }); connect(ui->webView, &SearchableWebView::linkClicked, [this](const QUrl &url) { const QString message = tr("Do you want to open an external link?<br>URL: <b>%1</b>"); int ret = QMessageBox::question(this, QStringLiteral("Zeal"), message.arg(url.toString())); if (ret == QMessageBox::Yes) QDesktopServices::openUrl(url); }); connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, &MainWindow::onSearchComplete); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, this, [this](const QString &name) { setupSearchBoxCompletions(); for (SearchState *searchState : m_tabs) { #ifdef USE_WEBENGINE if (docsetName(searchState->page->url()) != name) continue; searchState->page->load(QUrl(startPageUrl)); #else if (docsetName(searchState->page->mainFrame()->url()) != name) continue; searchState->sectionsList->setResults(); // optimization: disable updates temporarily because // removeSearchResultWithName can call {begin,end}RemoveRows // multiple times which can cause GUI updates to be suboptimal // in case of many rows to be removed ui->treeView->setUpdatesEnabled(false); searchState->zealSearch->removeSearchResultWithName(name); ui->treeView->setUpdatesEnabled(true); searchState->page->mainFrame()->load(QUrl(startPageUrl)); #endif /// TODO: Cleanup history } }); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetAdded, this, [this](const QString &) { setupSearchBoxCompletions(); }); connect(ui->lineEdit, &QLineEdit::textChanged, [this](const QString &text) { if (!m_searchState || text == m_searchState->searchQuery) return; m_searchState->searchQuery = text; m_application->docsetRegistry()->search(text); if (text.isEmpty()) { m_searchState->sectionsList->setResults(); displayTreeView(); } }); ui->actionNewTab->setShortcut(QKeySequence::AddTab); connect(ui->actionNewTab, &QAction::triggered, this, &MainWindow::createTab); addAction(ui->actionNewTab); // save the expanded items: connect(ui->treeView, &QTreeView::expanded, [this](QModelIndex index) { if (m_searchState->expansions.indexOf(index) == -1) m_searchState->expansions.append(index); }); connect(ui->treeView, &QTreeView::collapsed, [this](QModelIndex index) { m_searchState->expansions.removeOne(index); }); #ifdef Q_OS_WIN32 ui->actionCloseTab->setShortcut(QKeySequence(Qt::Key_W + Qt::CTRL)); #else ui->actionCloseTab->setShortcut(QKeySequence::Close); #endif addAction(ui->actionCloseTab); connect(ui->actionCloseTab, &QAction::triggered, this, [this]() { closeTab(); }); m_tabBar->setTabsClosable(true); m_tabBar->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab); m_tabBar->setExpanding(false); m_tabBar->setUsesScrollButtons(true); m_tabBar->setDrawBase(false); m_tabBar->setDocumentMode(true); m_tabBar->setElideMode(Qt::ElideRight); m_tabBar->setStyleSheet(QStringLiteral("QTabBar::tab { width: 150px; }")); connect(m_tabBar, &QTabBar::currentChanged, this, &MainWindow::goToTab); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); { QHBoxLayout *layout = reinterpret_cast<QHBoxLayout *>(ui->tabBarFrame->layout()); layout->insertWidget(2, m_tabBar, 0, Qt::AlignBottom); } connect(ui->openUrlButton, &QPushButton::clicked, [this]() { const QUrl url(ui->webView->page()->history()->currentItem().url()); if (url.scheme() != QLatin1String("qrc")) QDesktopServices::openUrl(url); }); ui->actionNextTab->setShortcut(QKeySequence::NextChild); addAction(ui->actionNextTab); connect(ui->actionNextTab, &QAction::triggered, [this]() { m_tabBar->setCurrentIndex((m_tabBar->currentIndex() + 1) % m_tabBar->count()); }); ui->actionPreviousTab->setShortcut(QKeySequence::PreviousChild); addAction(ui->actionPreviousTab); connect(ui->actionPreviousTab, &QAction::triggered, [this]() { m_tabBar->setCurrentIndex((m_tabBar->currentIndex() - 1 + m_tabBar->count()) % m_tabBar->count()); }); #ifdef Q_OS_OSX ui->treeView->setAttribute(Qt::WA_MacShowFocusRect, false); ui->sections->setAttribute(Qt::WA_MacShowFocusRect, false); #endif /// TODO: Remove in the future releases // Check pre-0.1 docset path QString oldDocsetDir = QStandardPaths::writableLocation(QStandardPaths::DataLocation); oldDocsetDir.remove(QStringLiteral("Zeal/Zeal")); oldDocsetDir += QLatin1String("zeal/docsets"); if (QFileInfo::exists(oldDocsetDir) && m_settings->docsetPath != oldDocsetDir) { QMessageBox::information(this, QStringLiteral("Zeal"), QString(tr("Old docset storage has been found in <b>%1</b>. " "You can move docsets to <b>%2</b> or change the docset storage path in the settings. <br><br>" "Please note, that old docsets cannot be updated automatically, so it is better to download your docsets again. <br><br>" "Remove or use the old docset storage to avoid this message in the future.")) .arg(QDir::toNativeSeparators(oldDocsetDir), QDir::toNativeSeparators(m_settings->docsetPath))); } if (m_settings->checkForUpdate) m_application->checkForUpdate(true); }