Пример #1
0
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);
    }));
}
Пример #2
0
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();
}
Пример #3
0
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);
}
Пример #4
0
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);
}