From 4f5a34936e0b3ed54bca05a3b5ff65cbcf1c8de7 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 11 Nov 2015 23:33:43 -0500 Subject: [PATCH 001/273] doc: Add release version badge to README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 611f2feb5..8a1dce973 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Zeal -[![IRC](https://img.shields.io/badge/irc-%23zealdocs-blue.svg?style=flat-square)](https://kiwiirc.com/client/irc.freenode.net/#zealdocs) +[![GitHub release](https://img.shields.io/github/release/zealdocs/zeal.svg?style=flat-square)](https://github.com/zealdocs/zeal/releases) [![IRC](https://img.shields.io/badge/irc-%23zealdocs-blue.svg?style=flat-square)](https://kiwiirc.com/client/irc.freenode.net/#zealdocs) > **zeal** *noun* > From 328e45916ebe20dd310704a5fff85ee629fb908c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 19 Nov 2015 01:05:46 -0500 Subject: [PATCH 002/273] core: Use Q_ENUM() macro for Qt 5.5+ --- src/core/settings.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/settings.h b/src/core/settings.h index a7c36c8d5..c798f6327 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -63,6 +63,9 @@ class Settings : public QObject System, UserDefined }; +#if QT_VERSION >= 0x050500 + Q_ENUM(ProxyType) +#endif // Internal // -------- @@ -104,6 +107,8 @@ public slots: } // namespace Core } // namespace Zeal +#if QT_VERSION < 0x050500 Q_DECLARE_METATYPE(Zeal::Core::Settings::ProxyType) +#endif #endif // SETTINGS_H From 47f57558284a821113ea512829a632dc9407d8af Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 19 Nov 2015 01:06:58 -0500 Subject: [PATCH 003/273] core: Avoid QString to QByteArray conversion on every download request --- src/core/application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 95c50aabc..447d170d1 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -148,13 +148,13 @@ void Application::extract(const QString &filePath, const QString &destination, c QNetworkReply *Application::download(const QUrl &url) { static const QString ua = userAgent(); - static const QString uaJson = userAgentJson(); + static const QByteArray uaJson = userAgentJson().toUtf8(); QNetworkRequest request(url); request.setHeader(QNetworkRequest::UserAgentHeader, ua); if (url.host().endsWith(QLatin1String(".zealdocs.org", Qt::CaseInsensitive))) - request.setRawHeader("X-Zeal-User-Agent", uaJson.toUtf8()); + request.setRawHeader("X-Zeal-User-Agent", uaJson); return m_networkManager->get(request); } From 6c533e924a3738b44f82c9741a1ddc0cdb052ae3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 19 Nov 2015 01:23:25 -0500 Subject: [PATCH 004/273] doc: Fix links for Shippable badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a1dce973..17307375f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Zeal is a simple offline documentation browser inspired by [Dash](https://kapeli OS \ Branch | master | stable ------------|--------|------- -Linux | [![Shippable](https://img.shields.io/shippable/54ac2ce4d46935d5fbc19b84/master.svg?style=flat-square)](https://app.shippable.com/builds/54ac2ce4d46935d5fbc19b84) | [![Shippable](https://img.shields.io/shippable/54ac2ce4d46935d5fbc19b84/stable.svg?style=flat-square)](https://app.shippable.com/builds/54ac2ce4d46935d5fbc19b84) +Linux | [![Shippable](https://img.shields.io/shippable/54ac2ce4d46935d5fbc19b84/master.svg?style=flat-square)](https://app.shippable.com/projects/54ac2ce4d46935d5fbc19b84) | [![Shippable](https://img.shields.io/shippable/54ac2ce4d46935d5fbc19b84/stable.svg?style=flat-square)](https://app.shippable.com/projects/54ac2ce4d46935d5fbc19b84) Windows | [![AppVeyor](https://img.shields.io/appveyor/ci/trollixx/zeal/master.svg?style=flat-square)](https://ci.appveyor.com/project/trollixx/zeal) | [![AppVeyor](https://img.shields.io/appveyor/ci/trollixx/zeal/stable.svg?style=flat-square)](https://ci.appveyor.com/project/trollixx/zeal) ## Download From 4e8717f8ebc98cc81f359529b0ef0153eff3edc6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 22 Nov 2015 22:05:15 -0500 Subject: [PATCH 005/273] core: Drop support for --query CLI parameter --- src/main.cpp | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 917ce66df..022d981f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,10 +72,7 @@ CommandLineParameters parseCommandLine(const QStringList &arguments) /// TODO: [Qt 5.4] parser.addOption({{"f", "force"}, "Force the application run."}); parser.addOption(QCommandLineOption({QStringLiteral("f"), QStringLiteral("force")}, QObject::tr("Force the application run."))); - /// TODO: [0.3.0] Remove --query support - parser.addOption(QCommandLineOption({QStringLiteral("q"), QStringLiteral("query")}, - QObject::tr("[DEPRECATED] Query ."), - QStringLiteral("term"))); + #ifdef Q_OS_WIN32 parser.addOption(QCommandLineOption({QStringLiteral("register")}, QObject::tr("Register protocol handlers"))); @@ -98,23 +95,19 @@ CommandLineParameters parseCommandLine(const QStringList &arguments) } #endif - if (parser.isSet(QStringLiteral("query"))) { - clParams.query.setQuery(parser.value(QStringLiteral("query"))); + /// TODO: Support dash-feed:// protocol + const QString arg + = QUrl::fromPercentEncoding(parser.positionalArguments().value(0).toUtf8()); + if (arg.startsWith(QLatin1String("dash:"))) { + clParams.query.setQuery(stripParameterUrl(arg, QStringLiteral("dash"))); + } else if (arg.startsWith(QLatin1String("dash-plugin:"))) { + const QUrlQuery urlQuery(stripParameterUrl(arg, QStringLiteral("dash-plugin"))); + const QString keys = urlQuery.queryItemValue(QStringLiteral("keys")); + if (!keys.isEmpty()) + clParams.query.setKeywords(keys.split(QLatin1Char(','))); + clParams.query.setQuery(urlQuery.queryItemValue(QStringLiteral("query"))); } else { - /// TODO: Support dash-feed:// protocol - const QString arg - = QUrl::fromPercentEncoding(parser.positionalArguments().value(0).toUtf8()); - if (arg.startsWith(QLatin1String("dash:"))) { - clParams.query.setQuery(stripParameterUrl(arg, QStringLiteral("dash"))); - } else if (arg.startsWith(QLatin1String("dash-plugin:"))) { - const QUrlQuery urlQuery(stripParameterUrl(arg, QStringLiteral("dash-plugin"))); - const QString keys = urlQuery.queryItemValue(QStringLiteral("keys")); - if (!keys.isEmpty()) - clParams.query.setKeywords(keys.split(QLatin1Char(','))); - clParams.query.setQuery(urlQuery.queryItemValue(QStringLiteral("query"))); - } else { - clParams.query.setQuery(arg); - } + clParams.query.setQuery(arg); } return clParams; From 77ab13ea07c47e69d17049a75aa0f02125b14816 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 22 Nov 2015 23:09:22 -0500 Subject: [PATCH 006/273] util: Cleanup unused code in Version --- src/util/version.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/util/version.cpp b/src/util/version.cpp index dc632ee39..0c5fd2f89 100644 --- a/src/util/version.cpp +++ b/src/util/version.cpp @@ -48,24 +48,6 @@ QString Version::toString() const return QString("%1.%2.%3").arg(m_major).arg(m_minor).arg(m_patch); } -/*bool Version::operator>(const Version &other) const -{ - if (m_major > other.m_major) - return true; - else if (m_major < other.m_major) - return false; - - if (m_minor > other.m_minor) - return true; - else if (m_minor < other.m_minor) - return false; - - if (m_patch > other.m_patch) - return true; - - return false; -}*/ - bool Version::fromString(const QString &str) { const QStringList parts = str.split(QLatin1Char('.')); @@ -117,4 +99,3 @@ bool operator<(const Version &lhs, const Version &rhs) } // namespace Util } // namespace Zeal - From a17a0bb4ac9e0beca4a4fd602e98df67a95f483b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 26 Nov 2015 03:48:37 -0500 Subject: [PATCH 007/273] ui: Remove build date and time information in the About dialog Also, fixes inability to create reproducible builds. --- src/ui/aboutdialog.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index bb49c91fa..9b08927c1 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -31,9 +31,8 @@ AboutDialog::AboutDialog(QWidget *parent) : { ui->setupUi(this); - const QString buildInfo - = QString(tr("Version: %1
Built: %2")) - .arg(QCoreApplication::applicationVersion(), QString("%1 %2").arg(__DATE__, __TIME__)); + const QString buildInfo = QString(tr("Version: %1
")) + .arg(QCoreApplication::applicationVersion()); ui->buildInfoLabel->setText(buildInfo); ui->buttonBox->setFocus(Qt::OtherFocusReason); From 57185b4d7d37edb5503fe0a1ddfde7c87791dcaa Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 28 Nov 2015 22:10:15 -0500 Subject: [PATCH 008/273] registry: Docset doesn't need to inherit QObject --- src/registry/docset.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/registry/docset.h b/src/registry/docset.h index 76feb93b2..2560709fc 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -33,12 +33,11 @@ namespace Zeal { -class Docset : public QObject +class Docset { - Q_OBJECT public: explicit Docset(const QString &path); - ~Docset() override; + ~Docset(); bool isValid() const; From e08969cd7a8a6f93050659a967e89d086a7a13f1 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 28 Nov 2015 22:50:28 -0500 Subject: [PATCH 009/273] registry: Cleanup SearchModel --- src/registry/searchmodel.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index c7dbc67b4..e4cc0aa85 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -23,8 +23,7 @@ #include "searchmodel.h" -#include "core/application.h" -#include "registry/docsetregistry.h" +#include "registry/docset.h" #include @@ -74,7 +73,9 @@ QModelIndex SearchModel::index(int row, int column, const QModelIndex &parent) c if (parent.isValid() || m_dataList.count() <= row || column > 1) return QModelIndex(); - return createIndex(row, column, (void *)&m_dataList.at(row)); + /// FIXME: const_cast + SearchResult *item = const_cast(&m_dataList.at(row)); + return createIndex(row, column, item); } QModelIndex SearchModel::parent(const QModelIndex &child) const From e90fdd1cf28db91d2d639f64ac04494720c595be Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 3 Dec 2015 21:38:52 -0500 Subject: [PATCH 010/273] ui: Remove C-style cast --- src/ui/mainwindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c8e4a354f..6f9402e5a 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -302,7 +302,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_tabBar, &QTabBar::currentChanged, this, &MainWindow::goToTab); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); - ((QHBoxLayout *)ui->tabBarFrame->layout())->insertWidget(2, m_tabBar, 0, Qt::AlignBottom); + { + QHBoxLayout *layout = reinterpret_cast(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()); From 18d75b300325880d5795b5bbee9f7f0999dc7ee9 Mon Sep 17 00:00:00 2001 From: Jerzy Kozera Date: Tue, 5 Jan 2016 00:50:02 +0100 Subject: [PATCH 011/273] doc: New screenshot for README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17307375f..d2519f2d7 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Zeal is a simple offline documentation browser inspired by [Dash](https://kapeli.com/dash). -![Screenshot](https://i.imgur.com/SiLvpz8.png) +![Screenshot](https://i.imgur.com/v63u1ZJ.png) [More screenshots](https://imgur.com/a/eVi97) From 7a8f15ca0490f864cc9a851115f9b297d94af501 Mon Sep 17 00:00:00 2001 From: Joao Sa Date: Wed, 9 Dec 2015 00:44:33 -0200 Subject: [PATCH 012/273] registry: Fix index creation for ZDash docsets --- src/registry/docset.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 6256dc5c3..916a42013 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -458,12 +458,14 @@ void Docset::createIndex() static const QString indexListQuery = QStringLiteral("PRAGMA INDEX_LIST('%1')"); static const QString indexDropQuery = QStringLiteral("DROP INDEX '%1'"); static const QString indexCreateQuery = QStringLiteral("CREATE INDEX IF NOT EXISTS %1%2" - " ON %3 (name COLLATE NOCASE)"); + " ON %3 (%4 COLLATE NOCASE)"); QSqlQuery query(database()); const QString tableName = m_type == Type::Dash ? QStringLiteral("searchIndex") : QStringLiteral("ztoken"); + const QString columnName = m_type == Type::Dash ? QStringLiteral("name") + : QStringLiteral("ztokenname"); query.exec(indexListQuery.arg(tableName)); @@ -484,7 +486,7 @@ void Docset::createIndex() for (const QString oldIndexName : oldIndexes) query.exec(indexDropQuery.arg(oldIndexName)); - query.exec(indexCreateQuery.arg(IndexNamePrefix, IndexNameVersion, tableName)); + query.exec(indexCreateQuery.arg(IndexNamePrefix, IndexNameVersion, tableName, columnName)); } QString Docset::parseSymbolType(const QString &str) From f143417a88274dd6830269a1bd3d1d60b319e2bb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 11 Dec 2015 00:36:06 -0500 Subject: [PATCH 013/273] ui: Do not create excessive quit QAction --- src/ui/mainwindow.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 6f9402e5a..bdda1d90f 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -83,6 +83,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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); @@ -96,9 +98,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : // initialise key grabber connect(m_globalShortcut, &QxtGlobalShortcut::activated, this, &MainWindow::toggleWindow); - // initialise ui - ui->setupUi(this); - QShortcut *focusSearch = new QShortcut(QKeySequence(QStringLiteral("Ctrl+K")), this); focusSearch->setContext(Qt::ApplicationShortcut); connect(focusSearch, &QShortcut::activated, @@ -703,8 +702,7 @@ void MainWindow::createTrayIcon() }); QMenu *trayIconMenu = new QMenu(this); - QAction *quitAction = trayIconMenu->addAction(tr("&Quit")); - connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit); + trayIconMenu->addAction(ui->actionQuit); m_trayIcon->setContextMenu(trayIconMenu); From 8f157435abfc4d7d567ea3fb1a642a9fc42ed705 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 18 Jan 2016 02:09:50 -0500 Subject: [PATCH 014/273] core: Respect startMinimized setting --- src/core/application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 447d170d1..00ea78b5b 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -105,7 +105,9 @@ Application::Application(const SearchQuery &query, QObject *parent) : if (!query.isEmpty()) m_mainWindow->bringToFront(query); - else if (!m_settings->startMinimized) + else if (m_settings->startMinimized) + m_mainWindow->showMinimized(); + else m_mainWindow->show(); } From 17398dbc21e426e9fab4ab4e3994d3e265d0b51c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 18 Jan 2016 02:25:02 -0500 Subject: [PATCH 015/273] core, ui: Respect prevent_activation dash-plugin parameter (fixes #448) --- src/core/application.cpp | 18 ++++++++++++------ src/main.cpp | 9 +++++++++ src/ui/mainwindow.cpp | 18 +++++++++++------- src/ui/mainwindow.h | 3 ++- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 00ea78b5b..e390c7942 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -83,11 +83,17 @@ Application::Application(const SearchQuery &query, QObject *parent) : if (connection->bytesAvailable()) { QDataStream in(connection); Zeal::SearchQuery query; + bool preventActivation; in >> query; - m_mainWindow->bringToFront(query); - } else { - m_mainWindow->bringToFront(); + in >> preventActivation; + + m_mainWindow->search(query); + + if (preventActivation) + return; } + + m_mainWindow->bringToFront(); }); /// TODO: Verify if removeServer() is needed QLocalServer::removeServer(LocalServerName); // remove in case previous instance crashed @@ -103,12 +109,12 @@ Application::Application(const SearchQuery &query, QObject *parent) : connect(m_settings, &Settings::updated, this, &Application::applySettings); applySettings(); - if (!query.isEmpty()) - m_mainWindow->bringToFront(query); - else if (m_settings->startMinimized) + if (m_settings->startMinimized) m_mainWindow->showMinimized(); else m_mainWindow->show(); + + m_mainWindow->search(query); } Application::~Application() diff --git a/src/main.cpp b/src/main.cpp index 022d981f7..fcbb1f379 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,7 @@ struct CommandLineParameters { bool force; + bool preventActivation; Zeal::SearchQuery query; #ifdef Q_OS_WIN32 bool registerProtocolHandlers; @@ -84,6 +85,7 @@ CommandLineParameters parseCommandLine(const QStringList &arguments) CommandLineParameters clParams; clParams.force = parser.isSet(QStringLiteral("force")); + clParams.preventActivation = false; #ifdef Q_OS_WIN32 clParams.registerProtocolHandlers = parser.isSet(QStringLiteral("register")); @@ -102,10 +104,16 @@ CommandLineParameters parseCommandLine(const QStringList &arguments) clParams.query.setQuery(stripParameterUrl(arg, QStringLiteral("dash"))); } else if (arg.startsWith(QLatin1String("dash-plugin:"))) { const QUrlQuery urlQuery(stripParameterUrl(arg, QStringLiteral("dash-plugin"))); + const QString keys = urlQuery.queryItemValue(QStringLiteral("keys")); if (!keys.isEmpty()) clParams.query.setKeywords(keys.split(QLatin1Char(','))); + clParams.query.setQuery(urlQuery.queryItemValue(QStringLiteral("query"))); + + const QString preventActivation + = urlQuery.queryItemValue(QStringLiteral("prevent_activation")); + clParams.preventActivation = preventActivation == QLatin1String("true"); } else { clParams.query.setQuery(arg); } @@ -212,6 +220,7 @@ int main(int argc, char *argv[]) if (socket->waitForConnected(500)) { QDataStream out(socket.data()); out << clParams.query; + out << clParams.preventActivation; socket->flush(); return 0; } diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index bdda1d90f..10cf359ac 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -358,6 +358,15 @@ MainWindow::~MainWindow() } } +void MainWindow::search(const SearchQuery &query) +{ + if (query.isEmpty()) + return; + + ui->lineEdit->setText(query.toString()); + ui->treeView->activated(ui->treeView->currentIndex()); +} + void MainWindow::openDocset(const QModelIndex &index) { const QVariant urlStr = index.sibling(index.row(), 1).data(); @@ -743,19 +752,14 @@ void MainWindow::removeTrayIcon() #endif } -void MainWindow::bringToFront(const Zeal::SearchQuery &query) +void MainWindow::bringToFront() { show(); setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); raise(); activateWindow(); - ui->lineEdit->setFocus(); - if (!query.isEmpty()) { - ui->lineEdit->setText(query.toString()); - ui->treeView->setFocus(); - ui->treeView->activated(ui->treeView->currentIndex()); - } + ui->lineEdit->setFocus(); } void MainWindow::changeEvent(QEvent *event) diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index d94353ad2..6bf565f60 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -96,7 +96,8 @@ class MainWindow : public QMainWindow explicit MainWindow(Zeal::Core::Application *app, QWidget *parent = nullptr); ~MainWindow() override; - void bringToFront(const Zeal::SearchQuery &query = Zeal::SearchQuery()); + void search(const Zeal::SearchQuery &query); + void bringToFront(); void createTab(); public slots: From 32af98c00e6b3bd73671afc02e9c4540a0d6ec88 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 18 Jan 2016 11:27:41 -0500 Subject: [PATCH 016/273] ui: Optimize SettingsDialog::findDocsetListItem() Since only the first item is needed, there's no need to search through all items. --- src/ui/settingsdialog.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 5c4bc04d3..eff030ba1 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -543,13 +543,14 @@ void SettingsDialog::on_tabWidget_currentChanged(int current) QListWidgetItem *SettingsDialog::findDocsetListItem(const QString &title) const { - const QList items - = ui->availableDocsetList->findItems(title, Qt::MatchFixedString); + for (int i = 0; i < ui->availableDocsetList->count(); ++i) { + QListWidgetItem *item = ui->availableDocsetList->item(i); - if (items.isEmpty()) - return nullptr; + if (item->text() == title) + return item; + } - return items.first(); + return nullptr; } bool SettingsDialog::updatesAvailable() const From 851fccb65ccb6a57a39e3e649a9ad0e3d24db899 Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Fri, 4 Dec 2015 21:39:11 -0800 Subject: [PATCH 017/273] ui: Refactor MainWindow This commit moves logic responsible for UI updates into functions. This removes code duplication and fixes bug when search completes after ESC. --- src/ui/mainwindow.cpp | 62 ++++++++++++++++++++++++------------------- src/ui/mainwindow.h | 3 +++ 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 10cf359ac..1ed135153 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -184,8 +184,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->lineEdit->setTreeView(ui->treeView); ui->lineEdit->setFocus(); setupSearchBoxCompletions(); - ui->treeView->setModel(m_zealListModel); - ui->treeView->setColumnHidden(1, true); SearchItemDelegate *delegate = new SearchItemDelegate(ui->treeView); connect(ui->lineEdit, &QLineEdit::textChanged, [delegate](const QString &text) { delegate->setHighlight(Zeal::SearchQuery::fromString(text).query()); @@ -231,9 +229,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QDesktopServices::openUrl(url); }); - ui->sections->hide(); - ui->seeAlsoLabel->hide(); - ui->sections->setModel(m_searchState->sectionsList); connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, &MainWindow::onSearchComplete); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, @@ -262,8 +257,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_application->docsetRegistry()->search(text); if (text.isEmpty()) { m_searchState->sectionsList->setResults(); - ui->treeView->setModel(m_zealListModel); - ui->treeView->setRootIsDecorated(true); + displayTreeView(); } }); @@ -404,10 +398,9 @@ QIcon MainWindow::docsetIcon(const QString &docsetName) const void MainWindow::queryCompleted() { - m_treeViewClicked = true; + displayTreeView(); - ui->treeView->setModel(m_searchState->zealSearch); - ui->treeView->setRootIsDecorated(false); + m_treeViewClicked = true; ui->treeView->setCurrentIndex(m_searchState->zealSearch->index(0, 0, QModelIndex())); ui->treeView->activated(ui->treeView->currentIndex()); } @@ -455,11 +448,7 @@ void MainWindow::createTab() newTab->sectionsList = new Zeal::SearchModel(); connect(newTab->zealSearch, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); - connect(newTab->sectionsList, &SearchModel::queryCompleted, [=]() { - const bool hasResults = newTab->sectionsList->rowCount(); - ui->sections->setVisible(hasResults); - ui->seeAlsoLabel->setVisible(hasResults); - }); + connect(newTab->sectionsList, &SearchModel::queryCompleted, this, &MainWindow::displaySections); newTab->page = new QWebPage(ui->webView); #ifdef USE_WEBENGINE @@ -477,6 +466,33 @@ void MainWindow::createTab() m_tabBar->setCurrentIndex(index); } +void MainWindow::displayTreeView() +{ + SearchState *searchState = currentSearchState(); + + if (!searchState->searchQuery.isEmpty()) { + ui->treeView->setModel(searchState->zealSearch); + ui->treeView->setRootIsDecorated(false); + } else { + ui->treeView->setModel(m_zealListModel); + ui->treeView->setColumnHidden(1, true); + ui->treeView->setRootIsDecorated(true); + } + ui->treeView->reset(); +} + +void MainWindow::displaySections() +{ + const bool hasResults = currentSearchState()->sectionsList->rowCount(); + ui->sections->setVisible(hasResults); + ui->seeAlsoLabel->setVisible(hasResults); +} + +SearchState *MainWindow::currentSearchState() const +{ + return m_tabs.at(m_tabBar->currentIndex()); +} + void MainWindow::displayTabs() { ui->menuTabs->clear(); @@ -526,19 +542,13 @@ void MainWindow::displayTabs() void MainWindow::reloadTabState() { - SearchState *searchState = m_tabs.at(m_tabBar->currentIndex()); + SearchState *searchState = currentSearchState(); ui->lineEdit->setText(searchState->searchQuery); ui->sections->setModel(searchState->sectionsList); - if (!searchState->searchQuery.isEmpty()) { - ui->treeView->setModel(searchState->zealSearch); - ui->treeView->setRootIsDecorated(false); - } else { - ui->treeView->setModel(m_zealListModel); - ui->treeView->setRootIsDecorated(true); - ui->treeView->reset(); - } + displaySections(); + displayTreeView(); // Bring back the selections and expansions ui->treeView->blockSignals(true); @@ -551,10 +561,6 @@ void MainWindow::reloadTabState() ui->webView->setPage(searchState->page); ui->webView->setZoomFactor(searchState->zoomFactor); - int resultCount = searchState->sectionsList->rowCount(); - ui->sections->setVisible(resultCount > 1); - ui->seeAlsoLabel->setVisible(resultCount > 1); - m_searchState = searchState; // scroll after the object gets loaded diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 6bf565f60..3e8cfe0cb 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -123,9 +123,12 @@ private slots: private: void displayViewActions(); + void displayTreeView(); + void displaySections(); void setupSearchBoxCompletions(); void reloadTabState(); void displayTabs(); + SearchState *currentSearchState() const; QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; QAction *addHistoryAction(QWebHistory *history, const QWebHistoryItem &item); From 522e5148c9c03b2c0e1b3db3365f1880f41cdcc6 Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Sun, 6 Dec 2015 10:55:13 -0800 Subject: [PATCH 018/273] ui: Make section list resizable --- src/core/settings.cpp | 15 +++++- src/core/settings.h | 3 +- src/ui/forms/mainwindow.ui | 97 +++++++++++++++++++++++++++----------- src/ui/mainwindow.cpp | 20 ++++++-- src/ui/mainwindow.h | 1 + 5 files changed, 101 insertions(+), 35 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 5a7342045..dc7039233 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -119,7 +119,13 @@ void Settings::load() m_settings->beginGroup(GroupState); windowGeometry = m_settings->value(QStringLiteral("window_geometry")).toByteArray(); - splitterGeometry = m_settings->value(QStringLiteral("splitter_geometry")).toByteArray(); + verticalSplitterGeometry = m_settings->value(QStringLiteral("splitter_geometry")).toByteArray(); + + sectionsSplitterSizes = QList(); + QList splitterSizes = m_settings->value(QStringLiteral("sections_geometry")).toList(); + for (QVariant splitterSize: splitterSizes) + sectionsSplitterSizes << splitterSize.toInt(); + m_settings->endGroup(); m_settings->beginGroup(GroupInternal); @@ -164,9 +170,14 @@ void Settings::save() m_settings->endGroup(); #endif + QList splitterSizes; + for (int splitterSize: sectionsSplitterSizes) + splitterSizes << splitterSize; + m_settings->beginGroup(GroupState); m_settings->setValue(QStringLiteral("window_geometry"), windowGeometry); - m_settings->setValue(QStringLiteral("splitter_geometry"), splitterGeometry); + m_settings->setValue(QStringLiteral("splitter_geometry"), verticalSplitterGeometry); + m_settings->setValue(QStringLiteral("sections_geometry"), splitterSizes); m_settings->endGroup(); m_settings->beginGroup(GroupInternal); diff --git a/src/core/settings.h b/src/core/settings.h index c798f6327..c09b87bdd 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -88,7 +88,8 @@ class Settings : public QObject // State QByteArray windowGeometry; - QByteArray splitterGeometry; + QByteArray verticalSplitterGeometry; + QList sectionsSplitterSizes; explicit Settings(QObject *parent = nullptr); ~Settings() override; diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index e31299056..e30190ce0 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -53,7 +53,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { 1 - + 0 @@ -95,36 +95,77 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { - - - QFrame::NoFrame + + + 5 - - QAbstractItemView::SelectItems + + Qt::Vertical - - 10 - - - false - - - - - - - See also - - - 2 - - - - - - - Qt::ScrollBarAlwaysOff + + 1 + + + QFrame::NoFrame + + + QAbstractItemView::SelectItems + + + 10 + + + false + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 9 + + + + * { padding: 0 2px; } + + + See also + + + 2 + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + + + diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 1ed135153..dbbe1f47f 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -104,10 +104,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->lineEdit, static_cast(&SearchEdit::setFocus)); restoreGeometry(m_settings->windowGeometry); - ui->splitter->restoreState(m_settings->splitterGeometry); - connect(ui->splitter, &QSplitter::splitterMoved, [=](int, int) { - m_settings->splitterGeometry = ui->splitter->saveState(); - }); + ui->splitter->restoreState(m_settings->verticalSplitterGeometry); m_zealNetworkManager = new NetworkAccessManager(this); #ifdef USE_WEBENGINE @@ -483,9 +480,21 @@ void MainWindow::displayTreeView() void MainWindow::displaySections() { + saveSectionsSplitterState(); + const bool hasResults = currentSearchState()->sectionsList->rowCount(); ui->sections->setVisible(hasResults); ui->seeAlsoLabel->setVisible(hasResults); + QList sizes = hasResults + ? m_settings->sectionsSplitterSizes + : QList({1, 0}); + ui->sectionsSplitter->setSizes(sizes); +} + +void MainWindow::saveSectionsSplitterState() +{ + if (ui->sections->isVisible()) + m_settings->sectionsSplitterSizes = ui->sectionsSplitter->sizes(); } SearchState *MainWindow::currentSearchState() const @@ -779,6 +788,9 @@ void MainWindow::changeEvent(QEvent *event) void MainWindow::closeEvent(QCloseEvent *event) { + m_settings->verticalSplitterGeometry = ui->splitter->saveState(); + saveSectionsSplitterState(); + m_settings->windowGeometry = saveGeometry(); if (m_settings->showSystrayIcon && m_settings->hideOnClose) { event->ignore(); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 3e8cfe0cb..816f23d8a 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -125,6 +125,7 @@ private slots: void displayViewActions(); void displayTreeView(); void displaySections(); + void saveSectionsSplitterState(); void setupSearchBoxCompletions(); void reloadTabState(); void displayTabs(); From 92f9538be340740c2f290aa3b7e3b76e6fa59758 Mon Sep 17 00:00:00 2001 From: Gustavo Brunoro Date: Tue, 5 Jan 2016 00:06:17 +0100 Subject: [PATCH 019/273] ui: Implement filtering of available docsets in Settings --- src/ui/forms/settingsdialog.ui | 7 +++++++ src/ui/settingsdialog.cpp | 17 +++++++++++++++++ src/ui/settingsdialog.h | 1 + 3 files changed, 25 insertions(+) diff --git a/src/ui/forms/settingsdialog.ui b/src/ui/forms/settingsdialog.ui index 711ca14cf..4ced6bc74 100644 --- a/src/ui/forms/settingsdialog.ui +++ b/src/ui/forms/settingsdialog.ui @@ -465,6 +465,13 @@ + + + + filter docsets + + + diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index eff030ba1..1c08ac174 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -111,6 +111,8 @@ SettingsDialog::SettingsDialog(Core::Application *app, ListModel *listModel, QWi this, &SettingsDialog::updateAllDocsets); connect(ui->removeDocsetsButton, &QPushButton::clicked, this, &SettingsDialog::removeSelectedDocsets); + connect(ui->docsetFilterInput, &QLineEdit::textEdited, + this, &SettingsDialog::updateDocsetFilter); ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); @@ -213,6 +215,21 @@ void SettingsDialog::removeSelectedDocsets() removeDocsets(names); } +void SettingsDialog::updateDocsetFilter(const QString &filterString) +{ + const bool doSearch = !filterString.simplified().isEmpty(); + + for (int i = 0; i < ui->availableDocsetList->count(); ++i) { + QListWidgetItem *item = ui->availableDocsetList->item(i); + + // Skip installed docsets + if (m_docsetRegistry->contains(item->data(ListModel::DocsetNameRole).toString())) + continue; + + item->setHidden(doSearch && !item->text().contains(filterString, Qt::CaseInsensitive)); + } +} + /*! \internal Should be connected to all \l QNetworkReply::finished signals in order to process possible diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index e951a7e15..725808e16 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -61,6 +61,7 @@ private slots: void updateSelectedDocsets(); void updateAllDocsets(); void removeSelectedDocsets(); + void updateDocsetFilter(const QString &filterString); void downloadCompleted(); void downloadProgress(qint64 received, qint64 total); From da5186ac80d13aed4c2972ad8d9f3bbface2c951 Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Fri, 4 Dec 2015 21:42:25 -0800 Subject: [PATCH 020/273] ui: Update completions on docset add (fixes #478) Update completions in search box whenever a docset is installed or removed. --- src/ui/mainwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index dbbe1f47f..431630770 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -230,6 +230,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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) @@ -246,6 +247,11 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } }); + 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; From d25283dd42bb0d6d6bada462b0ad16a7c832325d Mon Sep 17 00:00:00 2001 From: Serge45 Date: Fri, 4 Dec 2015 16:47:31 +0800 Subject: [PATCH 021/273] registry, ui: Fix crash on docset removal (fixes #436). --- src/registry/searchmodel.cpp | 30 ++++++++++++++++++++++++++++++ src/registry/searchmodel.h | 2 ++ src/ui/mainwindow.cpp | 10 ++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index e4cc0aa85..cdd443c8b 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -97,6 +97,36 @@ int SearchModel::columnCount(const QModelIndex &parent) const return 2; } +bool SearchModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (row + count <= m_dataList.size() && !parent.isValid()) { + beginRemoveRows(parent, row, row + count - 1); + while (count) { + m_dataList.removeAt(row); + --count; + } + endRemoveRows(); + return true; + } + return false; +} + +void SearchModel::removeSearchResultWithName(const QString &name) +{ + QMutableListIterator iterator(m_dataList); + + int rowNum = 0; + while (iterator.hasNext()) { + if (iterator.next().docset->name() == name) { + beginRemoveRows(QModelIndex(), rowNum, rowNum); + iterator.remove(); + rowNum -= 1; + endRemoveRows(); + } + rowNum += 1; + } +} + void SearchModel::setResults(const QList &results) { beginResetModel(); diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index f7a14cd3b..80f74904b 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -45,6 +45,8 @@ class SearchModel : public QAbstractItemModel QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent) const override; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + void removeSearchResultWithName(const QString &name); public slots: void setResults(const QList &results = QList()); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 431630770..fe9f399a8 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -241,6 +241,16 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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 From d37dbae1d47dc4fa295def5e0cae63f93f2cb2f1 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 27 Jan 2016 00:52:29 -0500 Subject: [PATCH 022/273] ui: Remove old workaround for QWindowsVistaStyle --- src/main.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fcbb1f379..c3760459c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,9 +37,7 @@ #include #ifdef Q_OS_WIN32 -#include #include -#include #endif struct CommandLineParameters @@ -162,24 +160,6 @@ void unregisterProtocolHandlers(const QHash &protocols) for (auto it = protocols.cbegin(); it != protocols.cend(); ++it) reg->remove(it.key()); } - -/// TODO: Verify if this bug still exists in Qt 5.2+ -class ZealProxyStyle : public QProxyStyle -{ -public: - void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, - const QWidget *widget = nullptr) const - { - if (element == PE_FrameLineEdit && option->styleObject) { - option->styleObject->setProperty("_q_no_animation", true); - // Workaround for a probable bug in QWindowsVistaStyle - for example opening the 'String (CommandEvent)' - // item from wxPython docset (available at http://wxpython.org/Phoenix/docsets) causes very high CPU usage. - // Some rough debugging shows that the 'd->startAnimation(t);' call in QWindowsVistaStyle::drawPrimitive - // is the cuplrit and setting _q_no_animation to true here fixes the issue. - } - return QProxyStyle::drawPrimitive(element, option, painter, widget); - } -}; #endif int main(int argc, char *argv[]) @@ -207,8 +187,6 @@ int main(int argc, char *argv[]) if (clParams.registerProtocolHandlers) ::exit(EXIT_SUCCESS); } - - qapp->setStyle(new ZealProxyStyle()); #endif From 601da85cd8e2fd0da794ee69a141d2482e1db075 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 27 Jan 2016 23:28:00 -0500 Subject: [PATCH 023/273] ui: Select rows instead if items in the index tree view This fixes non-native looking tree view selection on Windows. --- src/ui/forms/mainwindow.ui | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index e30190ce0..73b3d6164 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -109,9 +109,6 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { QFrame::NoFrame - - QAbstractItemView::SelectItems - 10 From b6356a33fa2e39c1c2c1f9b569a8d7f95f268172 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 4 Feb 2016 01:05:02 -0500 Subject: [PATCH 024/273] ui: Keep cache location next to binary in the portable build (#486) --- src/ui/settingsdialog.cpp | 21 +++++++++++++++------ src/ui/settingsdialog.h | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 1c08ac174..4a97e07cd 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -299,8 +299,7 @@ void SettingsDialog::downloadCompleted() case DownloadDocsetList: { const QByteArray data = reply->readAll(); - const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - QScopedPointer file(new QFile(cacheDir.filePath(DocsetListCacheFileName))); + QScopedPointer file(new QFile(cacheLocation(DocsetListCacheFileName))); if (file->open(QIODevice::WriteOnly)) file->write(data); @@ -529,10 +528,7 @@ void SettingsDialog::on_tabWidget_currentChanged(int current) if (ui->tabWidget->widget(current) != ui->docsetsTab || ui->availableDocsetList->count()) return; - const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); - if (!cacheDir.exists()) - QDir().mkpath(cacheDir.absolutePath()); - const QFileInfo fi(cacheDir.filePath(DocsetListCacheFileName)); + const QFileInfo fi(cacheLocation(DocsetListCacheFileName)); if (!fi.exists() || fi.lastModified().msecsTo(QDateTime::currentDateTime()) > CacheTimeout) { downloadDocsetList(); @@ -835,3 +831,16 @@ int SettingsDialog::percent(qint64 fraction, qint64 total) return fraction / static_cast(total) * 100; } + +QString SettingsDialog::cacheLocation(const QString &fileName) +{ +#ifndef PORTABLE_BUILD + const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); +#else + const QDir cacheDir(QCoreApplication::applicationDirPath() + QLatin1String("/cache")); +#endif + /// TODO: Report error + QDir().mkpath(cacheDir.path()); + + return cacheDir.filePath(fileName); +} diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 725808e16..133ec33b7 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -113,6 +113,8 @@ private slots: void loadSettings(); void saveSettings(); static inline int percent(qint64 fraction, qint64 total); + + static QString cacheLocation(const QString &fileName); }; } // namespace Zeal From 75392823b22a44a21b038dff307bb5620e2608d4 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Feb 2016 10:21:30 -0500 Subject: [PATCH 025/273] core: Restrict QString conversion from ASCII, and disable to ASCII Define QT_RESTRICTED_CAST_FROM_ASCII & QT_NO_CAST_TO_ASCII. --- src/core/application.cpp | 11 +++++------ src/core/extractor.cpp | 2 +- src/src.pro | 4 ++++ src/util/version.cpp | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index e390c7942..ed0955b9b 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -46,7 +46,6 @@ using namespace Zeal; using namespace Zeal::Core; namespace { -const char LocalServerName[] = "ZealLocalServer"; const char ReleasesApiUrl[] = "http://api.zealdocs.org/v1/releases"; } @@ -96,8 +95,8 @@ Application::Application(const SearchQuery &query, QObject *parent) : m_mainWindow->bringToFront(); }); /// TODO: Verify if removeServer() is needed - QLocalServer::removeServer(LocalServerName); // remove in case previous instance crashed - m_localServer->listen(LocalServerName); + QLocalServer::removeServer(localServerName()); // remove in case previous instance crashed + m_localServer->listen(localServerName()); // Extractor setup m_extractor->moveToThread(m_extractorThread); @@ -128,7 +127,7 @@ Application::~Application() QString Application::localServerName() { - return LocalServerName; + return QStringLiteral("ZealLocalServer"); } QNetworkAccessManager *Application::networkManager() const @@ -230,7 +229,7 @@ void Application::applySettings() QString Application::userAgent() { - return QString("Zeal/%1").arg(QCoreApplication::applicationVersion()); + return QStringLiteral("Zeal/%1").arg(QCoreApplication::applicationVersion()); } QString Application::userAgentJson() const @@ -298,5 +297,5 @@ QString Application::userAgentJson() const #endif // QT_VERSION >= 0x050400 - return QJsonDocument(ua).toJson(QJsonDocument::Compact); + return QString::fromUtf8(QJsonDocument(ua).toJson(QJsonDocument::Compact)); } diff --git a/src/core/extractor.cpp b/src/core/extractor.cpp index 1fd38a4ef..1f71b4e6e 100644 --- a/src/core/extractor.cpp +++ b/src/core/extractor.cpp @@ -63,7 +63,7 @@ void Extractor::extract(const QString &filePath, const QString &destination, con /// TODO: Do not strip root directory in archive if it equals to 'root' archive_entry *entry; while (archive_read_next_header(info.archiveHandle, &entry) == ARCHIVE_OK) { - QString pathname = archive_entry_pathname(entry); + QString pathname = QString::fromUtf8(archive_entry_pathname(entry)); if (!root.isEmpty()) pathname.remove(0, pathname.indexOf(QLatin1String("/")) + 1); archive_entry_set_pathname(entry, qPrintable(destinationDir.absoluteFilePath(pathname))); diff --git a/src/src.pro b/src/src.pro index 3dc66ac0b..fff605f84 100644 --- a/src/src.pro +++ b/src/src.pro @@ -18,6 +18,10 @@ portable { VERSION = 0.2.1 DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" +# QString options +DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII +DEFINES *= QT_NO_CAST_TO_ASCII + HEADERS += \ util/version.h \ util/plist.h diff --git a/src/util/version.cpp b/src/util/version.cpp index 0c5fd2f89..207e9e3d9 100644 --- a/src/util/version.cpp +++ b/src/util/version.cpp @@ -45,7 +45,7 @@ bool Version::isValid() const QString Version::toString() const { - return QString("%1.%2.%3").arg(m_major).arg(m_minor).arg(m_patch); + return QStringLiteral("%1.%2.%3").arg(m_major).arg(m_minor).arg(m_patch); } bool Version::fromString(const QString &str) From 3b22972a78010d5a860e7515546962ed71da2568 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Feb 2016 10:47:40 -0500 Subject: [PATCH 026/273] core: Enable QStringBuilder Define QT_USE_QSTRINGBUILDER. --- src/main.cpp | 2 +- src/src.pro | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index c3760459c..2155791b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -137,7 +137,7 @@ void registerProtocolHandler(const QString &scheme, const QString &description) reg->beginGroup(QStringLiteral("shell")); reg->beginGroup(QStringLiteral("open")); reg->beginGroup(QStringLiteral("command")); - reg->setValue(QStringLiteral("Default"), appPath + QLatin1String(" %1")); + reg->setValue(QStringLiteral("Default"), QVariant(appPath + QLatin1String(" %1"))); } void registerProtocolHandlers(const QHash &protocols, bool force = false) diff --git a/src/src.pro b/src/src.pro index fff605f84..625b974ca 100644 --- a/src/src.pro +++ b/src/src.pro @@ -19,6 +19,7 @@ VERSION = 0.2.1 DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" # QString options +DEFINES *= QT_USE_QSTRINGBUILDER DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII DEFINES *= QT_NO_CAST_TO_ASCII From 0136f9c9e44ef495b887f9d5af20073635020b2d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Feb 2016 10:48:45 -0500 Subject: [PATCH 027/273] core, ui: Disable implicit conversion from QString to QUrl Define QT_NO_URL_CAST_FROM_STRING. --- src/core/settings.cpp | 3 ++- src/main.cpp | 2 +- src/registry/docsetmetadata.cpp | 6 +++--- src/src.pro | 1 + src/ui/mainwindow.cpp | 4 ++-- src/ui/settingsdialog.cpp | 12 ++++++------ 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index dc7039233..c1a16f981 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -59,7 +59,8 @@ Settings::Settings(QObject *parent) : { /// TODO: Move to user style sheet (related to #268) #ifndef USE_WEBENGINE - QWebSettings::globalSettings()->setUserStyleSheetUrl(QStringLiteral("qrc:///browser/highlight.css")); + QWebSettings::globalSettings() + ->setUserStyleSheetUrl(QUrl(QStringLiteral("qrc:///browser/highlight.css"))); #endif load(); diff --git a/src/main.cpp b/src/main.cpp index 2155791b2..f3c05794a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -211,7 +211,7 @@ int main(int argc, char *argv[]) QObject::tr("Qt SQLite driver is not available."), QMessageBox::Close, QMessageBox::Help); if (ret == QMessageBox::Help) - QDesktopServices::openUrl(QStringLiteral("https://zealdocs.org/contact.html")); + QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/contact.html"))); return 0; } diff --git a/src/registry/docsetmetadata.cpp b/src/registry/docsetmetadata.cpp index 1e4c9f0ef..5399f7678 100644 --- a/src/registry/docsetmetadata.cpp +++ b/src/registry/docsetmetadata.cpp @@ -62,10 +62,10 @@ DocsetMetadata::DocsetMetadata(const QJsonObject &jsonObject) m_versions << vv.toString(); m_revision = jsonObject[QStringLiteral("revision")].toString(); - m_feedUrl = jsonObject[QStringLiteral("feed_url")].toString(); + m_feedUrl = QUrl(jsonObject[QStringLiteral("feed_url")].toString()); const QJsonArray urlArray = jsonObject[QStringLiteral("urls")].toArray(); for (const QJsonValue &url : urlArray) - m_urls.append(url.toString()); + m_urls.append(QUrl(url.toString())); m_extra = jsonObject[QStringLiteral("extra")].toObject(); } @@ -207,7 +207,7 @@ DocsetMetadata DocsetMetadata::fromDashFeed(const QUrl &feedUrl, const QByteArra } else if (xml.name() == QLatin1String("url")) { if (xml.readNext() != QXmlStreamReader::Characters) continue; - metadata.m_urls.append(xml.text().toString()); + metadata.m_urls.append(QUrl(xml.text().toString())); } } diff --git a/src/src.pro b/src/src.pro index 625b974ca..c4d95e0bf 100644 --- a/src/src.pro +++ b/src/src.pro @@ -22,6 +22,7 @@ DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" DEFINES *= QT_USE_QSTRINGBUILDER DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII DEFINES *= QT_NO_CAST_TO_ASCII +DEFINES *= QT_NO_URL_CAST_FROM_STRING HEADERS += \ util/version.h \ diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fe9f399a8..ebc5b1ef3 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -139,7 +139,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : // Help Menu connect(ui->actionReportProblem, &QAction::triggered, [this]() { - QDesktopServices::openUrl(QStringLiteral("https://github.com/zealdocs/zeal/issues")); + QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/zealdocs/zeal/issues"))); }); connect(ui->actionCheckForUpdate, &QAction::triggered, m_application, &Core::Application::checkForUpdate); @@ -166,7 +166,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QString(tr("A new version %1 is available. Open download page?")).arg(version), QMessageBox::Yes, QMessageBox::No); if (ret == QMessageBox::Yes) - QDesktopServices::openUrl(QStringLiteral("https://zealdocs.org/download.html")); + QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/download.html"))); }); m_backMenu = new QMenu(ui->backButton); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 4a97e07cd..2555d64d2 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -149,12 +149,12 @@ SettingsDialog::~SettingsDialog() void SettingsDialog::addDashFeed() { - QString txt = QApplication::clipboard()->text(); - if (!txt.startsWith(QLatin1String("dash-feed://"))) - txt.clear(); + QString clipboardText = QApplication::clipboard()->text(); + if (!clipboardText.startsWith(QLatin1String("dash-feed://"))) + clipboardText.clear(); QString feedUrl = QInputDialog::getText(this, QStringLiteral("Zeal"), tr("Feed URL:"), - QLineEdit::Normal, txt); + QLineEdit::Normal, clipboardText); if (feedUrl.isEmpty()) return; @@ -163,7 +163,7 @@ void SettingsDialog::addDashFeed() feedUrl = QUrl::fromPercentEncoding(feedUrl.toUtf8()); } - QNetworkReply *reply = download(feedUrl); + QNetworkReply *reply = download(QUrl(feedUrl)); reply->setProperty(DownloadTypeProperty, DownloadDashFeed); connect(reply, &QNetworkReply::finished, this, &SettingsDialog::downloadCompleted); } @@ -667,7 +667,7 @@ void SettingsDialog::downloadDashDocset(const QString &name) return; const QString urlString = RedirectServerUrl + QStringLiteral("/d/com.kapeli/%1/latest"); - QNetworkReply *reply = download(urlString.arg(name)); + QNetworkReply *reply = download(QUrl(urlString.arg(name))); reply->setProperty(DocsetNameProperty, name); reply->setProperty(DownloadTypeProperty, DownloadDocset); reply->setProperty(ListItemIndexProperty, From d267e07da2ee350fe14631c599cf9950704e918c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 15 Feb 2016 00:52:05 -0500 Subject: [PATCH 028/273] ui: Fix wording for the update checker (fixes #492) --- src/core/application.cpp | 2 +- src/core/application.h | 2 +- src/ui/forms/mainwindow.ui | 6 +++--- src/ui/mainwindow.cpp | 9 +++++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index ed0955b9b..7a30a6a05 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -172,7 +172,7 @@ QNetworkReply *Application::download(const QUrl &url) Performs a check whether a new Zeal version is available. Setting \a quiet to true supresses error and "you are using the latest version" message boxes. */ -void Application::checkForUpdate(bool quiet) +void Application::checkForUpdates(bool quiet) { QNetworkReply *reply = download(QUrl(ReleasesApiUrl)); connect(reply, &QNetworkReply::finished, this, [this, quiet]() { diff --git a/src/core/application.h b/src/core/application.h index 7d2fdf594..b72e0c17b 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -61,7 +61,7 @@ class Application : public QObject public slots: void extract(const QString &filePath, const QString &destination, const QString &root = QString()); QNetworkReply *download(const QUrl &url); - void checkForUpdate(bool quiet = false); + void checkForUpdates(bool quiet = false); signals: void extractionCompleted(const QString &filePath); diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 73b3d6164..4ba53da2f 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -262,7 +262,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { &Help - + @@ -347,9 +347,9 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { &Report Problem... - + - &Check for Update... + &Check for updates... diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ebc5b1ef3..4cae3f05b 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -141,8 +141,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->actionReportProblem, &QAction::triggered, [this]() { QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/zealdocs/zeal/issues"))); }); - connect(ui->actionCheckForUpdate, &QAction::triggered, - m_application, &Core::Application::checkForUpdate); + connect(ui->actionCheckForUpdates, &QAction::triggered, + m_application, &Core::Application::checkForUpdates); connect(ui->actionAboutZeal, &QAction::triggered, [this]() { QScopedPointer dialog(new AboutDialog(this)); dialog->exec(); @@ -158,7 +158,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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.")); + QMessageBox::information(this, QStringLiteral("Zeal"), + tr("You are using the latest version of Zeal.")); return; } @@ -351,7 +352,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } if (m_settings->checkForUpdate) - m_application->checkForUpdate(true); + m_application->checkForUpdates(true); } MainWindow::~MainWindow() From 98282d5808f91afa203c5460cacb7d421f3412cb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 15 Feb 2016 01:00:10 -0500 Subject: [PATCH 029/273] ui: Disable context help button in the about dialog (fixes #493) --- src/ui/aboutdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index 9b08927c1..61d656f5c 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -30,6 +30,7 @@ AboutDialog::AboutDialog(QWidget *parent) : ui(new Ui::AboutDialog) { ui->setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); const QString buildInfo = QString(tr("Version: %1
")) .arg(QCoreApplication::applicationVersion()); From 3227974829dcb99a046f0a568615183a386c33f0 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 15 Feb 2016 10:15:02 -0500 Subject: [PATCH 030/273] ui: Do not disable available docset list during download (fixes #480) --- src/ui/settingsdialog.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 2555d64d2..a87ffac01 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -591,7 +591,6 @@ QNetworkReply *SettingsDialog::download(const QUrl &url) ui->removeDocsetsButton->setEnabled(false); // Available docsets - ui->availableDocsetList->setEnabled(false); ui->refreshButton->setEnabled(false); ui->downloadDocsetButton->setText(tr("Stop downloads")); @@ -744,7 +743,6 @@ void SettingsDialog::resetProgress() ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); // Available docsets - ui->availableDocsetList->setEnabled(true); ui->refreshButton->setEnabled(true); ui->downloadDocsetButton->setText(tr("Download")); } From 8c979c5325f8408221da2f603e394517d8af8511 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 15 Feb 2016 10:17:51 -0500 Subject: [PATCH 031/273] ui: Enable clear button in the available docset filter --- src/ui/forms/settingsdialog.ui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ui/forms/settingsdialog.ui b/src/ui/forms/settingsdialog.ui index 4ced6bc74..8b35742e5 100644 --- a/src/ui/forms/settingsdialog.ui +++ b/src/ui/forms/settingsdialog.ui @@ -468,7 +468,10 @@ - filter docsets + Filter docsets + + + true From e0695bafd6bb0a899664234e2707a3e6b19620dd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 15 Feb 2016 10:21:21 -0500 Subject: [PATCH 032/273] ui: s/Report Problem/Submit Feedback (fixes #494) --- src/ui/forms/mainwindow.ui | 6 +++--- src/ui/mainwindow.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 4ba53da2f..84eb97852 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -261,7 +261,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { &Help - + @@ -342,9 +342,9 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { Previous Tab
- + - &Report Problem... + &Submit Feedback... diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 4cae3f05b..7ac6fb497 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -138,7 +138,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->actionForward, &QAction::triggered, this, &MainWindow::forward); // Help Menu - connect(ui->actionReportProblem, &QAction::triggered, [this]() { + connect(ui->actionSubmitFeedback, &QAction::triggered, [this]() { QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/zealdocs/zeal/issues"))); }); connect(ui->actionCheckForUpdates, &QAction::triggered, From fe008a28597d6378ce73cd00222b281a2ae5c904 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 19 Feb 2016 02:50:05 -0500 Subject: [PATCH 033/273] ui: Use qgetenv() to read XDG_CURRENT_DESKTOP (fixes #496) --- src/ui/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 7ac6fb497..0ad4ffb79 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -697,7 +697,7 @@ void MainWindow::createTrayIcon() #endif #ifdef USE_APPINDICATOR - const QString desktop = getenv("XDG_CURRENT_DESKTOP"); + const QString desktop = qgetenv("XDG_CURRENT_DESKTOP"); const bool isUnity = (desktop.toLower() == QLatin1String("unity")); if (isUnity) { // Application Indicators for Unity @@ -764,7 +764,7 @@ void MainWindow::removeTrayIcon() #endif #ifdef USE_APPINDICATOR - const QString desktop = getenv("XDG_CURRENT_DESKTOP"); + const QString desktop = qgetenv("XDG_CURRENT_DESKTOP"); const bool isUnity = (desktop.toLower() == QLatin1String("unity")); if (isUnity) { From a96c79bd9bcbf2091b5f14beea81a3de615e223d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 19 Feb 2016 03:09:49 -0500 Subject: [PATCH 034/273] ui: Use AppIndicator with Cinnamon 2.8 (fixes #487) --- src/ui/mainwindow.cpp | 34 ++++++++++++++++++++++++++-------- src/ui/mainwindow.h | 5 +++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 0ad4ffb79..07be11bd4 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -92,6 +92,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : setWindowIcon(QIcon::fromTheme(QStringLiteral("zeal"), QIcon(QStringLiteral(":/zeal.ico")))); +#ifdef USE_APPINDICATOR + detectAppIndicatorSupport(); +#endif + if (m_settings->showSystrayIcon) createTrayIcon(); @@ -678,6 +682,26 @@ QAction *MainWindow::addHistoryAction(QWebHistory *history, const QWebHistoryIte return backAction; } +#ifdef USE_APPINDICATOR +void MainWindow::detectAppIndicatorSupport() +{ + const QByteArray xdgDesktop = qgetenv("XDG_CURRENT_DESKTOP"); + + // Unity + if (xdgDesktop == "Unity") { + m_useAppIndicator = true; + return; + } + + // Cinnamon 2.8 + // Checking specifically for 2.8 because direct AppIndicator support will be dropped soon. + if (xdgDesktop == "X-Cinnamon" && qgetenv("CINNAMON_VERSION").startsWith("2.8")) { + m_useAppIndicator = true; + return; + } +} +#endif + #ifdef USE_APPINDICATOR void appIndicatorToggleWindow(GtkMenu *menu, gpointer data) { @@ -697,10 +721,7 @@ void MainWindow::createTrayIcon() #endif #ifdef USE_APPINDICATOR - const QString desktop = qgetenv("XDG_CURRENT_DESKTOP"); - const bool isUnity = (desktop.toLower() == QLatin1String("unity")); - - if (isUnity) { // Application Indicators for Unity + if (m_useAppIndicator) { m_appIndicatorMenu = gtk_menu_new(); m_appIndicatorShowHideMenuItem = gtk_menu_item_new_with_label(qPrintable(tr("Hide"))); @@ -764,10 +785,7 @@ void MainWindow::removeTrayIcon() #endif #ifdef USE_APPINDICATOR - const QString desktop = qgetenv("XDG_CURRENT_DESKTOP"); - const bool isUnity = (desktop.toLower() == QLatin1String("unity")); - - if (isUnity) { + if (m_useAppIndicator) { g_clear_object(&m_appIndicator); g_clear_object(&m_appIndicatorMenu); g_clear_object(&m_appIndicatorShowHideMenuItem); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 816f23d8a..a841bf70a 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -133,6 +133,10 @@ private slots: QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; QAction *addHistoryAction(QWebHistory *history, const QWebHistoryItem &item); + +#ifdef USE_APPINDICATOR + void detectAppIndicatorSupport(); +#endif void createTrayIcon(); void removeTrayIcon(); @@ -159,6 +163,7 @@ private slots: QSystemTrayIcon *m_trayIcon = nullptr; #ifdef USE_APPINDICATOR + bool m_useAppIndicator = false; _AppIndicator *m_appIndicator = nullptr; _GtkWidget *m_appIndicatorMenu = nullptr; _GtkWidget *m_appIndicatorQuitMenuItem = nullptr; From 384dbe721264068ff27485b0315aa52cedd06a70 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 20 Feb 2016 00:50:00 -0500 Subject: [PATCH 035/273] core: Always show the main window on app start if query is present --- src/core/application.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 7a30a6a05..96f9b3a91 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -108,12 +108,16 @@ Application::Application(const SearchQuery &query, QObject *parent) : connect(m_settings, &Settings::updated, this, &Application::applySettings); applySettings(); + if (!query.isEmpty()) { + m_mainWindow->search(query); + m_mainWindow->show(); + return; + } + if (m_settings->startMinimized) m_mainWindow->showMinimized(); else m_mainWindow->show(); - - m_mainWindow->search(query); } Application::~Application() From fcfb9799a354d106e0593e0b16f2bf292b7ba2a3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 20 Feb 2016 00:51:44 -0500 Subject: [PATCH 036/273] core: Fix startMinimized && minimizeToSystray situation Don't show the main window if both options are set. --- src/core/application.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 96f9b3a91..d2592ecef 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -114,10 +114,14 @@ Application::Application(const SearchQuery &query, QObject *parent) : return; } - if (m_settings->startMinimized) + if (m_settings->startMinimized) { + if (m_settings->showSystrayIcon && m_settings->minimizeToSystray) + return; + m_mainWindow->showMinimized(); - else + } else { m_mainWindow->show(); + } } Application::~Application() From ce551a0b950bb838341381ad407d96fd7b5916e9 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 20 Feb 2016 02:02:33 -0500 Subject: [PATCH 037/273] core: Fix forward declaration order in application.h --- src/core/application.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/application.h b/src/core/application.h index b72e0c17b..e5fc11a1e 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -26,13 +26,12 @@ #include class QLocalServer; - -class MainWindow; - class QNetworkAccessManager; class QNetworkReply; class QThread; +class MainWindow; + namespace Zeal { class DocsetRegistry; From 4a1f6036b237e35ec8589d8afa3748bae68b25fa Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 20 Feb 2016 02:21:44 -0500 Subject: [PATCH 038/273] ui: Do not check for the pre-0.1 docset location --- src/ui/mainwindow.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 07be11bd4..05a2e2eee 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -341,20 +341,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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 %1. " - "You can move docsets to %2 or change the docset storage path in the settings.

" - "Please note, that old docsets cannot be updated automatically, so it is better to download your docsets again.

" - "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->checkForUpdates(true); } From 78636fe034d4fc21e09789c0683478ab5edec3a3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 20 Feb 2016 13:06:21 -0500 Subject: [PATCH 039/273] app: Do not allow Qt version downgrade in run time Always require at least the one the app was build against. --- src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index f3c05794a..132ad855d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -164,6 +164,9 @@ void unregisterProtocolHandlers(const QHash &protocols) int main(int argc, char *argv[]) { + // Do not allow Qt version lower than the app was compiled with. + QT_REQUIRE_VERSION(argc, argv, QT_VERSION_STR); + QCoreApplication::setApplicationName(QStringLiteral("Zeal")); QCoreApplication::setApplicationVersion(ZEAL_VERSION); QCoreApplication::setOrganizationDomain(QStringLiteral("zealdocs.org")); From bca48bb1374c1f929c881b23200f73637ab75b51 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 21 Feb 2016 14:48:43 -0500 Subject: [PATCH 040/273] ui: Disable context help button in the settings dialog Fixes #499. --- src/ui/settingsdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index a87ffac01..06512a1d7 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -76,6 +76,7 @@ SettingsDialog::SettingsDialog(Core::Application *app, ListModel *listModel, QWi m_docsetRegistry(app->docsetRegistry()) { ui->setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); #ifdef Q_OS_OSX ui->availableDocsetList->setAttribute(Qt::WA_MacShowFocusRect, false); From 3d0cf8b819e0d3e01bf9a1f9bca3c396db6681ad Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 21 Feb 2016 14:53:00 -0500 Subject: [PATCH 041/273] app: Remove unnessecary include --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 132ad855d..2bf3ac22b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include From 1f6faf864627d78bfb60401dd3245c5f32ac451f Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Sat, 20 Feb 2016 16:34:47 -0800 Subject: [PATCH 042/273] ui: Fix segfault for incomplete docsets --- src/ui/mainwindow.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 05a2e2eee..a2c981f70 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -613,8 +613,13 @@ void MainWindow::onSearchComplete() void MainWindow::setupSearchBoxCompletions() { QStringList completions; - for (const Docset * const docset: m_application->docsetRegistry()->docsets()) + for (const Docset * const docset: m_application->docsetRegistry()->docsets()) { + if (docset->keywords().isEmpty()) + continue; + completions << docset->keywords().first() + QLatin1Char(':'); + } + ui->lineEdit->setCompletions(completions); } From 3bf30183bcd9f9413be91fb42e82663074e0eff5 Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Sat, 20 Feb 2016 16:54:57 -0800 Subject: [PATCH 043/273] registry: Initialize Docset type at end of constructor This ensures that docset is valid if basic folder/file structure is present. --- src/registry/docset.cpp | 5 +++-- src/registry/docsetregistry.cpp | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 916a42013..d9052f754 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -121,8 +121,6 @@ Docset::Docset(const QString &path) : return; } - m_type = db.tables().contains(QStringLiteral("searchIndex")) ? Type::Dash : Type::ZDash; - createIndex(); if (!dir.cd(QStringLiteral("Documents"))) @@ -159,6 +157,9 @@ Docset::Docset(const QString &path) : } countSymbols(); + + // Since the docset was fully initialized set its type. + m_type = db.tables().contains(QStringLiteral("searchIndex")) ? Type::Dash : Type::ZDash; } Docset::~Docset() diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index d2f1ad913..c84080770 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -108,6 +108,7 @@ void DocsetRegistry::_addDocset(const QString &path) /// TODO: Emit error if (!docset->isValid()) { + qWarning("Could not load docset from '%s'. Please reinstall the docset.", qPrintable(path)); delete docset; return; } From ef37e8948ffb4f0a12c1ecc31a0c7524c2535175 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 23 Feb 2016 23:28:19 -0500 Subject: [PATCH 044/273] registry: Partially revert 3bf30183bcd9f9413be91fb42e82663074e0eff5 Fix the regression. Docset type detection cannot be delayed, because the loading process is slightly different for two supported docset formats. Fixes #502. --- src/registry/docset.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index d9052f754..2b6302819 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -121,6 +121,9 @@ Docset::Docset(const QString &path) : return; } + // Since the docset was fully initialized set its type. + m_type = db.tables().contains(QStringLiteral("searchIndex")) ? Type::Dash : Type::ZDash; + createIndex(); if (!dir.cd(QStringLiteral("Documents"))) @@ -157,9 +160,6 @@ Docset::Docset(const QString &path) : } countSymbols(); - - // Since the docset was fully initialized set its type. - m_type = db.tables().contains(QStringLiteral("searchIndex")) ? Type::Dash : Type::ZDash; } Docset::~Docset() From d2acc9cddb81c4cb2c99d415140b32c7f0965136 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 24 Feb 2016 23:35:17 -0500 Subject: [PATCH 045/273] registry: Small cleanup --- src/registry/docset.cpp | 4 +--- src/registry/docsetregistry.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 2b6302819..cab687cd9 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -121,7 +121,6 @@ Docset::Docset(const QString &path) : return; } - // Since the docset was fully initialized set its type. m_type = db.tables().contains(QStringLiteral("searchIndex")) ? Type::Dash : Type::ZDash; createIndex(); @@ -129,8 +128,7 @@ Docset::Docset(const QString &path) : if (!dir.cd(QStringLiteral("Documents"))) return; - // - // Setyp keywords + // Setup keywords if (plist.contains(InfoPlist::DocSetPlatformFamily)) m_keywords << plist[InfoPlist::DocSetPlatformFamily].toString(); diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index c84080770..f81c07761 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -28,8 +28,6 @@ #include #include #include -#include -#include using namespace Zeal; @@ -153,7 +151,7 @@ void DocsetRegistry::addDocsetsFromFolder(const QString &path) { const QDir dir(path); for (const QFileInfo &subdir : dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllDirs)) { - if (subdir.suffix() == QLatin1String("docset")) + if (subdir.suffix() == QStringLiteral("docset")) addDocset(subdir.absoluteFilePath()); else addDocsetsFromFolder(subdir.absoluteFilePath()); From 1b93b7906145d645b555e20441bac975a4e2b54a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 21 Feb 2016 14:59:41 -0500 Subject: [PATCH 046/273] ui: Do not apply styling to splitters --- src/ui/forms/mainwindow.ui | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 84eb97852..c92ebb2db 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -15,10 +15,6 @@ -QSplitter::handle { - background: black; -} - QFrame#searchEditFrame, QFrame#tabBarFrame { border-top: none; border-right: none; @@ -43,15 +39,6 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { - - 5 - - - Qt::Horizontal - - - 1 - @@ -96,15 +83,9 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { - - 5 - Qt::Vertical - - 1 - QFrame::NoFrame From 9a91910268ce65301a19d7666af72e213cda975e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 26 Feb 2016 00:50:57 -0500 Subject: [PATCH 047/273] ui: Replace styled QFrame with a simple toolbar widget --- src/ui/forms/mainwindow.ui | 24 ++++++++++-------------- src/ui/mainwindow.cpp | 2 +- src/ui/widgets/toolbarframe.cpp | 19 +++++++++++++++++++ src/ui/widgets/toolbarframe.h | 16 ++++++++++++++++ 4 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 src/ui/widgets/toolbarframe.cpp create mode 100644 src/ui/widgets/toolbarframe.h diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index c92ebb2db..16f85d58c 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -13,16 +13,6 @@ Zeal - - -QFrame#searchEditFrame, QFrame#tabBarFrame { - border-top: none; - border-right: none; - border-bottom: 1px solid black; - border-left: none; -} - - @@ -45,7 +35,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { 0 - + 0 @@ -55,7 +45,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { - + 6 @@ -154,7 +144,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { 0 - + 0 @@ -186,7 +176,7 @@ QFrame#searchEditFrame, QFrame#tabBarFrame { - + @@ -347,6 +337,12 @@ QFrame#searchEditFrame, QFrame#tabBarFrame {
ui/widgets/searchablewebview.h
1 + + ToolBarFrame + QWidget +
ui/widgets/toolbarframe.h
+ 1 +
diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a2c981f70..ee1049e9f 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -314,7 +314,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); { - QHBoxLayout *layout = reinterpret_cast(ui->tabBarFrame->layout()); + QHBoxLayout *layout = reinterpret_cast(ui->navigationBar->layout()); layout->insertWidget(2, m_tabBar, 0, Qt::AlignBottom); } diff --git a/src/ui/widgets/toolbarframe.cpp b/src/ui/widgets/toolbarframe.cpp new file mode 100644 index 000000000..a6bb706bf --- /dev/null +++ b/src/ui/widgets/toolbarframe.cpp @@ -0,0 +1,19 @@ +#include "toolbarframe.h" + +#include + +ToolBarFrame::ToolBarFrame(QWidget *parent) : QWidget(parent) +{ +} + +void ToolBarFrame::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + + // Draw a line at the bottom. + QPainter painter(this); + painter.save(); + painter.setPen(palette().dark().color()); + painter.drawLine(0, height() - 1, width(), height() - 1); + painter.restore(); +} diff --git a/src/ui/widgets/toolbarframe.h b/src/ui/widgets/toolbarframe.h new file mode 100644 index 000000000..64904202b --- /dev/null +++ b/src/ui/widgets/toolbarframe.h @@ -0,0 +1,16 @@ +#ifndef TOOLBARFRAME_H +#define TOOLBARFRAME_H + +#include + +class ToolBarFrame : public QWidget +{ + Q_OBJECT +public: + explicit ToolBarFrame(QWidget *parent = nullptr); + +private: + void paintEvent(QPaintEvent *event) override; +}; + +#endif // TOOLBARFRAME_H From 8bc7c9b84e61d68c60b3df34b08bbff66048d41b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 26 Feb 2016 00:52:48 -0500 Subject: [PATCH 048/273] ui: Cleanup mainwindow.ui --- src/ui/forms/mainwindow.ui | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 16f85d58c..dc98bf228 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -14,7 +14,7 @@ Zeal
- + 0 @@ -27,8 +27,11 @@ 0 - + + + Qt::Horizontal + @@ -176,21 +179,17 @@ - - - - - - 0 - 0 - - - - Open URL - - - - + + + + 0 + 0 + + + + Open URL + + @@ -217,7 +216,7 @@ 0 0 1050 - 23 + 22
From 97eec7afbf5952012be1b9582a21551b28983998 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 5 Feb 2016 23:48:09 -0500 Subject: [PATCH 049/273] ui: Remove SearchItemStyle --- src/ui/searchitemdelegate.cpp | 11 +++-------- src/ui/searchitemstyle.cpp | 35 ---------------------------------- src/ui/searchitemstyle.h | 36 ----------------------------------- 3 files changed, 3 insertions(+), 79 deletions(-) delete mode 100644 src/ui/searchitemstyle.cpp delete mode 100644 src/ui/searchitemstyle.h diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 2e68943af..fbb910f1e 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -23,7 +23,6 @@ #include "searchitemdelegate.h" -#include "searchitemstyle.h" #include "registry/searchmodel.h" #include @@ -46,16 +45,13 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->save(); QStyleOptionViewItem option(option_); - option.text = index.data().toString(); - option.features |= QStyleOptionViewItem::HasDisplay; if (!index.data(Qt::DecorationRole).isNull()) { option.features |= QStyleOptionViewItem::HasDecoration; option.icon = index.data(Qt::DecorationRole).value(); } - ZealSearchItemStyle style; - style.drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); if (option.state & QStyle::State_Selected) { #ifdef Q_OS_WIN32 @@ -67,8 +63,6 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QRect rect = QApplication::style()->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget); - const int margin = style.pixelMetric(QStyle::PM_FocusFrameHMargin, 0, option.widget); - rect.adjust(margin, 0, 2, 0); // +2px for bold text const QFont defaultFont(painter->font()); QFont boldFont(defaultFont); @@ -77,7 +71,8 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op const QFontMetrics metrics(defaultFont); const QFontMetrics metricsBold(boldFont); - const QString elided = metrics.elidedText(option.text, option.textElideMode, rect.width()); + const QString elided = metrics.elidedText(index.data().toString(), option.textElideMode, + rect.width()); int from = 0; while (from < elided.size()) { diff --git a/src/ui/searchitemstyle.cpp b/src/ui/searchitemstyle.cpp deleted file mode 100644 index c181db14e..000000000 --- a/src/ui/searchitemstyle.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Oleg Shparber -** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html -** -** This file is part of Zeal. -** -** Zeal 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. -** -** Zeal 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 Zeal. If not, see . -** -****************************************************************************/ - -#include "searchitemstyle.h" - -QRect ZealSearchItemStyle::subElementRect(SubElement element, const QStyleOption *option, - const QWidget *widget) const -{ - if (element == QStyle::SE_ItemViewItemText) { - // do not draw text - delegate does it - return QRect(); - } else { - return QProxyStyle::subElementRect(element, option, widget); - } -} diff --git a/src/ui/searchitemstyle.h b/src/ui/searchitemstyle.h deleted file mode 100644 index ef87b5e18..000000000 --- a/src/ui/searchitemstyle.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Oleg Shparber -** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html -** -** This file is part of Zeal. -** -** Zeal 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. -** -** Zeal 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 Zeal. If not, see . -** -****************************************************************************/ - -#ifndef SEARCHITEMSTYLE_H -#define SEARCHITEMSTYLE_H - -#include - -class ZealSearchItemStyle : public QProxyStyle -{ -public: - QRect subElementRect(SubElement element, const QStyleOption *option, - const QWidget *widget) const override; -}; - -#endif // SEARCHITEMSTYLE_H From 89656ded2d240f23c1371867d1193df1a19079b3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 7 Feb 2016 22:54:40 -0500 Subject: [PATCH 050/273] ui: Display a tooltip for SearchItemDelegate with elided text --- src/ui/searchitemdelegate.cpp | 16 ++++++++++++++++ src/ui/searchitemdelegate.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index fbb910f1e..64f8ccada 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -23,17 +23,33 @@ #include "searchitemdelegate.h" +#include #include "registry/searchmodel.h" #include #include +#include #include +#include SearchItemDelegate::SearchItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { } +bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, + const QStyleOptionViewItem &option, const QModelIndex &index) +{ + if (sizeHint(option, index).width() <= view->visualRect(index).width()) { + QToolTip::hideText(); + return QStyledItemDelegate::helpEvent(event, view, option, index); + } + + QToolTip::showText(event->globalPos(), index.data().toString(), view); + + return true; +} + void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option_, const QModelIndex &index) const { diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index 197ebd6aa..32b07a98b 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -32,6 +32,8 @@ class SearchItemDelegate : public QStyledItemDelegate public: explicit SearchItemDelegate(QObject *parent = nullptr); + bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, + const QModelIndex &index) override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; From 6c2401da6157cdadf9a2844a25ee355c98b13f22 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 13 Feb 2016 12:29:01 -0500 Subject: [PATCH 051/273] ui: Redo SearchItemDelegate highlighting --- src/ui/searchitemdelegate.cpp | 85 +++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 64f8ccada..e5355b37b 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -24,9 +24,6 @@ #include "searchitemdelegate.h" #include -#include "registry/searchmodel.h" - -#include #include #include #include @@ -58,8 +55,6 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op return; } - painter->save(); - QStyleOptionViewItem option(option_); if (!index.data(Qt::DecorationRole).isNull()) { @@ -67,53 +62,67 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op option.icon = index.data(Qt::DecorationRole).value(); } - QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); + QStyle *style = option.widget->style(); + style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); - if (option.state & QStyle::State_Selected) { -#ifdef Q_OS_WIN32 - option.palette.setColor(QPalette::All, QPalette::HighlightedText, - option.palette.color(QPalette::Active, QPalette::Text)); -#endif - painter->setPen(QPen(option.palette.highlightedText(), 1)); - } - - QRect rect = QApplication::style()->subElementRect(QStyle::SE_ItemViewItemText, &option, - option.widget); + const QRect rect = style->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget); - const QFont defaultFont(painter->font()); - QFont boldFont(defaultFont); - boldFont.setBold(true); + // Match QCommonStyle behaviour. + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, option.widget) + 1; + const QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); - const QFontMetrics metrics(defaultFont); - const QFontMetrics metricsBold(boldFont); + const QString text = index.data().toString(); + const QFontMetrics fm(option.font); + const QString elidedText = fm.elidedText(text, option.textElideMode, textRect.width()); - const QString elided = metrics.elidedText(index.data().toString(), option.textElideMode, - rect.width()); + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(QColor::fromRgb(255, 253, 0)); - int from = 0; - while (from < elided.size()) { - const int to = elided.indexOf(m_highlight, from, Qt::CaseInsensitive); + const QColor highlightColor = option.state & (QStyle::State_Selected | QStyle::State_HasFocus) + ? QColor::fromRgb(255, 255, 100, 20) : QColor::fromRgb(255, 255, 100, 120); - if (to == -1) { - painter->drawText(rect, elided.mid(from)); + for (int i = 0; i < elidedText.length();) { + const int matchIndex = text.indexOf(m_highlight, i, Qt::CaseInsensitive); + if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) break; - } - QString text = elided.mid(from, to - from); - painter->drawText(rect, text); - rect.setLeft(rect.left() + metrics.width(text)); + QRect highlightRect = textRect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); + highlightRect.setWidth(fm.width(elidedText.mid(matchIndex, m_highlight.length()))); - text = elided.mid(to, m_highlight.size()); - painter->setFont(boldFont); - painter->drawText(rect, text); - rect.setLeft(rect.left() + metricsBold.width(text)); + QPainterPath path; + path.addRoundedRect(highlightRect, 2, 2); - painter->setFont(defaultFont); + painter->fillPath(path, highlightColor); + painter->drawPath(path); - from = to + m_highlight.size(); + i = matchIndex + m_highlight.length(); } painter->restore(); + painter->save(); + +#ifdef Q_OS_WIN32 + // QWindowsVistaStyle overrides highlight colour. + if (style->objectName() == QStringLiteral("windowsvista")) { + option.palette.setColor(QPalette::All, QPalette::HighlightedText, + option.palette.color(QPalette::Active, QPalette::Text)); + } +#endif + + const QPalette::ColorGroup cg = option.state & QStyle::State_Active + ? QPalette::Normal : QPalette::Inactive; + + if (option.state & QStyle::State_Selected) + painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); + else + painter->setPen(option.palette.color(cg, QPalette::Text)); + + // Vertically align the text in the middle to match QCommonStyle behaviour. + const QRect alignedRect = QStyle::alignedRect(option.direction, option.displayAlignment, + QSize(1, fm.height()), textRect); + painter->drawText(QPoint(alignedRect.x(), alignedRect.y() + fm.ascent()), elidedText); + painter->restore(); } void SearchItemDelegate::setHighlight(const QString &text) From 3fc57a309f05c44da9b5ceab817b52f3fef97610 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 28 Feb 2016 10:59:18 -0500 Subject: [PATCH 052/273] ui: Minor refactoring in SearchItemDelegate Based on suggestions made by Artur Spychaj. --- src/ui/searchitemdelegate.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index e5355b37b..ddb46186f 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -65,15 +65,14 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op QStyle *style = option.widget->style(); style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); - const QRect rect = style->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget); - // Match QCommonStyle behaviour. const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, option.widget) + 1; - const QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); + const QRect rect = style->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget) + .adjusted(textMargin, 0, -textMargin, 0); const QString text = index.data().toString(); const QFontMetrics fm(option.font); - const QString elidedText = fm.elidedText(text, option.textElideMode, textRect.width()); + const QString elidedText = fm.elidedText(text, option.textElideMode, rect.width()); painter->save(); painter->setRenderHint(QPainter::Antialiasing); @@ -82,12 +81,12 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op const QColor highlightColor = option.state & (QStyle::State_Selected | QStyle::State_HasFocus) ? QColor::fromRgb(255, 255, 100, 20) : QColor::fromRgb(255, 255, 100, 120); - for (int i = 0; i < elidedText.length();) { + for (int i = 0;;) { const int matchIndex = text.indexOf(m_highlight, i, Qt::CaseInsensitive); if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) break; - QRect highlightRect = textRect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); + QRect highlightRect = rect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); highlightRect.setWidth(fm.width(elidedText.mid(matchIndex, m_highlight.length()))); QPainterPath path; @@ -120,7 +119,7 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op // Vertically align the text in the middle to match QCommonStyle behaviour. const QRect alignedRect = QStyle::alignedRect(option.direction, option.displayAlignment, - QSize(1, fm.height()), textRect); + QSize(1, fm.height()), rect); painter->drawText(QPoint(alignedRect.x(), alignedRect.y() + fm.ascent()), elidedText); painter->restore(); } From d9cbc512b14d9d5c1a5eb4cb948e609771120eaf Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 28 Feb 2016 11:30:17 -0500 Subject: [PATCH 053/273] ui: Show tooltips for elided items in the section list --- src/ui/mainwindow.cpp | 2 ++ src/ui/searchitemdelegate.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ee1049e9f..7e2355fd8 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -192,6 +192,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : }); ui->treeView->setItemDelegate(delegate); + ui->sections->setItemDelegate(new SearchItemDelegate(ui->sections)); + createTab(); /// FIXME: QTabBar does not emit currentChanged() after the first addTab() call reloadTabState(); diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index ddb46186f..b8d601fb5 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -37,7 +37,7 @@ SearchItemDelegate::SearchItemDelegate(QObject *parent) : bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { - if (sizeHint(option, index).width() <= view->visualRect(index).width()) { + if (sizeHint(option, index).width() < view->visualRect(index).width()) { QToolTip::hideText(); return QStyledItemDelegate::helpEvent(event, view, option, index); } From 21c891e4356a81ae26c866864b7d5d08a59fdff2 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 1 Mar 2016 21:56:20 -0500 Subject: [PATCH 054/273] ui: Do not share ListModel between MainWindow and SettingsDialog --- src/ui/mainwindow.cpp | 2 +- src/ui/settingsdialog.cpp | 4 ++-- src/ui/settingsdialog.h | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 7e2355fd8..794b50c61 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -80,7 +80,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_application(app), m_settings(app->settings()), m_zealListModel(new ListModel(app->docsetRegistry(), this)), - m_settingsDialog(new SettingsDialog(app, m_zealListModel, this)), + m_settingsDialog(new SettingsDialog(app, this)), m_globalShortcut(new QxtGlobalShortcut(m_settings->showShortcut, this)) { ui->setupUi(this); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 06512a1d7..0a6e2e3a3 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -69,7 +69,7 @@ const char DownloadPreviousReceived[] = "downloadPreviousReceived"; const char ListItemIndexProperty[] = "listItem"; } -SettingsDialog::SettingsDialog(Core::Application *app, ListModel *listModel, QWidget *parent) : +SettingsDialog::SettingsDialog(Core::Application *app, QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog()), m_application(app), @@ -87,7 +87,7 @@ SettingsDialog::SettingsDialog(Core::Application *app, ListModel *listModel, QWi ui->docsetsProgress->hide(); ui->installedDocsetList->setItemDelegate(new DocsetListItemDelegate(this)); - ui->installedDocsetList->setModel(listModel); + ui->installedDocsetList->setModel(new ListModel(app->docsetRegistry(), this)); ui->installedDocsetList->setSelectionMode(QAbstractItemView::ExtendedSelection); QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 133ec33b7..32d9b0fdf 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -43,7 +43,6 @@ class SettingsDialog; namespace Zeal { class DocsetRegistry; -class ListModel; namespace Core { class Application; @@ -53,7 +52,7 @@ class SettingsDialog : public QDialog { Q_OBJECT public: - explicit SettingsDialog(Core::Application *app, ListModel *listModel, QWidget *parent = nullptr); + explicit SettingsDialog(Core::Application *app, QWidget *parent = nullptr); ~SettingsDialog() override; private slots: From a6caf1cf789eb98001598f8ca4f8b67eaf3f9f68 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 4 Mar 2016 22:45:10 -0500 Subject: [PATCH 055/273] registry, ui, util: A minor cleanup --- src/registry/docsetregistry.h | 3 +-- src/ui/mainwindow.cpp | 5 ++--- src/util/plist.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index 61bf2fb0b..808d4c1be 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -49,11 +49,10 @@ class DocsetRegistry : public QObject Docset *docset(const QString &name) const; Docset *docset(int index) const; + QList docsets() const; - QString prepareQuery(const QString &rawQuery); void search(const QString &query); const QList &queryResults(); - QList docsets() const; public slots: void addDocset(const QString &path); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 794b50c61..5cf16fabd 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -37,8 +37,6 @@ #include #include #include -#include -#include #include #include #include @@ -233,7 +231,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QDesktopServices::openUrl(url); }); - connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, &MainWindow::onSearchComplete); + connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, + this, &MainWindow::onSearchComplete); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, this, [this](const QString &name) { diff --git a/src/util/plist.h b/src/util/plist.h index 15cf6d34d..ebeb24fe3 100644 --- a/src/util/plist.h +++ b/src/util/plist.h @@ -41,7 +41,7 @@ class Plist : public QHash bool m_hasError = false; }; -} // namespace Zeal } // namespace Util +} // namespace Zeal #endif // PLIST_H From 4629a47d52283c19dd944e5121d6477294a959d4 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 10 Mar 2016 23:18:48 -0500 Subject: [PATCH 056/273] ui: Do not override indentation for the tree view --- src/ui/forms/mainwindow.ui | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index dc98bf228..936700bbe 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -83,9 +83,6 @@ QFrame::NoFrame - - 10 - false From fad8f943f794272cdd635461695fca34169ae78d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 11 Mar 2016 21:01:25 -0500 Subject: [PATCH 057/273] registry: Return 'unknown' icon for unknown symbol types --- src/registry/docset.cpp | 8 ++++++++ src/registry/docset.h | 1 + src/registry/listmodel.cpp | 4 ++-- src/registry/searchmodel.cpp | 9 ++++----- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index cab687cd9..bccc4d4df 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -210,6 +210,14 @@ QIcon Docset::icon() const return m_icon; } +QIcon Docset::symbolTypeIcon(const QString &symbolType) const +{ + static const QIcon unknownIcon(QStringLiteral("typeIcon:Unknown.png")); + + const QIcon icon(QStringLiteral("typeIcon:%1.png").arg(symbolType)); + return icon.availableSizes().isEmpty() ? unknownIcon : icon; +} + QString Docset::indexFilePath() const { return QDir(documentPath()).absoluteFilePath(m_indexFilePath); diff --git a/src/registry/docset.h b/src/registry/docset.h index 2560709fc..39b0ac909 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -51,6 +51,7 @@ class Docset QString path() const; QString documentPath() const; QIcon icon() const; + QIcon symbolTypeIcon(const QString &symbolType) const; QString indexFilePath() const; QMap symbolCounts() const; diff --git a/src/registry/listmodel.cpp b/src/registry/listmodel.cpp index 26c0698c8..d13e3d4e8 100644 --- a/src/registry/listmodel.cpp +++ b/src/registry/listmodel.cpp @@ -60,11 +60,11 @@ QVariant ListModel::data(const QModelIndex &index, int role) const case Level::GroupLevel: { DocsetItem *docsetItem = reinterpret_cast(index.internalPointer()); const QString symbolType = docsetItem->groups.at(index.row())->symbolType; - return QIcon(QString("typeIcon:%1.png").arg(symbolType)); + return docsetItem->docset->symbolTypeIcon(symbolType); } case Level::SymbolLevel: { GroupItem *groupItem = reinterpret_cast(index.internalPointer()); - return QIcon(QString("typeIcon:%1.png").arg(groupItem->symbolType)); + return groupItem->docsetItem->docset->symbolTypeIcon(groupItem->symbolType); } default: return QVariant(); diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index cdd443c8b..2ca63923b 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -55,13 +55,12 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const return QVariant(); } - case Qt::DecorationRole: - return item->docset->icon(); + case Qt::DecorationRole: { + return item->docset->symbolTypeIcon(item->type); + } case Roles::TypeIconRole: - if (index.column() != 0) - return QVariant(); - return QIcon(QString("typeIcon:%1.png").arg(item->type)); + return item->docset->icon(); default: return QVariant(); From 1236d3b5faebe5b0ed63bfee00c52a6adbff46cf Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 13 Mar 2016 08:16:06 -0400 Subject: [PATCH 058/273] ui: Support multiple icons in SearchItemDelegate This enables display of docset and symbol type icons at the same time. Related to #343. --- src/registry/listmodel.h | 5 +- src/registry/searchmodel.cpp | 2 +- src/registry/searchmodel.h | 5 +- src/ui/mainwindow.cpp | 1 + src/ui/searchitemdelegate.cpp | 91 +++++++++++++++++++++++++---------- src/ui/searchitemdelegate.h | 4 ++ 6 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/registry/listmodel.h b/src/registry/listmodel.h index 79283352f..3a1d17926 100644 --- a/src/registry/listmodel.h +++ b/src/registry/listmodel.h @@ -36,8 +36,9 @@ class ListModel : public QAbstractItemModel { Q_OBJECT public: - enum { - DocsetNameRole = Qt::UserRole, + enum ItemDataRole { + // Do not collide with SearchModel + DocsetNameRole = Qt::UserRole + 10, UpdateAvailableRole }; diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index 2ca63923b..48fa9b96d 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -59,7 +59,7 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const return item->docset->symbolTypeIcon(item->type); } - case Roles::TypeIconRole: + case ItemDataRole::DocsetIconRole: return item->docset->icon(); default: diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index 80f74904b..61e9e7a89 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -34,8 +34,9 @@ class SearchModel : public QAbstractItemModel { Q_OBJECT public: - enum Roles { - TypeIconRole = Qt::UserRole + /// TODO: Standardise roles across app + enum ItemDataRole { + DocsetIconRole = Qt::UserRole }; explicit SearchModel(QObject *parent = nullptr); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 5cf16fabd..fa372602b 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -185,6 +185,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->lineEdit->setFocus(); setupSearchBoxCompletions(); SearchItemDelegate *delegate = new SearchItemDelegate(ui->treeView); + delegate->setDecorationRoles({Zeal::SearchModel::DocsetIconRole, Qt::DecorationRole}); connect(ui->lineEdit, &QLineEdit::textChanged, [delegate](const QString &text) { delegate->setHighlight(Zeal::SearchQuery::fromString(text).query()); }); diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index b8d601fb5..43b344c77 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -34,6 +34,16 @@ SearchItemDelegate::SearchItemDelegate(QObject *parent) : { } +QList SearchItemDelegate::decorationRoles() const +{ + return m_decorationRoles; +} + +void SearchItemDelegate::setDecorationRoles(const QList &roles) +{ + m_decorationRoles = roles; +} + bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { @@ -50,55 +60,86 @@ bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option_, const QModelIndex &index) const { - if (m_highlight.isEmpty()) { - QStyledItemDelegate::paint(painter, option_, index); - return; - } - QStyleOptionViewItem option(option_); - if (!index.data(Qt::DecorationRole).isNull()) { + // Find roles with data present. + QList roles; + for (int role : m_decorationRoles) { + if (!index.data(role).isNull()) + roles.append(role); + } + + if (!roles.isEmpty()) { option.features |= QStyleOptionViewItem::HasDecoration; - option.icon = index.data(Qt::DecorationRole).value(); + option.icon = index.data(roles.first()).value(); + } + + // No or one icon && no highlight => no custom logic required. + if (roles.size() < 2 && m_highlight.isEmpty()) { + QStyledItemDelegate::paint(painter, option, index); + return; } QStyle *style = option.widget->style(); + const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, option.widget) + 1; + const QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &option, + option.widget); + style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); + for (int i = 1; i < roles.size(); ++i) { + const QIcon icon = index.data(roles[i]).value(); + + const int dx = iconRect.width() + margin; + const QRect rect = iconRect.adjusted(dx * i, 0, dx * i, 0); + option.decorationSize.rwidth() += dx; + + QIcon::Mode mode = QIcon::Normal; + if (!(option.state & QStyle::State_Enabled)) + mode = QIcon::Disabled; + else if (option.state & QStyle::State_Selected) + mode = QIcon::Selected; + QIcon::State state = option.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + icon.paint(painter, rect, option.decorationAlignment, mode, state); + } + // Match QCommonStyle behaviour. + const QString text = index.data().toString(); const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, option.widget) + 1; const QRect rect = style->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget) .adjusted(textMargin, 0, -textMargin, 0); - const QString text = index.data().toString(); const QFontMetrics fm(option.font); const QString elidedText = fm.elidedText(text, option.textElideMode, rect.width()); - painter->save(); - painter->setRenderHint(QPainter::Antialiasing); - painter->setPen(QColor::fromRgb(255, 253, 0)); + if (!m_highlight.isEmpty()) { + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(QColor::fromRgb(255, 253, 0)); + + const QColor highlightColor = option.state & (QStyle::State_Selected | QStyle::State_HasFocus) + ? QColor::fromRgb(255, 255, 100, 20) : QColor::fromRgb(255, 255, 100, 120); - const QColor highlightColor = option.state & (QStyle::State_Selected | QStyle::State_HasFocus) - ? QColor::fromRgb(255, 255, 100, 20) : QColor::fromRgb(255, 255, 100, 120); + for (int i = 0;;) { + const int matchIndex = text.indexOf(m_highlight, i, Qt::CaseInsensitive); + if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) + break; - for (int i = 0;;) { - const int matchIndex = text.indexOf(m_highlight, i, Qt::CaseInsensitive); - if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) - break; + QRect highlightRect = rect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); + highlightRect.setWidth(fm.width(elidedText.mid(matchIndex, m_highlight.length()))); - QRect highlightRect = rect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); - highlightRect.setWidth(fm.width(elidedText.mid(matchIndex, m_highlight.length()))); + QPainterPath path; + path.addRoundedRect(highlightRect, 2, 2); - QPainterPath path; - path.addRoundedRect(highlightRect, 2, 2); + painter->fillPath(path, highlightColor); + painter->drawPath(path); - painter->fillPath(path, highlightColor); - painter->drawPath(path); + i = matchIndex + m_highlight.length(); + } - i = matchIndex + m_highlight.length(); + painter->restore(); } - painter->restore(); painter->save(); #ifdef Q_OS_WIN32 diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index 32b07a98b..714308718 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -32,6 +32,9 @@ class SearchItemDelegate : public QStyledItemDelegate public: explicit SearchItemDelegate(QObject *parent = nullptr); + QList decorationRoles() const; + void setDecorationRoles(const QList &roles); + bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) override; void paint(QPainter *painter, const QStyleOptionViewItem &option, @@ -41,6 +44,7 @@ public slots: void setHighlight(const QString &text); private: + QList m_decorationRoles = {Qt::DecorationRole}; QString m_highlight; }; From ddadee859798639ae114cc91f3bcc07bf66a7601 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 13 Mar 2016 08:15:28 -0400 Subject: [PATCH 059/273] ui: Minor refactoring in SearchItemDelegate --- src/ui/searchitemdelegate.cpp | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 43b344c77..5b82b07ef 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -57,10 +57,10 @@ bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, return true; } -void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option_, +void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QStyleOptionViewItem option(option_); + QStyleOptionViewItem opt(option); // Find roles with data present. QList roles; @@ -70,54 +70,54 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } if (!roles.isEmpty()) { - option.features |= QStyleOptionViewItem::HasDecoration; - option.icon = index.data(roles.first()).value(); + opt.features |= QStyleOptionViewItem::HasDecoration; + opt.icon = index.data(roles.first()).value(); } // No or one icon && no highlight => no custom logic required. if (roles.size() < 2 && m_highlight.isEmpty()) { - QStyledItemDelegate::paint(painter, option, index); + QStyledItemDelegate::paint(painter, opt, index); return; } - QStyle *style = option.widget->style(); - const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, option.widget) + 1; - const QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &option, - option.widget); + QStyle *style = opt.widget->style(); + const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt, opt.widget) + 1; + const QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, + opt.widget); - style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); for (int i = 1; i < roles.size(); ++i) { const QIcon icon = index.data(roles[i]).value(); const int dx = iconRect.width() + margin; const QRect rect = iconRect.adjusted(dx * i, 0, dx * i, 0); - option.decorationSize.rwidth() += dx; + opt.decorationSize.rwidth() += dx; QIcon::Mode mode = QIcon::Normal; - if (!(option.state & QStyle::State_Enabled)) + if (!(opt.state & QStyle::State_Enabled)) mode = QIcon::Disabled; - else if (option.state & QStyle::State_Selected) + else if (opt.state & QStyle::State_Selected) mode = QIcon::Selected; - QIcon::State state = option.state & QStyle::State_Open ? QIcon::On : QIcon::Off; - icon.paint(painter, rect, option.decorationAlignment, mode, state); + QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + icon.paint(painter, rect, opt.decorationAlignment, mode, state); } // Match QCommonStyle behaviour. const QString text = index.data().toString(); - const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, option.widget) + 1; - const QRect rect = style->subElementRect(QStyle::SE_ItemViewItemText, &option, option.widget) + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; + const QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget) .adjusted(textMargin, 0, -textMargin, 0); - const QFontMetrics fm(option.font); - const QString elidedText = fm.elidedText(text, option.textElideMode, rect.width()); + const QFontMetrics fm(opt.font); + const QString elidedText = fm.elidedText(text, opt.textElideMode, textRect.width()); if (!m_highlight.isEmpty()) { painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(QColor::fromRgb(255, 253, 0)); - const QColor highlightColor = option.state & (QStyle::State_Selected | QStyle::State_HasFocus) + const QColor highlightColor = opt.state & (QStyle::State_Selected | QStyle::State_HasFocus) ? QColor::fromRgb(255, 255, 100, 20) : QColor::fromRgb(255, 255, 100, 120); for (int i = 0;;) { @@ -125,7 +125,7 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) break; - QRect highlightRect = rect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); + QRect highlightRect = textRect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); highlightRect.setWidth(fm.width(elidedText.mid(matchIndex, m_highlight.length()))); QPainterPath path; @@ -145,22 +145,22 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op #ifdef Q_OS_WIN32 // QWindowsVistaStyle overrides highlight colour. if (style->objectName() == QStringLiteral("windowsvista")) { - option.palette.setColor(QPalette::All, QPalette::HighlightedText, - option.palette.color(QPalette::Active, QPalette::Text)); + opt.palette.setColor(QPalette::All, QPalette::HighlightedText, + opt.palette.color(QPalette::Active, QPalette::Text)); } #endif - const QPalette::ColorGroup cg = option.state & QStyle::State_Active + const QPalette::ColorGroup cg = opt.state & QStyle::State_Active ? QPalette::Normal : QPalette::Inactive; - if (option.state & QStyle::State_Selected) - painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); + if (opt.state & QStyle::State_Selected) + painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); else - painter->setPen(option.palette.color(cg, QPalette::Text)); + painter->setPen(opt.palette.color(cg, QPalette::Text)); // Vertically align the text in the middle to match QCommonStyle behaviour. - const QRect alignedRect = QStyle::alignedRect(option.direction, option.displayAlignment, - QSize(1, fm.height()), rect); + const QRect alignedRect = QStyle::alignedRect(opt.direction, opt.displayAlignment, + QSize(1, fm.height()), textRect); painter->drawText(QPoint(alignedRect.x(), alignedRect.y() + fm.ascent()), elidedText); painter->restore(); } From 2f1d09cf23d814517982de8aec3050231469099e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 13 Mar 2016 09:36:26 -0400 Subject: [PATCH 060/273] ui: Optimize SearchItemDelegate::paint() a bit --- src/ui/searchitemdelegate.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 5b82b07ef..37a96d45a 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -81,17 +81,15 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } QStyle *style = opt.widget->style(); + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt, opt.widget) + 1; - const QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, - opt.widget); - style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); + QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, opt.widget); + const int dx = iconRect.width() + margin; for (int i = 1; i < roles.size(); ++i) { - const QIcon icon = index.data(roles[i]).value(); - - const int dx = iconRect.width() + margin; - const QRect rect = iconRect.adjusted(dx * i, 0, dx * i, 0); + iconRect.translate(dx, 0); opt.decorationSize.rwidth() += dx; QIcon::Mode mode = QIcon::Normal; @@ -100,14 +98,15 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op else if (opt.state & QStyle::State_Selected) mode = QIcon::Selected; QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; - icon.paint(painter, rect, opt.decorationAlignment, mode, state); + + const QIcon icon = index.data(roles[i]).value(); + icon.paint(painter, iconRect, opt.decorationAlignment, mode, state); } // Match QCommonStyle behaviour. const QString text = index.data().toString(); - const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1; const QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget) - .adjusted(textMargin, 0, -textMargin, 0); + .adjusted(margin, 0, -margin, 0); const QFontMetrics fm(opt.font); const QString elidedText = fm.elidedText(text, opt.textElideMode, textRect.width()); From 7e02eafc1eae7121ea951834985f2b5aea51efac Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 13 Mar 2016 12:40:04 -0400 Subject: [PATCH 061/273] ui: Enable uniformRowHeights/uniformItemSizes for sidebar lists --- src/ui/forms/mainwindow.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 936700bbe..84b40497e 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -83,6 +83,9 @@ QFrame::NoFrame + + true + false @@ -130,6 +133,9 @@ Qt::ScrollBarAlwaysOff + + true +
From 559ee924698e1cfd27befd1497148738d259c3ae Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 14 Mar 2016 00:41:54 -0400 Subject: [PATCH 062/273] ui: Fix SearchItemDelegate when it has no decoration roles --- src/ui/searchitemdelegate.cpp | 42 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 37a96d45a..b963cab04 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -62,45 +62,48 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op { QStyleOptionViewItem opt(option); - // Find roles with data present. + QStyle *style = opt.widget->style(); + + // Find decoration roles with data present. QList roles; for (int role : m_decorationRoles) { if (!index.data(role).isNull()) roles.append(role); } + /// TODO: Implemented via initStyleOption() overload if (!roles.isEmpty()) { opt.features |= QStyleOptionViewItem::HasDecoration; opt.icon = index.data(roles.first()).value(); - } - // No or one icon && no highlight => no custom logic required. - if (roles.size() < 2 && m_highlight.isEmpty()) { - QStyledItemDelegate::paint(painter, opt, index); - return; + const QSize actualSize = opt.icon.actualSize(opt.decorationSize); + opt.decorationSize = {std::min(opt.decorationSize.width(), actualSize.width()), + std::min(opt.decorationSize.height(), actualSize.height())}; } - QStyle *style = opt.widget->style(); style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget); const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt, opt.widget) + 1; - QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, opt.widget); - const int dx = iconRect.width() + margin; - - for (int i = 1; i < roles.size(); ++i) { - iconRect.translate(dx, 0); - opt.decorationSize.rwidth() += dx; - + if (!roles.isEmpty()) { QIcon::Mode mode = QIcon::Normal; if (!(opt.state & QStyle::State_Enabled)) mode = QIcon::Disabled; else if (opt.state & QStyle::State_Selected) mode = QIcon::Selected; - QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + const QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + + // All icons are sized after the first one. + QRect iconRect = style->subElementRect(QStyle::SE_ItemViewItemDecoration, &opt, opt.widget); + const int dx = iconRect.width() + margin; - const QIcon icon = index.data(roles[i]).value(); - icon.paint(painter, iconRect, opt.decorationAlignment, mode, state); + for (int i = 1; i < roles.size(); ++i) { + opt.decorationSize.rwidth() += dx; + iconRect.translate(dx, 0); + + const QIcon icon = index.data(roles[i]).value(); + icon.paint(painter, iconRect, opt.decorationAlignment, mode, state); + } } // Match QCommonStyle behaviour. @@ -108,7 +111,7 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op const QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget) .adjusted(margin, 0, -margin, 0); - const QFontMetrics fm(opt.font); + const QFontMetrics &fm = opt.fontMetrics; const QString elidedText = fm.elidedText(text, opt.textElideMode, textRect.width()); if (!m_highlight.isEmpty()) { @@ -124,7 +127,8 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) break; - QRect highlightRect = textRect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); + QRect highlightRect + = textRect.adjusted(fm.width(elidedText.left(matchIndex)), 2, 0, -2); highlightRect.setWidth(fm.width(elidedText.mid(matchIndex, m_highlight.length()))); QPainterPath path; From 13f0afadf1748257b3ca39b7672cdabee3b0092e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 14 Mar 2016 00:42:48 -0400 Subject: [PATCH 063/273] ui: Fix SearchItemDelegate's tooltip trigger logic --- src/ui/searchitemdelegate.cpp | 35 +++++++++++++++++++++++++++++++++-- src/ui/searchitemdelegate.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index b963cab04..013ee4f1b 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -47,13 +47,14 @@ void SearchItemDelegate::setDecorationRoles(const QList &roles) bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { - if (sizeHint(option, index).width() < view->visualRect(index).width()) { + /// FIXME: It should be view->visualRect(index).width() instead of viewport()->width() + /// Doesn't work for shot items in the TOC, bug? + if (sizeHint(option, index).width() < view->viewport()->width()) { QToolTip::hideText(); return QStyledItemDelegate::helpEvent(event, view, option, index); } QToolTip::showText(event->globalPos(), index.data().toString(), view); - return true; } @@ -168,6 +169,36 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op painter->restore(); } +QSize SearchItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItem opt(option); + + QStyle *style = opt.widget->style(); + + QSize size = QStyledItemDelegate::sizeHint(opt, index); + size.setWidth(0); + + const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt, opt.widget) + 1; + + // Find decoration roles with data present. + QList roles; + for (int role : m_decorationRoles) { + if (!index.data(role).isNull()) + roles.append(role); + } + + if (!roles.isEmpty()) { + const QIcon icon = index.data(roles.first()).value(); + const QSize actualSize = icon.actualSize(opt.decorationSize); + const int decorationWidth = std::min(opt.decorationSize.width(), actualSize.width()); + size.rwidth() = (decorationWidth + margin) * roles.size() + margin; + } + + size.rwidth() += opt.fontMetrics.width(index.data().toString()) + margin * 2; + return size; +} + void SearchItemDelegate::setHighlight(const QString &text) { m_highlight = text; diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index 714308718..1c96cc7ae 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -39,6 +39,7 @@ class SearchItemDelegate : public QStyledItemDelegate const QModelIndex &index) override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; public slots: void setHighlight(const QString &text); From d7a44b55808d76f190e8328659d093cc7acfdd66 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 14 Mar 2016 00:46:49 -0400 Subject: [PATCH 064/273] ui: Set disable collapsing for the main splitter --- src/ui/forms/mainwindow.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 84b40497e..e6a4826df 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -32,6 +32,9 @@ Qt::Horizontal + + false + From 12fa4b486db0b0e3cd08e32314d4fb85c340ba01 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 16 Mar 2016 00:16:05 -0400 Subject: [PATCH 065/273] registry: Fix data role collision in ListModel Fixes a regression introduced in 6cd537d2 where ListModel::DocsetNameRole value was changed to the same as ProgressItemDelegate::ValueRole. Fixes #512. --- src/registry/listmodel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registry/listmodel.h b/src/registry/listmodel.h index 3a1d17926..6c66bf3e0 100644 --- a/src/registry/listmodel.h +++ b/src/registry/listmodel.h @@ -37,8 +37,8 @@ class ListModel : public QAbstractItemModel Q_OBJECT public: enum ItemDataRole { - // Do not collide with SearchModel - DocsetNameRole = Qt::UserRole + 10, + // Do not collide with SearchModel, and ProgressItemDelegate. + DocsetNameRole = Qt::UserRole + 20, UpdateAvailableRole }; From 727440f95053ff6070cc2c6a65f9e8e5d66d0178 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 17 Mar 2016 09:18:53 -0400 Subject: [PATCH 066/273] ci: Update .shippable.yml to the new format http://blog.shippable.com/migrating-to-the-new-build-platform --- .shippable.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index eca162338..3568b6336 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -1,7 +1,6 @@ -before_install: - - shippable_retry sudo apt-get -y -qq update -install: - - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev -script: - - qmake - - make +build: + ci: + - shippable_retry sudo apt-get -y -qq update + - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev + - qmake + - make From 4c19ec02a2e8f550f552230d20307965e7f7f76c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 18 Mar 2016 22:20:59 -0400 Subject: [PATCH 067/273] resources: Add new entity type icons --- src/resources/icons/type/Collection.png | Bin 0 -> 421 bytes src/resources/icons/type/Collection@2x.png | Bin 0 -> 577 bytes src/resources/icons/type/Decorator.png | Bin 0 -> 305 bytes src/resources/icons/type/Decorator@2x.png | Bin 0 -> 478 bytes src/resources/icons/type/Helper.png | Bin 0 -> 255 bytes src/resources/icons/type/Helper@2x.png | Bin 0 -> 366 bytes src/resources/icons/type/Request.png | Bin 0 -> 302 bytes src/resources/icons/type/Request@2x.png | Bin 0 -> 475 bytes src/resources/icons/type/Signature.png | Bin 0 -> 416 bytes src/resources/icons/type/Signature@2x.png | Bin 0 -> 553 bytes src/resources/icons/type/View.png | Bin 0 -> 471 bytes src/resources/icons/type/View@2x.png | Bin 0 -> 557 bytes src/resources/zeal.qrc | 12 ++++++++++++ 13 files changed, 12 insertions(+) create mode 100644 src/resources/icons/type/Collection.png create mode 100644 src/resources/icons/type/Collection@2x.png create mode 100644 src/resources/icons/type/Decorator.png create mode 100644 src/resources/icons/type/Decorator@2x.png create mode 100644 src/resources/icons/type/Helper.png create mode 100644 src/resources/icons/type/Helper@2x.png create mode 100644 src/resources/icons/type/Request.png create mode 100644 src/resources/icons/type/Request@2x.png create mode 100644 src/resources/icons/type/Signature.png create mode 100644 src/resources/icons/type/Signature@2x.png create mode 100644 src/resources/icons/type/View.png create mode 100644 src/resources/icons/type/View@2x.png diff --git a/src/resources/icons/type/Collection.png b/src/resources/icons/type/Collection.png new file mode 100644 index 0000000000000000000000000000000000000000..428fd1eb10cc7996f67ded17e7aeff34b462f6cd GIT binary patch literal 421 zcmV;W0b2fvP)CfKFkmc8* z;m?-s1r;P)$dKdKtKQL_+s&EQ#D&wrfZouX+RT&W+OE^Uf9T)1)Wd zL;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_009w6L_t(2&yCaDa)K}r2H-$M*%Att z*am}D3l`eiHe%0*_kXP}LY)xM@xNihH%XSAg%Hc8y|FDqEP5~&vFX4W_QV-bn^4+o zsFWh^mm?RdoOvULE2g7=4*LYv3l04c#upLid~)fU$U?Z{qE2k02k}%0nar+}X$M1? z=cy23OC+@Tb1U8CgzAaWLg(a#R72#Ufrpzg$~40hy>s+ zxW`VlkpV>bnGa3-+Bi&Mja%j8Q(Qb3Ci(yi*|aY=5lez~RI%hM1C>&nvMjeRuWws? zZcJ3~A7!1-uWtjz?!=$p370~t9{i7nPIIiDX29yv>>%5X=Fy=(_B;FmV>T)lGqjwN P00000NkvXXu0mjfvmz(S literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Decorator.png b/src/resources/icons/type/Decorator.png new file mode 100644 index 0000000000000000000000000000000000000000..7b88c5db9a90fe06c28a550e484bac26e07528b4 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh3?wzC-F*zCq5^zET-&3XIwG4UBzI5Goz#`k zmS&Y$>Q&gA+&L|0Vwrd0i+j(XTz|Z{abA{v+W-ImkE}b`996%6`JN4v*W@^)A6&IR z-#M!xtR~MX^ZoPp6Vtkj+;XR6_0K4qlIxfeS9D7qXbWRWkY8}a+PG*p5GTpo-GwiI zuYo_1!&%@FS^;opCAQC$&c z>(?o(*c(zA4Ep%zFggduOc6chJ=M-|t7wI`>8iIY>@Ut-;>tXg-4J-a9N u^U7S$V3%7t)vfn?R^%^vVraF$fWc`W>*9V@p5s947(8A5T-G@yGywn?aB*1x literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Decorator@2x.png b/src/resources/icons/type/Decorator@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..08243f82dc8eac74a6ac6a49c386e756522fbae9 GIT binary patch literal 478 zcmV<40U`d0P)|FbdUi{3=-%hq$kwry zt%F*BZ$oO7YLEZ_|M~a&x}UacKW24Gaif8rns}CSM{SU5i+D_PY(Qu9?(@H=yn9b| zi)DtDagl^sf4ic%@8|DsLTQa-iKmI9r-!4Rdzc|_L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_007=eL_t(2&y|zu4uUWcgbUR& zSml)B0V?2qy#MRD5aPu`;{2NAOWW-1R0zwKtZYjNOZLhVwj7NWqwz@ELQ0kqm69MC z2QRr3J#FBOfwjDbzM&tq3Zod9C*RP#lrEN7b>KS7vM3-!)cJ*e{azlD+tf#Y;nv&1 zFN_I+E_77lqBN$+$#$WtkhPY98hf$_nw5cG17jTjy*An5WX$=3D?3U~F_duG5H2)H z8l&RkyVddCfoV_h#bXK0ZRJcWquaON`}~xvRUe$_M7`la!FsAWYpOX|>Y?xO1f`B1 UXnFAR(*OVf07*qoM6N<$g8nw!umAu6 literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Helper.png b/src/resources/icons/type/Helper.png new file mode 100644 index 0000000000000000000000000000000000000000..4c366ab544bd398a237735cea46cd90790303aa7 GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh3?wzC-F*zCYyx~jT<6T>L_>!U@|-`*duTt; z+ErW|*Kwab#{2N@vH$=7Z(0>|^f1r9Jv;|?)L%KjX3IwI@ORceKyz42g8YI#pFQ__ zl6oL@8Bl;R$=lt9_uH1luRsoGfk$L90|U1(2s1Lwnj--e^!9Xd4B@!m+V9BMpdi4! zJ0UW{RpkHw@Lu*7=EA(mYQEeY(o7x~+ynxW7p;`a4YixKZO`<_XTHwTy!raH$={W) kN@f`Llze!%d&3XuJ8A4Z+V=blfyOd;y85}Sb4q9e01nt+kpKVy literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Helper@2x.png b/src/resources/icons/type/Helper@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ede52e355e54db8a2a694667eddf955d7d813e5a GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s3?yAI>n{UR$pJnguIJD4{{R1f&P+~RXw`DA zQzv+V%FdqVUB8BF@qDfoOSz66;W>PeXWM4(xidMBALaS{@g>lZ;|Kb8@8sUTh5Ov` zdC#9*TDgpC^$M<&$9erzeWQWaag_x51v4^-hu4`u#uW%TM}PFn^z#j98Ch_pf=e mrpfgylaPke zj^^5t!F{HLcS*Y5|Ns9#zkPXNcKzEY_ck@h{QUN1SuEH5NY3NS`>*U>vn7@L;l*QX z6S+a8u#Li73AB#2B*-t=^VxH+C#eTgmjMMBlf2zs zc)x8){0ih`c)B=-a9j`Vzsc92z{AqbRk1MQpzzfH|Gm2T8-8C%F}j(;eV~GeIl<`| z2V2Z3s~O8wpS8rU*EoE`?Mls|g`O7DE|ViyPcwa=_j_Vw@AA{T)L;Gcs)+vjgFo}w ln-@P4>Xo@Qy1zJu?)zBHzB1*AUOmuG22WQ%mvv4FO#l+sf5HF& literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Request@2x.png b/src/resources/icons/type/Request@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b8ce0176d92a50dc1542c90d515f368fd5d07319 GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s3?yAI>n{UR(*k@#T+f&B{{R1fPBN6>(hK(z%Zp^2`nAJdn!+)cE}NrQ^%{uk2m3t3U7UlY2|j^-h=Yt}b;y zn8&j_i+fXZ%+Ug#pWnXBkK{bJY2Ja^^{W%O7DRGBym;*M+n1YCxYs3d-9El^c^ucC zY@V~Fyz7&=7DscPEao+ysCXUdLave^zhDLi)wLhh-+$KlR3{pz2oz;Z@^*J&{LiF& z56HRe>EaloalUraOQ9wMo|bObe%3V^E=Pqe_pJY3Z<&2i^5~Vno9F&ibDzv{agv_I z&P`7_*7J7Xnm6G?^Mt?$&RpU;mqlb5Tf`Vm->fcIHSL%cP-|i&W2)e=^_Zc-CdWmb zBFv>{N|xCkoYNYSF+b_#K~bT%**QN>%+NSGZT-y5(}6d3`4&%UY!)oR<-Hem!Tu+Q%hYzl~dj)IZNOX4h9MG+lhmu060~P1!HeOg+b!Ue|B$ zt=s$HKJ#Rah+i6CGRxk&-xWPH*_Q9?lIJ#zxl^?Rrnm(;06og!>FVdQ&MBb@0Qs}a A;{X5v literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Signature.png b/src/resources/icons/type/Signature.png new file mode 100644 index 0000000000000000000000000000000000000000..87f6d189bdf0b3533fb1edc653d47d3ccf3f17d8 GIT binary patch literal 416 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh3?wzC-F*zC8UuVnT>t<7U)i~;Z}yHwYmUxc zd1&U6{R>tfX`8&MWy1QdXS52C?bLqOHZ{B_W`t|3pUwpG@vUb*Qc(5U;5U(Z~+ueNi|>}3Zg&E0wF`r~!mPS06!aQdP>t2UjS zxpe>31$+Bv@93PmrFGJ#iF0=Xwfr@*Ndr1Yt0c%TnBgC>K)~a8JWv;7lDE4HLkFv@ z2av;A;1OBOz`!jG!i)^F=12eqn><|{LpZMcp1;X=NI`%#AR$Halu}da>Qd*`|Nl2H zYFzf&$nxY_ot6u(f=-eQYb>5GHT2SGn7}1i%Kl-w$+gJ*Yg4Uq43=GyXuf}}&byPIDt6DQC$44$rjF6*2UngHJo+S~vD literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/Signature@2x.png b/src/resources/icons/type/Signature@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f545cfd12a7c9c3febd22aa859c3d82de07148e7 GIT binary patch literal 553 zcmV+^0@nSBP)i8xs(Fd3fRC@0p}nH4#h9bNkD9oaqP?H1#EO=*e2A)mjIEodzl|`Tzg_`uhCd;p&o|x$*M#?C$fRsl$JZtf;Wa$=|8SjzBSJ#GKR6t|WY!B~mdzJsTZ~!! zUs=rNtF^PB^@`h!^O3n8$#-v*bArQr0C>{|)R#L91>$xWMbVQyG>5T3NYYGd|Exp6 zLr$P53VP^JV3K9&vBVNyUUi5_SKh{wG+4@bTdK4IVctw+N{Wkh?89O~SwmR7J4P#~ z57o)%0kJZN(4JMJ=>^f9Lnmwz;Y;HE5xaR#I_puH(8$C?xsz%)RTvP4bR5wHN_Fkf zuK}+oN{Z!$!X_w;@#Rh5e-q0A!JO@|u>?>A8iZYR?)&Qx?OKHT%I<<-@Qs4XU@^I? r?z-CZgNebUHGdbRtohK?kA8Gmbgn@h+}h`YI>edV2gHysa9u@W_O!PTZmq6 zm#ekP|NsAMd!Vbc%CNZ3Tx^zhg{rN#%ZHS<@$&U>ex!7RsNdr2@bdRgUyN*fqI!s_ z=<4xJUW#RQotB}!ev7QRz|^9u#9?uneTuJIYLor_{ldxGQDTkx`}=2ioOp+mZf0HH($9dQ}_iYCuOwwowVVzQH0I*N# z8X`QC&6ymme8J`f5pasawZJKrDPEb zd9+xreuVWV-0pmqaDNcT(-{(8t~YTHQo`dIy+9GivKf;%mQVjrcmurH4C;EyDCGbE N002ovPDHLkV1i$*+!O!+ literal 0 HcmV?d00001 diff --git a/src/resources/icons/type/View@2x.png b/src/resources/icons/type/View@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc7158b741d19c0910895ffe423d8dc8c1707a1 GIT binary patch literal 557 zcmV+|0@D47P)#p48gqtcd1426M88E{Z8 z1A{WaDTv$N|M`}-FdV4))#jroIc=~k+Yt}Lu`SCMPs6qxv2o>ta5uuSgmAq#6TZ#{ zX5+a+Fq9!oL>g|*Cfpeq14){u5dsA>yr&6}O9N$rJrO0?GV@R#=!i;AP$%dEnKU2P z1-w7VQVr3e)_x+#+G!PZTUt)U@Zt3{=F6de^*j6m1JWSC=gq@}00000NkvXXu0mjf=Y;s# literal 0 HcmV?d00001 diff --git a/src/resources/zeal.qrc b/src/resources/zeal.qrc index 9b592bac0..862ab3979 100644 --- a/src/resources/zeal.qrc +++ b/src/resources/zeal.qrc @@ -30,6 +30,8 @@ icons/type/Category@2x.png icons/type/Class.png icons/type/Class@2x.png + icons/type/Collection.png + icons/type/Collection@2x.png icons/type/Column.png icons/type/Column@2x.png icons/type/Command.png @@ -44,6 +46,8 @@ icons/type/Conversion@2x.png icons/type/Database.png icons/type/Database@2x.png + icons/type/Decorator.png + icons/type/Decorator@2x.png icons/type/Define.png icons/type/Define@2x.png icons/type/Delegate.png @@ -86,6 +90,8 @@ icons/type/Global@2x.png icons/type/Guide.png icons/type/Guide@2x.png + icons/type/Helper.png + icons/type/Helper@2x.png icons/type/Hook.png icons/type/Hook@2x.png icons/type/Index.png @@ -156,6 +162,8 @@ icons/type/Relationship@2x.png icons/type/Report.png icons/type/Report@2x.png + icons/type/Request.png + icons/type/Request@2x.png icons/type/Resource.png icons/type/Resource@2x.png icons/type/Sample.png @@ -172,6 +180,8 @@ icons/type/Setting@2x.png icons/type/Shortcut.png icons/type/Shortcut@2x.png + icons/type/Signature.png + icons/type/Signature@2x.png icons/type/Snippet.png icons/type/Snippet@2x.png icons/type/Special Form.png @@ -210,6 +220,8 @@ icons/type/Variable@2x.png icons/type/Variant.png icons/type/Variant@2x.png + icons/type/View.png + icons/type/View@2x.png icons/type/Web.png icons/type/Web@2x.png icons/type/Word.png From c317bb22a2a5802ae34d9db58355845d775e091f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 18 Mar 2016 22:21:56 -0400 Subject: [PATCH 068/273] resources: Update Parameter entity type icon --- src/resources/icons/type/Parameter.png | Bin 360 -> 445 bytes src/resources/icons/type/Parameter@2x.png | Bin 493 -> 877 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/resources/icons/type/Parameter.png b/src/resources/icons/type/Parameter.png index e3df896523bc922af11c6eb81f8cf387517115b3..2c8e5069e70ee54808aa8ee4358bb9f1cb4d6fac 100644 GIT binary patch delta 385 zcmV-{0e=4I0=)x}B!9F}OjJex|NpA2hpDWHwz!zY#i*#Phr`9DuCk80y`HhPlC!sz zz`~=!!=$LIg~P<9uCk5x_w)b%|Md0m&e6KFwv(r-g~7z6tgwx^yq(C)v-|t`r>TUi zuZ*s;kf*AItFVj3$gbk#*W%>Xtg(!yse`}5qN}fp{r&v!@Jr~@)xfyBnWd?MzQLfe zw2`^Io296NzrdfXu8E|lfxf_>s;-Fe@#($4ovE#dq^E$evyZ#Jo1>*(*ywQlxnQ_hOo1oC7re z08Op+qczdib;C4G%jk&SZNqk)9$lCH!O(GRj682lPNp-CJ#PeGBp`!1IT!J<5LuF| zwY%AhED%Of%pLa!>lj5L5~X4?j!$Q$RDw&IUdd}(yCBQ+E8G2k%WE03qIi51wG3rd fd_AiYc>Tc}5)u~F5hX%H00000NkvXXu0mjfOE=iY delta 299 zcmdnX{DNtMO1(m|N02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&Rd2 zApt%iuK)l4pVpAQWJ2A>g_EYYl`fsyKD(=OUQf-sxqY8LyamdBc=KxC<`p|vFZlWW z+twAcZ(ce*v!nda@82(;J~+B-!@S z7%ohFCNQC6?|0GmSt|mPrYz(2`WUPKXQK8-nINCVMUyHc&5h6ec5F-is9(JPoKJb? eJIh=93YfbBSu#R;CYJ+U!{F)a=d#Wzp$P!8=9|F) diff --git a/src/resources/icons/type/Parameter@2x.png b/src/resources/icons/type/Parameter@2x.png index 4e0e1807e8241ba6b3c52da4d61c38bf827f9a4e..c3689e4e6c3909dc103cbc8dae19ce39657b408a 100644 GIT binary patch delta 855 zcmV-d1E~D%1MLQoBYy#LP)t-s00020tcR+shpDTGqo;tQrhlWRf2ypAs;q~ptB9_! zj=Q~{!^NnntcSe4oy5hbsH}&>#ip*ZjQp{J{c!hgl3t+9>x`S!uYsI|G4 zr>cd)#H6gSjpgRrxV)XazM;_4zVY(w>g(a+Kse-=2pt81-y}+NPsDi%0psTKmtgnl(vyid0 zk+!&&yuO{kz@MwGiLkSdtFDNor-Ht~pQ^5iud|M%r-8n}p78PM-QLcxvW>mJovE#d zy}q5Kr+~G%l%uDBsH}ywxRkuVow~l8qo#iqi{uUf0Dk}nbW%=J08roG-%#HMdPDR8 z0004EOGiW@#B2=~00009a7bBm000XU000XU0RWnu7ytkPf=NU{R4C7N&-ph3Q5eSY zx0Iz!lBFzZWJ$=iGq%i-EDf@SWGmGur0jpa_npEV#^GkyW)8=-A&o_Yl{&FOPL;hjfd_D*SMi65dN5{q|Cb3R2Mq40&u@$Lt znlUyrh<7tan;K`4AYhym<`;xTj7tJ-7=yuOB!7w&MNyphViZN%fV4 zL!mVk4r5&3*!0qOw!*`-g+dUC&_R~JzOucuD@XTei$t_>Uy`JQLs=G%)+#X;J4R}h zWYx*(u__jWc>D|{5)>2X7nfJpXBF`{#w1FmD5h?b8s9OUrkMU6Gnp(>6pG4iRwI*v zTu?5L6y=WR@0EwVMlOf3fF8@D1r0S85my#1YG5pto(j62N+mEozr4Qv_5S+uYy$Jg hzsvyUYW-AghEJH@zw<=1%hmt@002ovPDHLkV1j;m+%NzD delta 449 zcmV;y0Y3ii2JHioBYyxOV@Og>004R>004l5008;`004mK004C`008P>0026e000+o zoVrmw0001uP)t-s|NsA%fNYk4YnFg)n}&0#mW8pQk(Y&an~Hj*lY_9HkEN7`o{fE& zhj*!%i1P65|NsB?^z!iR>d(f!s+^9jn~ScWlA(`)+||ygnP7^-wyW&v<>K7e*wD$L zk%F3tc$$fM*3QP$$-(8|+rF}=)y>8H`}^S8)9>u)$i1|li+rDseWsL!uAPpmnTJa< zAg=%b00VSVPE!C--&Ubk&j0`b0b)x>L;#2d9Y~YD0T+J&zDYzuR4C82)7cV&AQXUM z7VV@)pq1J}+FrK2|KkNzlOy1C(|_g6r-Q-~Axx+h8%Bf%;lNQCP=Y9Rno>#? z>MQs*jN+HJFfolZvvC)>(4{<^Oo7duXl}@%u(3?$i>1;PfQ?eEw@!uNZmbxTUIeH! zKh_(y<`z{d8+ZGIdQR{)M4nGMo)V~H8_!b8OAhZnaJ-PJu=my=Yp%EZ=UBSfw9oAS rX!;prgFOSLNAuyxjArjp_x%n}e61XBcE5YT00000NkvXXu0mjfRWjsF From 4599f2ed61842302d1755fa330091bd23fe62980 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 18 Mar 2016 22:28:43 -0400 Subject: [PATCH 069/273] resources: Strip entity type icons --- src/resources/icons/type/Abbreviation.png | Bin 398 -> 354 bytes src/resources/icons/type/Abbreviation@2x.png | Bin 578 -> 534 bytes src/resources/icons/type/Alias.png | Bin 398 -> 354 bytes src/resources/icons/type/Alias@2x.png | Bin 578 -> 534 bytes src/resources/icons/type/Annotation.png | Bin 398 -> 354 bytes src/resources/icons/type/Annotation@2x.png | Bin 578 -> 534 bytes src/resources/icons/type/Attribute.png | Bin 398 -> 354 bytes src/resources/icons/type/Attribute@2x.png | Bin 578 -> 534 bytes src/resources/icons/type/Axiom.png | Bin 398 -> 354 bytes src/resources/icons/type/Axiom@2x.png | Bin 578 -> 534 bytes src/resources/icons/type/Binding.png | Bin 419 -> 375 bytes src/resources/icons/type/Binding@2x.png | Bin 526 -> 482 bytes src/resources/icons/type/Bookmark.png | Bin 360 -> 316 bytes src/resources/icons/type/Bookmark@2x.png | Bin 567 -> 523 bytes src/resources/icons/type/Builtin.png | Bin 419 -> 375 bytes src/resources/icons/type/Builtin@2x.png | Bin 526 -> 482 bytes src/resources/icons/type/Callback.png | Bin 338 -> 294 bytes src/resources/icons/type/Callback@2x.png | Bin 551 -> 507 bytes src/resources/icons/type/Category.png | Bin 465 -> 421 bytes src/resources/icons/type/Category@2x.png | Bin 621 -> 577 bytes src/resources/icons/type/Class.png | Bin 518 -> 474 bytes src/resources/icons/type/Class@2x.png | Bin 624 -> 580 bytes src/resources/icons/type/Column.png | Bin 465 -> 421 bytes src/resources/icons/type/Column@2x.png | Bin 621 -> 577 bytes src/resources/icons/type/Command.png | Bin 338 -> 294 bytes src/resources/icons/type/Command@2x.png | Bin 551 -> 507 bytes src/resources/icons/type/Component.png | Bin 465 -> 421 bytes src/resources/icons/type/Component@2x.png | Bin 621 -> 577 bytes src/resources/icons/type/Constant.png | Bin 515 -> 471 bytes src/resources/icons/type/Constant@2x.png | Bin 601 -> 557 bytes src/resources/icons/type/Constructor.png | Bin 474 -> 430 bytes src/resources/icons/type/Constructor@2x.png | Bin 624 -> 580 bytes src/resources/icons/type/Conversion.png | Bin 338 -> 294 bytes src/resources/icons/type/Conversion@2x.png | Bin 551 -> 507 bytes src/resources/icons/type/Database.png | Bin 348 -> 304 bytes src/resources/icons/type/Database@2x.png | Bin 554 -> 510 bytes src/resources/icons/type/Define.png | Bin 308 -> 264 bytes src/resources/icons/type/Define@2x.png | Bin 362 -> 318 bytes src/resources/icons/type/Delegate.png | Bin 349 -> 305 bytes src/resources/icons/type/Delegate@2x.png | Bin 522 -> 478 bytes src/resources/icons/type/DeletedSnippet.png | Bin 643 -> 599 bytes .../icons/type/DeletedSnippet@2x.png | Bin 1149 -> 1105 bytes src/resources/icons/type/Diagram.png | Bin 349 -> 305 bytes src/resources/icons/type/Diagram@2x.png | Bin 522 -> 478 bytes src/resources/icons/type/Directive.png | Bin 348 -> 304 bytes src/resources/icons/type/Directive@2x.png | Bin 554 -> 510 bytes src/resources/icons/type/Element.png | Bin 315 -> 271 bytes src/resources/icons/type/Element@2x.png | Bin 353 -> 309 bytes src/resources/icons/type/Entry.png | Bin 315 -> 271 bytes src/resources/icons/type/Entry@2x.png | Bin 353 -> 309 bytes src/resources/icons/type/Enumeration.png | Bin 315 -> 271 bytes src/resources/icons/type/Enumeration@2x.png | Bin 353 -> 309 bytes src/resources/icons/type/Environment.png | Bin 315 -> 271 bytes src/resources/icons/type/Environment@2x.png | Bin 353 -> 309 bytes src/resources/icons/type/Error.png | Bin 354 -> 310 bytes src/resources/icons/type/Error@2x.png | Bin 454 -> 410 bytes src/resources/icons/type/Event.png | Bin 284 -> 240 bytes src/resources/icons/type/Event@2x.png | Bin 386 -> 342 bytes src/resources/icons/type/Exception.png | Bin 381 -> 337 bytes src/resources/icons/type/Exception@2x.png | Bin 544 -> 500 bytes src/resources/icons/type/Extension.png | Bin 381 -> 337 bytes src/resources/icons/type/Extension@2x.png | Bin 565 -> 521 bytes src/resources/icons/type/Field.png | Bin 290 -> 246 bytes src/resources/icons/type/Field@2x.png | Bin 325 -> 281 bytes src/resources/icons/type/File.png | Bin 290 -> 246 bytes src/resources/icons/type/File@2x.png | Bin 325 -> 281 bytes src/resources/icons/type/Filter.png | Bin 290 -> 246 bytes src/resources/icons/type/Filter@2x.png | Bin 325 -> 281 bytes src/resources/icons/type/Foreign Key.png | Bin 290 -> 246 bytes src/resources/icons/type/Foreign Key@2x.png | Bin 325 -> 281 bytes src/resources/icons/type/Framework.png | Bin 290 -> 246 bytes src/resources/icons/type/Framework@2x.png | Bin 325 -> 281 bytes src/resources/icons/type/Function.png | Bin 479 -> 435 bytes src/resources/icons/type/Function@2x.png | Bin 602 -> 558 bytes src/resources/icons/type/Global.png | Bin 386 -> 342 bytes src/resources/icons/type/Global@2x.png | Bin 547 -> 503 bytes src/resources/icons/type/Guide.png | Bin 1122 -> 1078 bytes src/resources/icons/type/Guide@2x.png | Bin 1930 -> 1886 bytes src/resources/icons/type/Hook.png | Bin 278 -> 234 bytes src/resources/icons/type/Hook@2x.png | Bin 389 -> 345 bytes src/resources/icons/type/Index.png | Bin 240 -> 196 bytes src/resources/icons/type/Index@2x.png | Bin 337 -> 293 bytes src/resources/icons/type/Indirection.png | Bin 240 -> 196 bytes src/resources/icons/type/Indirection@2x.png | Bin 337 -> 293 bytes src/resources/icons/type/Inductive.png | Bin 240 -> 196 bytes src/resources/icons/type/Inductive@2x.png | Bin 337 -> 293 bytes src/resources/icons/type/Instance.png | Bin 257 -> 213 bytes src/resources/icons/type/Instance@2x.png | Bin 351 -> 307 bytes src/resources/icons/type/Instruction.png | Bin 240 -> 196 bytes src/resources/icons/type/Instruction@2x.png | Bin 337 -> 293 bytes src/resources/icons/type/Interface.png | Bin 240 -> 196 bytes src/resources/icons/type/Interface@2x.png | Bin 316 -> 272 bytes src/resources/icons/type/Keyword.png | Bin 371 -> 327 bytes src/resources/icons/type/Keyword@2x.png | Bin 532 -> 488 bytes src/resources/icons/type/Lemma.png | Bin 276 -> 232 bytes src/resources/icons/type/Lemma@2x.png | Bin 320 -> 276 bytes src/resources/icons/type/Library.png | Bin 276 -> 232 bytes src/resources/icons/type/Library@2x.png | Bin 320 -> 276 bytes src/resources/icons/type/Literal.png | Bin 276 -> 232 bytes src/resources/icons/type/Literal@2x.png | Bin 320 -> 276 bytes src/resources/icons/type/Macro.png | Bin 308 -> 264 bytes src/resources/icons/type/Macro@2x.png | Bin 362 -> 318 bytes src/resources/icons/type/Method.png | Bin 413 -> 369 bytes src/resources/icons/type/Method@2x.png | Bin 520 -> 476 bytes src/resources/icons/type/Mixin.png | Bin 413 -> 369 bytes src/resources/icons/type/Mixin@2x.png | Bin 520 -> 476 bytes src/resources/icons/type/Modifier.png | Bin 394 -> 350 bytes src/resources/icons/type/Modifier@2x.png | Bin 529 -> 485 bytes src/resources/icons/type/Module.png | Bin 413 -> 369 bytes src/resources/icons/type/Module@2x.png | Bin 517 -> 473 bytes src/resources/icons/type/Namespace.png | Bin 354 -> 310 bytes src/resources/icons/type/Namespace@2x.png | Bin 465 -> 421 bytes src/resources/icons/type/NewSnippet.png | Bin 595 -> 551 bytes src/resources/icons/type/NewSnippet@2x.png | Bin 1076 -> 1032 bytes src/resources/icons/type/Notation.png | Bin 354 -> 310 bytes src/resources/icons/type/Notation@2x.png | Bin 465 -> 421 bytes src/resources/icons/type/Object.png | Bin 431 -> 387 bytes src/resources/icons/type/Object@2x.png | Bin 673 -> 629 bytes src/resources/icons/type/Operator.png | Bin 431 -> 387 bytes src/resources/icons/type/Operator@2x.png | Bin 673 -> 629 bytes src/resources/icons/type/Option.png | Bin 431 -> 387 bytes src/resources/icons/type/Option@2x.png | Bin 673 -> 629 bytes src/resources/icons/type/Package.png | Bin 360 -> 316 bytes src/resources/icons/type/Package@2x.png | Bin 493 -> 449 bytes src/resources/icons/type/Plugin.png | Bin 360 -> 316 bytes src/resources/icons/type/Plugin@2x.png | Bin 493 -> 449 bytes src/resources/icons/type/Procedure.png | Bin 360 -> 316 bytes src/resources/icons/type/Procedure@2x.png | Bin 493 -> 449 bytes src/resources/icons/type/Projection.png | Bin 360 -> 316 bytes src/resources/icons/type/Projection@2x.png | Bin 493 -> 449 bytes src/resources/icons/type/Property.png | Bin 400 -> 356 bytes src/resources/icons/type/Property@2x.png | Bin 497 -> 453 bytes src/resources/icons/type/Protocol.png | Bin 422 -> 378 bytes src/resources/icons/type/Protocol@2x.png | Bin 511 -> 467 bytes src/resources/icons/type/Provider.png | Bin 489 -> 445 bytes src/resources/icons/type/Provider@2x.png | Bin 921 -> 877 bytes src/resources/icons/type/Provisioner.png | Bin 360 -> 316 bytes src/resources/icons/type/Provisioner@2x.png | Bin 493 -> 449 bytes src/resources/icons/type/Query.png | Bin 589 -> 545 bytes src/resources/icons/type/Query@2x.png | Bin 1176 -> 1132 bytes src/resources/icons/type/Record.png | Bin 346 -> 302 bytes src/resources/icons/type/Record@2x.png | Bin 519 -> 475 bytes src/resources/icons/type/Relationship.png | Bin 346 -> 302 bytes src/resources/icons/type/Relationship@2x.png | Bin 519 -> 475 bytes src/resources/icons/type/Report.png | Bin 346 -> 302 bytes src/resources/icons/type/Report@2x.png | Bin 519 -> 475 bytes src/resources/icons/type/Resource.png | Bin 346 -> 302 bytes src/resources/icons/type/Resource@2x.png | Bin 519 -> 475 bytes src/resources/icons/type/Sample.png | Bin 905 -> 861 bytes src/resources/icons/type/Sample@2x.png | Bin 1939 -> 1895 bytes src/resources/icons/type/Schema.png | Bin 460 -> 416 bytes src/resources/icons/type/Schema@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Script.png | Bin 460 -> 416 bytes src/resources/icons/type/Script@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Section.png | Bin 327 -> 283 bytes src/resources/icons/type/Section@2x.png | Bin 634 -> 590 bytes src/resources/icons/type/Service.png | Bin 460 -> 416 bytes src/resources/icons/type/Service@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Setting.png | Bin 460 -> 416 bytes src/resources/icons/type/Setting@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Shortcut.png | Bin 419 -> 375 bytes src/resources/icons/type/Shortcut@2x.png | Bin 614 -> 570 bytes src/resources/icons/type/Snippet.png | Bin 605 -> 561 bytes src/resources/icons/type/Snippet@2x.png | Bin 1290 -> 1246 bytes src/resources/icons/type/Special Form.png | Bin 290 -> 246 bytes src/resources/icons/type/Special Form@2x.png | Bin 325 -> 281 bytes src/resources/icons/type/Statement.png | Bin 460 -> 416 bytes src/resources/icons/type/Statement@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Structure.png | Bin 460 -> 416 bytes src/resources/icons/type/Structure@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Style.png | Bin 460 -> 416 bytes src/resources/icons/type/Style@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Subroutine.png | Bin 460 -> 416 bytes src/resources/icons/type/Subroutine@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Syntax.png | Bin 460 -> 416 bytes src/resources/icons/type/Syntax@2x.png | Bin 597 -> 553 bytes src/resources/icons/type/Table.png | Bin 270 -> 226 bytes src/resources/icons/type/Table@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Tactic.png | Bin 274 -> 240 bytes src/resources/icons/type/Tactic@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Tag.png | Bin 270 -> 226 bytes src/resources/icons/type/Tag@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Test.png | Bin 274 -> 240 bytes src/resources/icons/type/Test@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Trait.png | Bin 270 -> 226 bytes src/resources/icons/type/Trait@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Trigger.png | Bin 274 -> 240 bytes src/resources/icons/type/Trigger@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Type.png | Bin 274 -> 240 bytes src/resources/icons/type/Type@2x.png | Bin 313 -> 269 bytes src/resources/icons/type/Union.png | Bin 341 -> 297 bytes src/resources/icons/type/Union@2x.png | Bin 478 -> 434 bytes src/resources/icons/type/Unknown.png | Bin 302 -> 258 bytes src/resources/icons/type/Unknown@2x.png | Bin 513 -> 469 bytes src/resources/icons/type/Value.png | Bin 456 -> 412 bytes src/resources/icons/type/Value@2x.png | Bin 577 -> 533 bytes src/resources/icons/type/Variable.png | Bin 515 -> 471 bytes src/resources/icons/type/Variable@2x.png | Bin 601 -> 557 bytes src/resources/icons/type/Variant.png | Bin 456 -> 412 bytes src/resources/icons/type/Variant@2x.png | Bin 577 -> 533 bytes src/resources/icons/type/Web.png | Bin 1200 -> 1156 bytes src/resources/icons/type/Web@2x.png | Bin 2811 -> 2767 bytes src/resources/icons/type/Word.png | Bin 454 -> 410 bytes src/resources/icons/type/Word@2x.png | Bin 682 -> 638 bytes src/resources/icons/type/_DashAnnotations.png | Bin 329 -> 285 bytes .../icons/type/_DashAnnotations@2x.png | Bin 524 -> 480 bytes src/resources/icons/type/_Struct.png | Bin 420 -> 376 bytes src/resources/icons/type/_Struct@2x.png | Bin 601 -> 557 bytes 208 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/resources/icons/type/Abbreviation.png b/src/resources/icons/type/Abbreviation.png index 2a802d6762b29fda5147a61fb648f229be8fb6db..9f72492f8e7cd5a55dda5d99d56db26364319a10 100644 GIT binary patch delta 10 RcmeBUe#A6EWn+LHBLEc?18M*O delta 52 zcmaFF)WLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HhA{#Fc()Eg diff --git a/src/resources/icons/type/Binding@2x.png b/src/resources/icons/type/Binding@2x.png index 9ad8740caf0c454c7915f58686aef8b6cc48f2c5..77b161e189220d60952453fa283a57e8c0d26e0e 100644 GIT binary patch delta 10 RcmeBUdBi+HWn;iTMgSHh1MC0* delta 52 zcmaFF+{ZFOMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz H4>AG(agz>& diff --git a/src/resources/icons/type/Bookmark.png b/src/resources/icons/type/Bookmark.png index 6f41ba0fb048709bae0bf0b77e7e7c9a0cd4660a..9be3830e5caebd012195f034919de4772832b4e2 100644 GIT binary patch delta 10 RcmaFCw1;Ve%EkZ*MgSKR19t!b delta 52 zcmdnP^nz)Eil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HN;3igd5#Vb diff --git a/src/resources/icons/type/Bookmark@2x.png b/src/resources/icons/type/Bookmark@2x.png index 3e4adbb789d3ac4c06bb22a519976a803e8805a6..9748bc288050625bf396c9ca69bb3ed2e81586c0 100644 GIT binary patch delta 10 Rcmdna(#4KnhL&3l40%%+7@kToFc_;dFi48e^pvUJ IsCbYO0D=e(EC2ui diff --git a/src/resources/icons/type/Callback.png b/src/resources/icons/type/Callback.png index 3244b4f8eb7a840591f8e83d4cb7bf8aa3cfface..377b08e0e98b21de0ff1ff3d9a079344e8796356 100644 GIT binary patch delta 10 Rcmcb_w2Wzj%EkaDMgSFC12q5u delta 52 zcmZ3+bctz#il#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC HWMu>ZjYLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HwlD$!aheWH diff --git a/src/resources/icons/type/Category@2x.png b/src/resources/icons/type/Category@2x.png index 5767dc4d1e0896009d0ea6740384eb08980df59d..7cdf9953c971ef3e306944f3ae2260d743c58e79 100644 GIT binary patch delta 10 RcmaFMa*$<$%Eka$CIALqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HDlh>6d|wVD diff --git a/src/resources/icons/type/Class.png b/src/resources/icons/type/Class.png index 04366ef43fb7c1f6fb8671317e5bcac7f1888401..46e4bf7e7baf06685bab9cd8e2586c2b7c1843a6 100644 GIT binary patch delta 10 RcmZo;xy3v|Wn;iLMgSFr1JnQj delta 52 zcmcb`+{Q9NMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQOJ1Zc`3y diff --git a/src/resources/icons/type/Class@2x.png b/src/resources/icons/type/Class@2x.png index 1b5ec178ce2f047f134aa463b4a3b1db4ab53ade..4180f7ea7904b0de885afea5b12f0c6256162bdf 100644 GIT binary patch delta 10 Rcmeysa)f1q%EkZ%CIA=I1C#&& delta 52 zcmX@Y@_}W7il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HDl-89eU}a_ diff --git a/src/resources/icons/type/Column.png b/src/resources/icons/type/Column.png index d37ff1a2a48368b63d69df7a509d1625577fa61d..9cc37d618ee31fea905f4fd9860fd98d9e91ace6 100644 GIT binary patch delta 10 Rcmcb}yp(x@%Eo|3MgSI91GE4D delta 52 zcmZ3=e35yAil#!cN02WAL+%U)hT=X3hTkj<49#m87^)^PFuYpEz+m`}fk9-?ne%Q+ I8x>m^0gr1B+W-In diff --git a/src/resources/icons/type/Column@2x.png b/src/resources/icons/type/Column@2x.png index 1deaf1d39e947fe43ecba0c4c747b3ce35785092..8ada6f0431babfcc4a584d87dc5ba6c05c737892 100644 GIT binary patch delta 10 RcmaFMa*$<$%Eka$CIAj0F2ZP%K!iX diff --git a/src/resources/icons/type/Command.png b/src/resources/icons/type/Command.png index a1152f0c98f9514a691902205e91a928a20bf310..6724a81505b2c4d72af67f081677da9839d59724 100644 GIT binary patch delta 10 Rcmcb_w2Wzj%EkaDMgSFC12q5u delta 52 zcmZ3+bctz#il#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC HWMu>ZjYm^0gr1B+W-In diff --git a/src/resources/icons/type/Component@2x.png b/src/resources/icons/type/Component@2x.png index 1deaf1d39e947fe43ecba0c4c747b3ce35785092..8ada6f0431babfcc4a584d87dc5ba6c05c737892 100644 GIT binary patch delta 10 RcmaFMa*$<$%Eka$CIAj0F2ZP%K!iX diff --git a/src/resources/icons/type/Constant.png b/src/resources/icons/type/Constant.png index a59d72731317dce524779f9b45283dff46a20757..1d56e2cfd15e72f78ffd0fee746a323c0157a31a 100644 GIT binary patch delta 10 RcmZo>xz0R6Wn;i*MgSE^1Iqva delta 52 zcmcc4+{`jTMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz Hw=n_$Z5s|_ diff --git a/src/resources/icons/type/Constant@2x.png b/src/resources/icons/type/Constant@2x.png index 803fa1e0bc62b2d6ceefb4fe747c00c421d5a223..8540dab0eda00db23c9fc28d872ed2efe44fdb3e 100644 GIT binary patch delta 10 Rcmcb~vX*6n%EkarCIA))15W?| delta 52 zcmZ3>a+76(il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H@-P7abUzK} diff --git a/src/resources/icons/type/Constructor.png b/src/resources/icons/type/Constructor.png index 19a8c282451958bf349761e0a68928e167cd74e5..cb08c47dade1bac79093d0f8f6ecaa97234acf86 100644 GIT binary patch delta 10 Rcmcb`ypDN-%Eo{$MgSKJ1J3{e delta 52 zcmZ3-e2aO4il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H_A&whbwUnj diff --git a/src/resources/icons/type/Constructor@2x.png b/src/resources/icons/type/Constructor@2x.png index ea45258d97e6b4d096e97ef9b87f561d8064a0fe..cee38eb9d1b599802e780a30afaeb879472f572e 100644 GIT binary patch delta 10 Rcmeysa)f1q%EkZ%CIA=I1C#&& delta 52 zcmX@Y@_}W7il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HDl-89eU}a_ diff --git a/src/resources/icons/type/Conversion.png b/src/resources/icons/type/Conversion.png index 5a203f11f5862e39c8bdef9bb44c3eaeb8f445db..5b929d89bd23dc40440734d3c665a88914c56cce 100644 GIT binary patch delta 10 Rcmcb_w2Wzj%EkaDMgSFC12q5u delta 52 zcmZ3+bctz#il#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC HWMu>ZjYvL>4nJa0`PlBg3pY5;15(X1hO;~pGD({?_AkNCr!7A%9u|}ePhNp{Th{WaOgb=efW@SdU#AKC( z6ARwVVq;fy<2jbdk+;gQ*>HlEzJ5OQLmvZk;S({OM^0ZlaA(b{%}+NsR7kbVW=v@+ zkeU%47gsLVw6W;C17lfU<=ae-W9RM`%K`;BXZ(3?$&&nd+0^?t@39>c&`)8Ssohv1 z*)p5;%TFCWg?Vfb(->wd%wc=Bh)p)=KpGRXnC^{0WmX2KfYp}z!s|JJPG|6R^>bP0 Hl+XkKf@NB1 diff --git a/src/resources/icons/type/Delegate.png b/src/resources/icons/type/Delegate.png index 24af9a7a0f6a3ab38f216aff8fae47bb3a895ece..a6d7808cba0aec072df730c8baa44f9cebaaf677 100644 GIT binary patch delta 10 Rcmcc1w2^6o%Eka*MgSH!16BY4 delta 52 zcmdnUbeCy@il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H3NQiybruco diff --git a/src/resources/icons/type/Delegate@2x.png b/src/resources/icons/type/Delegate@2x.png index a1ea9252fab3dd3bda989b7a69fbd32945d39b6f..97d30f5c3c821412555550731fdb6ea3555fa70c 100644 GIT binary patch delta 10 RcmeBTxyL*~Wn;iDMgSGm1Kz0NX0Wn+Lb695!h15N+{ delta 52 zcmcc4(#$$RMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz G&6ogefDPsV diff --git a/src/resources/icons/type/DeletedSnippet@2x.png b/src/resources/icons/type/DeletedSnippet@2x.png index aa9c07f8c8472b89021d94c61fd3bb56983a6f3a..7be2bc3a9eca151c47f05cb23e63f831b15c5b38 100644 GIT binary patch delta 10 Rcmey%agk$!@762I(1H=FT delta 53 zcmcb}@t0$QvKE6vvPY0F14ES>14Ba#1H&%{ApL@Yq11qZ;Z*_ygVhWM2JwP9y8>-C IDjKi=0Ea9NT>t<8 diff --git a/src/resources/icons/type/Diagram.png b/src/resources/icons/type/Diagram.png index 4b94e6385a71a87e22dd3b9291b914e44534cb1f..7b88c5db9a90fe06c28a550e484bac26e07528b4 100644 GIT binary patch delta 10 Rcmcc1w2^6o%Eka*MgSH!16BY4 delta 52 zcmdnUbeCy@il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQBi;q0ELSUmH+?% diff --git a/src/resources/icons/type/Diagram@2x.png b/src/resources/icons/type/Diagram@2x.png index 22c581988f39195b0cea331ad96898003389e1bb..08243f82dc8eac74a6ac6a49c386e756522fbae9 100644 GIT binary patch delta 10 RcmeBTxyL*~Wn;iDMgSGm1K4KnhL&3l40%%+7@kToFc_;dFi48e^pvUJ IsJNFA0Dx!?AOHXW diff --git a/src/resources/icons/type/Directive.png b/src/resources/icons/type/Directive.png index cb036709e7413e90aacdd345726a46261b60489e..f090f83d8fc3e11124aab470380d4b4f3546b5c3 100644 GIT binary patch delta 10 Rcmcb^w1H`Y%Eka5MgSHg15*G1 delta 52 zcmdnMbcbnzil#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC H4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3;5Yby>9 diff --git a/src/resources/icons/type/Element@2x.png b/src/resources/icons/type/Element@2x.png index fdceff2473842d841bcac903667a7e8fc3ac23f2..3fb4a97140e2ac434b293d2fd42b0d19230da80c 100644 GIT binary patch delta 10 RcmaFJw3TUs%EkaeMgSIv17ZLG delta 52 zcmdnW^pI(Sil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQBi~u0Ea6Lq5uE@ diff --git a/src/resources/icons/type/Entry.png b/src/resources/icons/type/Entry.png index 51839c1f03f5ff08a74cf024a95df9ecadf5f890..ffc00120423d4c847f49e7d49b2ccd5370a05645 100644 GIT binary patch delta 9 QcmdnZ)Xy|QWn#c<01-a}&j0`b delta 51 zcmeBY+RZdUMN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3;5Yby>9 diff --git a/src/resources/icons/type/Entry@2x.png b/src/resources/icons/type/Entry@2x.png index 24e0c515275ecba4dcb0d55cb9aef10abca51d6f..e1a0f1a1e97ef4fa5c666964316b668e9a3754f5 100644 GIT binary patch delta 10 RcmaFJw3TUs%EkaeMgSIv17ZLG delta 52 zcmdnW^pI(Sil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQBi~u0Ea6Lq5uE@ diff --git a/src/resources/icons/type/Enumeration.png b/src/resources/icons/type/Enumeration.png index 47ef92023e3ce389064395593ce9d730a0126259..e8e7f58dd3168c3f9aaaa1e6658c9a76ba2299f6 100644 GIT binary patch delta 9 QcmdnZ)Xy|QWn#c<01-a}&j0`b delta 51 zcmeBY+RZdUMN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3;5Yby>9 diff --git a/src/resources/icons/type/Enumeration@2x.png b/src/resources/icons/type/Enumeration@2x.png index 3a4041429510511b356b070fba7896d298aadeb3..42f71ed42aa4af5c70f842e2bf313b00005ad719 100644 GIT binary patch delta 10 RcmaFJw3TUs%EkaeMgSIv17ZLG delta 52 zcmdnW^pI(Sil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQBi~u0Ea6Lq5uE@ diff --git a/src/resources/icons/type/Environment.png b/src/resources/icons/type/Environment.png index 51839c1f03f5ff08a74cf024a95df9ecadf5f890..ffc00120423d4c847f49e7d49b2ccd5370a05645 100644 GIT binary patch delta 9 QcmdnZ)Xy|QWn#c<01-a}&j0`b delta 51 zcmeBY+RZdUMN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3;5Yby>9 diff --git a/src/resources/icons/type/Environment@2x.png b/src/resources/icons/type/Environment@2x.png index 24e0c515275ecba4dcb0d55cb9aef10abca51d6f..e1a0f1a1e97ef4fa5c666964316b668e9a3754f5 100644 GIT binary patch delta 10 RcmaFJw3TUs%EkaeMgSIv17ZLG delta 52 zcmdnW^pI(Sil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQBi~u0Ea6Lq5uE@ diff --git a/src/resources/icons/type/Error.png b/src/resources/icons/type/Error.png index 4e550328d8c689d20c7b4cd75b6ff127f7edcea1..45b9bce17a6f4afaebc8ad560670e01d5142cff8 100644 GIT binary patch delta 10 RcmaFFw2f(k%Eka8MgSI@17!dJ delta 52 zcmdnS^oVJKil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HiZTKKcODJ> diff --git a/src/resources/icons/type/Error@2x.png b/src/resources/icons/type/Error@2x.png index cde9f9d44013f0b2f252414b2c46c88e8d4ea25d..d0bb08081e71dd74c0b6905ad6716015ecd418b5 100644 GIT binary patch delta 10 RcmX@cJd1gP%Eo{)MgSFi1Csy% delta 52 zcmbQme2jU5il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HRx$zrZ6XdU diff --git a/src/resources/icons/type/Event.png b/src/resources/icons/type/Event.png index 58be593a5c756704eb9be41f1fee75f8dea5ed47..19116ccb233981305153c9ad018b96213ad02d58 100644 GIT binary patch delta 9 QcmbQk^nr1L%EW*(01~PL@c;k- delta 51 zcmeysIEQJ1il#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGf4% GJP!ba2oIhB diff --git a/src/resources/icons/type/Event@2x.png b/src/resources/icons/type/Event@2x.png index 27f1d4e85fe893f2b3b2591348acdbfc2d5f1a0f..14caba71f674dde45d29a32dba160b79d0dd8b33 100644 GIT binary patch delta 10 RcmZo-zQ!~`Wn+L5BLEa614aM< delta 52 zcmcb{)WkeNMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz GO&I}ePYvDx diff --git a/src/resources/icons/type/Exception.png b/src/resources/icons/type/Exception.png index 7049c223c785bf7ce06f59e2bbc20784c41144a6..5bf1ea2a47abf6c046b6465744d0c86a9bf87e1d 100644 GIT binary patch delta 10 Rcmey%bdhO-%Eka)MgSPM1GWGF delta 52 zcmcb}^p|OZil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H8ZZI?f))-= diff --git a/src/resources/icons/type/Exception@2x.png b/src/resources/icons/type/Exception@2x.png index 015047c88d31bea438de5b0b3427f38797c25025..d451af7062b55ae89b51cb623eb8b45ef86c84e3 100644 GIT binary patch delta 10 RcmZ3$@`ZVV%Eo{Ti~tvm1R?+c delta 52 zcmeyuyntnbil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HUSLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL GUIhSY&kmaa diff --git a/src/resources/icons/type/File@2x.png b/src/resources/icons/type/File@2x.png index 84021b8105ebc5db7c13167324f1ec297ff0d78d..c977228afe85b4f3d6e23d2c0d5990df88383bdb 100644 GIT binary patch delta 9 QcmX@gG?Qt9%EW-L01@c}?EnA( delta 51 zcmbQqbd+g=il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL G{r~`8P!5Fv diff --git a/src/resources/icons/type/Filter.png b/src/resources/icons/type/Filter.png index f97beb195ed8e878eb6615076dad74bbd7d36fc8..3938859f129dbe0d359d546bf6738f7e4de5ec0d 100644 GIT binary patch delta 9 QcmZ3)^o?LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL GUIhSY&kmaa diff --git a/src/resources/icons/type/Framework@2x.png b/src/resources/icons/type/Framework@2x.png index 84021b8105ebc5db7c13167324f1ec297ff0d78d..c977228afe85b4f3d6e23d2c0d5990df88383bdb 100644 GIT binary patch delta 9 QcmX@gG?Qt9%EW-L01@c}?EnA( delta 51 zcmbQqbd+g=il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL G{r~`8P!5Fv diff --git a/src/resources/icons/type/Function.png b/src/resources/icons/type/Function.png index 1ddadd2e2c71e4caf550476da7aee962fb7f7646..d09ea3a5363e7a06cf74bbbd60ed4a0fe0201108 100644 GIT binary patch delta 10 Rcmcc5yqS4|%Eo|xMgSLY1Kt1t delta 52 zcmdnYe4lxOil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HPGSTAcS;U+ diff --git a/src/resources/icons/type/Function@2x.png b/src/resources/icons/type/Function@2x.png index 7055fe2f382fc46e7ece1f04abb8fcc2c0164345..136800065f88022232709abe3f3d909113f7e5a2 100644 GIT binary patch delta 10 Rcmcb`vW{hf%EkaLCIA*315yA0 delta 52 zcmZ3-a*Jhxil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H@-hJcbf*pK diff --git a/src/resources/icons/type/Global.png b/src/resources/icons/type/Global.png index 69c471a6914fa6b1a4e9fb47f08df5fbc84267c6..f74d2be22f462effce5e85338ea37523d6d51719 100644 GIT binary patch delta 10 RcmZo-zQ!~`Wn+L5BLEa614aM< delta 52 zcmcb{)WkeNMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz GO&I}ePYvDx diff --git a/src/resources/icons/type/Global@2x.png b/src/resources/icons/type/Global@2x.png index 32627a3454cf6cf4eec44d801738944ea98733e7..822ef762159f2a57fb2303882ca22773a4967646 100644 GIT binary patch delta 10 RcmZ3?@|}5t%Eo}pi~twN1S
LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HUSk9RdK(VI diff --git a/src/resources/icons/type/Guide.png b/src/resources/icons/type/Guide.png index afb5b6276fb178b742f93162e43bcb43fdd3763b..579fa6389233aca21b19cb5b184f50d9baf44440 100644 GIT binary patch delta 10 RcmaFFv5jMb@14Ba#1H&%{ApL@Yq11qZ;Z*_ygVhWM2JwP9y8>-C IDvGiI0DJxp3;+NC diff --git a/src/resources/icons/type/Guide@2x.png b/src/resources/icons/type/Guide@2x.png index d2b2025deca835b268380daac167cdbe67608577..df2fe0c68eca285d10da36c5a280099621183a7e 100644 GIT binary patch delta 10 RcmeC;zsEO0Wn+L9I{+1m1AG7g delta 52 zcmcb|*Tp|UMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz GZP@{HMGh1I diff --git a/src/resources/icons/type/Hook.png b/src/resources/icons/type/Hook.png index b338384f5b9f5b286377cf061fa4a6ca74c61557..b088fcea9477b2024530e43ff1f7e9d9db4bd368 100644 GIT binary patch delta 9 QcmbQn^ontU%EW+U01`w4-v9sr delta 51 zcmaFGIE`t7il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL Go&*486ApI( diff --git a/src/resources/icons/type/Hook@2x.png b/src/resources/icons/type/Hook@2x.png index c2467961ff0804108374a9f7187564e9ea40818e..b0173cb456160cf54357ed1751ba80cd2df378f3 100644 GIT binary patch delta 10 RcmZo=zR5H}Wn+LTBLEa&15W?| delta 52 zcmcb~)XF?TMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz GEf@i8hYjZd diff --git a/src/resources/icons/type/Index.png b/src/resources/icons/type/Index.png index 4f5ab7ef7d887c69cfd6babfadacf2f77b807e07..6e2fd9b4af62198d3e148c93bb90678e746cffeb 100644 GIT binary patch delta 9 Qcmeysc!Y6+%EW*L02DR@>;M1& delta 51 zcmX@Y_;M1& delta 51 zcmX@Y_;M1& delta 51 zcmX@Y_~~Wn#ca01)2;pa1{> delta 51 zcmcc0*vK?NMN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsJI0HZI=z; diff --git a/src/resources/icons/type/Instance@2x.png b/src/resources/icons/type/Instance@2x.png index c206248c26b7fb2f89e9e88a0668052eab120217..a2d2e96938b5989db4dbd836e050d45a19498955 100644 GIT binary patch delta 10 Rcmcc5w3%sw%EkbGMgSIH16%+A delta 52 zcmdnYbf0O0il#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC H6k-Gbl9CSz diff --git a/src/resources/icons/type/Instruction.png b/src/resources/icons/type/Instruction.png index 4f5ab7ef7d887c69cfd6babfadacf2f77b807e07..6e2fd9b4af62198d3e148c93bb90678e746cffeb 100644 GIT binary patch delta 9 Qcmeysc!Y6+%EW*L02DR@>;M1& delta 51 zcmX@Y_;M1& delta 51 zcmX@Y_LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL Gz6StW!wzZy diff --git a/src/resources/icons/type/Keyword.png b/src/resources/icons/type/Keyword.png index 75ca62e4f45f1937a124759196a8da1a20585d06..2c0490116fc07a1f00dfad0745b5e6cd963e21f1 100644 GIT binary patch delta 10 Rcmey&bew5|%Eka?MgSM@1DF5+ delta 52 zcmX@k^qFabil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b Hsxblpeg+OO diff --git a/src/resources/icons/type/Keyword@2x.png b/src/resources/icons/type/Keyword@2x.png index 515b5b30d0693c3afb43efea6fe7b5b8f48225b7..06928106594c9cc4d257fd1fb774b76de2d77116 100644 GIT binary patch delta 10 RcmbQj@`8DS%Eo{ri~ts#1O5O2 delta 52 zcmaFCJcVU~il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H9%lpqbOR2S diff --git a/src/resources/icons/type/Lemma.png b/src/resources/icons/type/Lemma.png index 880f9ee7056e98bb842a031e11e13c2c8efd4cba..a9d3fd2fb5a2e1b749e9ea77d715b289aea6ea39 100644 GIT binary patch delta 9 QcmbQj^n!7M%EW*p01_et*#H0l delta 51 zcmaFCIE86~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_yk` HQSmqcbrud8 diff --git a/src/resources/icons/type/Lemma@2x.png b/src/resources/icons/type/Lemma@2x.png index 784c2439dff89e79ec656d69f8d9876115b5bd96..7a9ea0d043fdf98c3de429fac10d018fd7141743 100644 GIT binary patch delta 9 QcmX@WG=*t`%EW*V01=b}-T(jq delta 51 zcmbQjbbx7sil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_yk` HQSmbXZ6ppJ diff --git a/src/resources/icons/type/Library.png b/src/resources/icons/type/Library.png index b3c0c83580901a9a02939f0e7afb21211b6a1f8b..bf458ccfb83e32767643d0fb11468449c255b8e6 100644 GIT binary patch delta 9 QcmbQj^n!7M%EW*p01_et*#H0l delta 51 zcmaFCIE86~il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL G9tQwqNe*!U diff --git a/src/resources/icons/type/Library@2x.png b/src/resources/icons/type/Library@2x.png index 9443d03cdaf34cc632e7429e51fd1de4f24610d1..923d19903094d78ae0be581321c4a1d37b06874f 100644 GIT binary patch delta 9 QcmX@WG=*t`%EW*V01=b}-T(jq delta 51 zcmbQjbbx7sil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL Geg*(sR}OXn diff --git a/src/resources/icons/type/Literal.png b/src/resources/icons/type/Literal.png index 15eadec80cb8db54d3305209531a9a56084fab9d..bd3b28ebc7428156c69a36cd284eaaa6c7a694a1 100644 GIT binary patch delta 9 QcmbQj^n!7M%EW*p01_et*#H0l delta 51 zcmaFCIE86~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_yk` HQSmqcbrud8 diff --git a/src/resources/icons/type/Literal@2x.png b/src/resources/icons/type/Literal@2x.png index 678de617576e93c2a2b4b8011af31a3223933765..f8824f518031ce5c62a12bcc99cdcb0f472c731c 100644 GIT binary patch delta 9 QcmX@WG=*t`%EW*V01=b}-T(jq delta 51 zcmbQjbbx7sil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_yk` HQSmbXZ6ppJ diff --git a/src/resources/icons/type/Macro.png b/src/resources/icons/type/Macro.png index 2f1d30aaabc173de714277c28269da24d8aacab6..e13cc63ecfa05b16749e5357e8173aa0ddae37d5 100644 GIT binary patch delta 9 QcmdnO)WI}CWn#b+01(Inx&QzG delta 51 zcmeBR+QKwJMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@Er Gp926_n+{R{ diff --git a/src/resources/icons/type/Macro@2x.png b/src/resources/icons/type/Macro@2x.png index e25617d30932961191d067d8f9804066ebf3f565..1bc6183acc79cefba6b50e0b1811a2ff2add59a0 100644 GIT binary patch delta 254 zcmaFGw2x_m1TP0O0|SHWW&LG9%6MX+N&Wx-|G#D!{s3~BOM?7@83OKyEetykvL>4nJa0`PlBg3pY5;15(X1hO;~pGD({?_AkNCr!7A%9u|}ePhNp{Th{WaOgb=efW@SdU#AKC( z6ARwVVq;fy<2jbdk+;gQ*>HlEzJ5OQLmvZk;S({OM^0ZlaA(b{%}+NsR7kbVW=v@+ zkeU%47gsLVw6W;C17lfU<=ae-W9RM`%K`;BXZ(3?$&&nd+0^?t@39>c&`)8Ssohv1 z*)p5;%TFCWg?Vfb(->wd%wc=Bh)p)=KpGRXnC^{0WmX2KfYp}z!s|JJPG|6R^>bP0 Hl+XkKf@NB1 diff --git a/src/resources/icons/type/Method.png b/src/resources/icons/type/Method.png index 402374a81ffb65e9f04e0e7b3be1af46c5c5ee4c..38ce04947011275293cf195d61708858557fb038 100644 GIT binary patch delta 10 RcmbQs{E=yb%Eka+MgSH-1D5~* delta 52 zcmey!G?#gTil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H1~38uc1I2` diff --git a/src/resources/icons/type/Method@2x.png b/src/resources/icons/type/Method@2x.png index 1850729a06ebbf5b67139c1d756da6e32f1b7751..623b7e9a087542d7454a63db748831a0873adc99 100644 GIT binary patch delta 10 RcmeBRxx+j`Wn;h&MgSG81KI!p delta 52 zcmcb^+`%$IMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQXP2ZzB$J diff --git a/src/resources/icons/type/Mixin.png b/src/resources/icons/type/Mixin.png index 2c55486564f9316d81c272fa4f061be1b3e9b7c3..41d520205696b23aab210c8e893933387d3848a8 100644 GIT binary patch delta 10 RcmbQs{E=yb%Eka+MgSH-1D5~* delta 52 zcmey!G?#gTil#!cN02WAL+%U)hT=X3hTkj<49#m87^)^PFuYpEz+m`}fk9-?ne%Q+ I8x;c>0hAaIz5oCK diff --git a/src/resources/icons/type/Mixin@2x.png b/src/resources/icons/type/Mixin@2x.png index 081e115cd6082c45919e77501ec722c24d4e006a..2832b04c7ddb8a77a08651c3cc5336910c60482e 100644 GIT binary patch delta 10 RcmeBRxx+j`Wn;h&MgSG81KI!p delta 52 zcmcb^+`%$IMN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvUJ IsJNRE0DqVc8UO$Q diff --git a/src/resources/icons/type/Modifier.png b/src/resources/icons/type/Modifier.png index 48d131e06fbd19c3662be8f1153e1a98d08237a6..61830023a7744cbc7b5a2d2e37ebe85d327d535f 100644 GIT binary patch delta 10 RcmeBTzQ;5{Wn+L9BLEb{16}|C delta 52 zcmcb|)WtkOMN=W!BgmJ5p-Pp3p`n?9;pcxK{gQ#9)PRBERRRNp)eHs(@%%~gN8L6m H+A;zFi#rbs diff --git a/src/resources/icons/type/Modifier@2x.png b/src/resources/icons/type/Modifier@2x.png index c1ce8a7bb34b2112963c6ed02ceedb4f574699c2..9e6cf0fb12945a894c72c64f68413d212c260d2c 100644 GIT binary patch delta 10 RcmbQp@|1ak%Eo|$i~ts31N8s^ delta 52 zcmaFLJdtIBil#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC HJi-V7k9QBE diff --git a/src/resources/icons/type/Module.png b/src/resources/icons/type/Module.png index fc7de5e7aa499c2d9ff0445d458487c7ca000c5d..658fdc99b1dfd2749e5245b94fbac3f17d30e494 100644 GIT binary patch delta 10 RcmbQs{E=yb%Eka+MgSH-1D5~* delta 52 zcmey!G?#gTil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H1~38uc1I2` diff --git a/src/resources/icons/type/Module@2x.png b/src/resources/icons/type/Module@2x.png index 87abc699dcab33b2fd787fb58ae318b8ab0cea2b..cd5c70bad36a727e050aee947e549e29d4e14733 100644 GIT binary patch delta 10 RcmZo=xyd|1Wn;irMgSFX1JM8g delta 52 zcmcb~+{!XRMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQ66~ZR-wc diff --git a/src/resources/icons/type/Namespace.png b/src/resources/icons/type/Namespace.png index 4f3535a9e99edeb0c9635ff7754671be471e5cac..ece3292849a80af65bc252eb4d33399656c8d4de 100644 GIT binary patch delta 10 RcmaFFw2f(k%Eka8MgSI@17!dJ delta 52 zcmdnS^oVJKil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HiZTKKcODJ> diff --git a/src/resources/icons/type/Namespace@2x.png b/src/resources/icons/type/Namespace@2x.png index 34d0a951382e537e5cc7ea178b06a77f0515366d..0cbb097942e95166be8a4eb6354c7d367556babb 100644 GIT binary patch delta 10 Rcmcb}yp(x@%Eo|3MgSI91GE4D delta 52 zcmZ3=e35yAil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HwlD$!aheWH diff --git a/src/resources/icons/type/NewSnippet.png b/src/resources/icons/type/NewSnippet.png index 3961d07c36364441fe1ae8fb1e04dd0010049730..9148b87cc73b927da829614a7eb13f27812ebd9f 100644 GIT binary patch delta 10 Rcmcc2vYcgt%Eka@CIA(X13dr$ delta 52 zcmZ3^a+zgLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HvM~VwanB9a diff --git a/src/resources/icons/type/NewSnippet@2x.png b/src/resources/icons/type/NewSnippet@2x.png index d36879176a53525a0f98165da2f496ed3c9ee59f..914695d3b9aff4aff2b773eaf87a218190a50431 100644 GIT binary patch delta 10 RcmdnO(ZMl6d87YRW&jmm1Lyz% delta 53 zcmeC+*upVES&Km-*(1o8fuTx`fuW&=f#DYekbc3yP-?)y@G60U!DdWn(}*BLEYx15N+{ delta 52 zcmZo>Ue7#1MN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvUJ IsF=hE0CYbMjsO4v diff --git a/src/resources/icons/type/Object@2x.png b/src/resources/icons/type/Object@2x.png index 6d442b8e8840f42bf7ed8815f67103cd8b6e3512..e2a2064ba3136413eb2603cc270595caf08b9268 100644 GIT binary patch delta 10 RcmZ3;`jusZ%Eo{|CIA+(1E>H1 delta 52 zcmey$vXFIxil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQ89!G0Es0H=l}o! diff --git a/src/resources/icons/type/Operator.png b/src/resources/icons/type/Operator.png index 56d44b101c83c5982c1b71cc9fe7715293ca4333..a797cd887b4e319e81c6118f2211376db8fec88a 100644 GIT binary patch delta 10 RcmZ3_+{`>dWn(}*BLEYx15N+{ delta 52 zcmZo>Ue7#1MN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvUJ IsF=hE0CYbMjsO4v diff --git a/src/resources/icons/type/Operator@2x.png b/src/resources/icons/type/Operator@2x.png index b64d56d81e4607a34738c4e83f745d68c332db5c..99f5171783f8894fd9a3fba6349e84b5c52f97f4 100644 GIT binary patch delta 10 RcmZ3;`jusZ%Eo{|CIA+(1E>H1 delta 52 zcmey$vXFIxil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQ89!G0Es0H=l}o! diff --git a/src/resources/icons/type/Option.png b/src/resources/icons/type/Option.png index 988dead1260928eef5ca8b5d59593a612c152df3..6a4b57ed83ea6835d584514b4cb0c0bd3d8fea01 100644 GIT binary patch delta 10 RcmZ3_+{`>dWn(}*BLEYx15N+{ delta 52 zcmZo>Ue7#1MN=W!BgmJ5A$JA?LvbGi!>4KnhL&3l40%%+7@kToFc_;dFi48e^pvUJ IsF=hE0CYbMjsO4v diff --git a/src/resources/icons/type/Option@2x.png b/src/resources/icons/type/Option@2x.png index 2e93584ede3514111e317634a3fc3bf141b47f3d..5c4350c213bca831f49f9a27c52fcec276ee1ca9 100644 GIT binary patch delta 10 RcmZ3;`jusZ%Eo{|CIA+(1E>H1 delta 52 zcmey$vXFIxil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQ89!G0Es0H=l}o! diff --git a/src/resources/icons/type/Package.png b/src/resources/icons/type/Package.png index 9f893c0568d78a91ed956a7204e888a3c44847cd..9c215dc04448a3f7615c627b87fabc8bdf117446 100644 GIT binary patch delta 10 RcmaFCw1;Ve%EkZ*MgSKR19t!b delta 52 zcmdnP^nz)Eil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HN;3igd5#Vb diff --git a/src/resources/icons/type/Package@2x.png b/src/resources/icons/type/Package@2x.png index f925cce227eb787f74c441781aa9ed8165b1391a..1dc2294dbb2f77451727eff2cde957fec9129ecb 100644 GIT binary patch delta 10 RcmaFMe2{s9%Eo}Xi~tyi1PA~C delta 52 zcmX@e{FZrwil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HE?@)zeEJTc diff --git a/src/resources/icons/type/Plugin.png b/src/resources/icons/type/Plugin.png index 9f893c0568d78a91ed956a7204e888a3c44847cd..9c215dc04448a3f7615c627b87fabc8bdf117446 100644 GIT binary patch delta 10 RcmaFCw1;Ve%EkZ*MgSKR19t!b delta 52 zcmdnP^nz)Eil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HN;3igd5#Vb diff --git a/src/resources/icons/type/Plugin@2x.png b/src/resources/icons/type/Plugin@2x.png index f925cce227eb787f74c441781aa9ed8165b1391a..1dc2294dbb2f77451727eff2cde957fec9129ecb 100644 GIT binary patch delta 10 RcmaFMe2{s9%Eo}Xi~tyi1PA~C delta 52 zcmX@e{FZrwil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HE?@)zeEJTc diff --git a/src/resources/icons/type/Procedure.png b/src/resources/icons/type/Procedure.png index e3df896523bc922af11c6eb81f8cf387517115b3..e6f0525e00f3c7d10b424a1b370256b7e50953b2 100644 GIT binary patch delta 10 RcmaFCw1;Ve%EkZ*MgSKR19t!b delta 52 zcmdnP^nz)Eil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HN;3igd5#Vb diff --git a/src/resources/icons/type/Procedure@2x.png b/src/resources/icons/type/Procedure@2x.png index 4e0e1807e8241ba6b3c52da4d61c38bf827f9a4e..19bdfb107925ae76f8c16921a9154084a06e8582 100644 GIT binary patch delta 10 RcmaFMe2{s9%Eo}Xi~tyi1PA~C delta 52 zcmX@e{FZrwil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HE?@)zeEJTc diff --git a/src/resources/icons/type/Projection.png b/src/resources/icons/type/Projection.png index e3df896523bc922af11c6eb81f8cf387517115b3..e6f0525e00f3c7d10b424a1b370256b7e50953b2 100644 GIT binary patch delta 10 RcmaFCw1;Ve%EkZ*MgSKR19t!b delta 52 zcmdnP^nz)Eil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HN;3igd5#Vb diff --git a/src/resources/icons/type/Projection@2x.png b/src/resources/icons/type/Projection@2x.png index 4e0e1807e8241ba6b3c52da4d61c38bf827f9a4e..19bdfb107925ae76f8c16921a9154084a06e8582 100644 GIT binary patch delta 10 RcmaFMe2{s9%Eo}Xi~tyi1PA~C delta 52 zcmX@e{FZrwil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HE?@)zeEJTc diff --git a/src/resources/icons/type/Property.png b/src/resources/icons/type/Property.png index 87cfc52a3f75aac62313290799bff337cd2f762b..719967d92cdf9a722d8a884102182ec5711767fe 100644 GIT binary patch delta 10 RcmbQh{Df(O%EkZ(MgSE&18@KU delta 52 zcmaFDG=X`7il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HIx_+QaQ_Yn diff --git a/src/resources/icons/type/Property@2x.png b/src/resources/icons/type/Property@2x.png index 9afcab9a72379862f177e28717b8c2dec823b386..a47a3e8ce0a0f307824d796825dbe2f97d3eddcb 100644 GIT binary patch delta 10 Rcmey!e3W^D%Eo|&i~tzd1QY-O delta 52 zcmX@g{E>Nril#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HE@1=!ewq%f diff --git a/src/resources/icons/type/Protocol.png b/src/resources/icons/type/Protocol.png index 84122fbfc1b414437865d230d1427da9602b5ec4..a12b9dde87c8b5034b47b64b47c97b953b9bfd3f 100644 GIT binary patch delta 10 RcmZ3+{EKOV%Eo{&MgSJ{1F`@B delta 52 zcmeyxw2XOzil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HMlu2bdG8KN diff --git a/src/resources/icons/type/Protocol@2x.png b/src/resources/icons/type/Protocol@2x.png index 037a11626e9719ae876cc68873b6897caf3d2e64..dce85d2c570db9f458d9ea87d8da31f3cef7f6b8 100644 GIT binary patch delta 10 Rcmey*e3^NI%Eo~8i~t$$1U>)& delta 52 zcmcc2{GWM(il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HZej!ggh~$9 diff --git a/src/resources/icons/type/Provider.png b/src/resources/icons/type/Provider.png index 0b7287faa6dd2876918d3c1d5f80a53167fc4479..2c8e5069e70ee54808aa8ee4358bb9f1cb4d6fac 100644 GIT binary patch delta 10 RcmaFKyq9@`%Eo}1i~txn1N;C0 delta 52 zcmdnX{E~Tsil#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC HoWlqJm8&EL#Y7+!>a@a2CEqi4C48d;*Yv* IRPLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HN;3igd5#Vb diff --git a/src/resources/icons/type/Provisioner@2x.png b/src/resources/icons/type/Provisioner@2x.png index 4e0e1807e8241ba6b3c52da4d61c38bf827f9a4e..19bdfb107925ae76f8c16921a9154084a06e8582 100644 GIT binary patch delta 10 RcmaFMe2{s9%Eo}Xi~tyi1PA~C delta 52 zcmX@e{FZrwil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HE?@)zeEJTc diff --git a/src/resources/icons/type/Query.png b/src/resources/icons/type/Query.png index 3723f8756f754a4e53a4d8893bb371b089386529..5eff5167e2593bc99df68ca8ec09f5a38c6113df 100644 GIT binary patch delta 10 RcmX@hvXEth%Eo}di~tuG1S$Xk delta 51 zcmZ3;a+YO+il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&Ny5 GG64W#ZVj^l diff --git a/src/resources/icons/type/Query@2x.png b/src/resources/icons/type/Query@2x.png index fb4cff5416e4b65a88600c759480bf1240a9da90..eef6cb6446e312ba6b5b6b3cef13009b0e74fb1c 100644 GIT binary patch delta 10 RcmbQi`G#YH@14Ba#1H&%{ApL@Yq11qZ;Z*_ygVhWM2JwP9y8>-C IDtfa30C@}!F8}}l diff --git a/src/resources/icons/type/Record.png b/src/resources/icons/type/Record.png index cb84bf665b48e319506f641503b7fddb18e51438..bb51ab5f8849386f9395ecc08b39720f46dac3c8 100644 GIT binary patch delta 10 Rcmcb`w2oLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H@-hMdbKVW* diff --git a/src/resources/icons/type/Record@2x.png b/src/resources/icons/type/Record@2x.png index bdfc1a0ef5f277908f5102abfe66a4ee9fd8c366..b8ce0176d92a50dc1542c90d515f368fd5d07319 100644 GIT binary patch delta 10 RcmZo?xy?L5Wn;j0MgSF<1J?im delta 52 zcmcc3+|DvVMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQFD0Zo3X| diff --git a/src/resources/icons/type/Relationship.png b/src/resources/icons/type/Relationship.png index cb84bf665b48e319506f641503b7fddb18e51438..bb51ab5f8849386f9395ecc08b39720f46dac3c8 100644 GIT binary patch delta 10 Rcmcb`w2oLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H@-hMdbKVW* diff --git a/src/resources/icons/type/Relationship@2x.png b/src/resources/icons/type/Relationship@2x.png index bdfc1a0ef5f277908f5102abfe66a4ee9fd8c366..b8ce0176d92a50dc1542c90d515f368fd5d07319 100644 GIT binary patch delta 10 RcmZo?xy?L5Wn;j0MgSF<1J?im delta 52 zcmcc3+|DvVMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQFD0Zo3X| diff --git a/src/resources/icons/type/Report.png b/src/resources/icons/type/Report.png index cb84bf665b48e319506f641503b7fddb18e51438..bb51ab5f8849386f9395ecc08b39720f46dac3c8 100644 GIT binary patch delta 10 Rcmcb`w2oLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H@-hMdbKVW* diff --git a/src/resources/icons/type/Report@2x.png b/src/resources/icons/type/Report@2x.png index bdfc1a0ef5f277908f5102abfe66a4ee9fd8c366..b8ce0176d92a50dc1542c90d515f368fd5d07319 100644 GIT binary patch delta 10 RcmZo?xy?L5Wn;j0MgSF<1J?im delta 52 zcmcc3+|DvVMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQFD0Zo3X| diff --git a/src/resources/icons/type/Resource.png b/src/resources/icons/type/Resource.png index cb84bf665b48e319506f641503b7fddb18e51438..bb51ab5f8849386f9395ecc08b39720f46dac3c8 100644 GIT binary patch delta 10 Rcmcb`w2oLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H@-hMdbKVW* diff --git a/src/resources/icons/type/Resource@2x.png b/src/resources/icons/type/Resource@2x.png index bdfc1a0ef5f277908f5102abfe66a4ee9fd8c366..b8ce0176d92a50dc1542c90d515f368fd5d07319 100644 GIT binary patch delta 10 RcmZo?xy?L5Wn;j0MgSF<1J?im delta 52 zcmcc3+|DvVMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@cz HcQFD0Zo3X| diff --git a/src/resources/icons/type/Sample.png b/src/resources/icons/type/Sample.png index d4b6bbae0e0577d0e2d253cc27040989e7507919..8f8c54fbb799336018e5c6b21f3f4a5ce998cf34 100644 GIT binary patch delta 10 RcmeBVzsoj3d85A-GXNCq17rXI delta 53 zcmcc1*2z9WS&Km-*(1o8fuTx`fuW&=f#DYekbc3yP-?)y@G60U!DXRSatRIn diff --git a/src/resources/icons/type/Sample@2x.png b/src/resources/icons/type/Sample@2x.png index d97ee95092d073926ee50cd177abc318aa8a7574..de38d7ab79cfbfb2557cb1c594323f927053391a 100644 GIT binary patch delta 10 RcmbQt|D11v%Eka^b^sPW1D5~* delta 52 zcmaFPH<^Eeil#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b Hy0HTQcI^%? diff --git a/src/resources/icons/type/Schema.png b/src/resources/icons/type/Schema.png index dae63988f6eb7a6e857fb158fbfbbe0bca3f3177..87f6d189bdf0b3533fb1edc653d47d3ccf3f17d8 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Script.png b/src/resources/icons/type/Script.png index 6f5a914a9f6517d8a4e30328b90f0bdd17d0e755..f58a61795de0fb06426fdbcdf9255f72fcf5f298 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Section.png b/src/resources/icons/type/Section.png index d57b2c0d1f0b005de658128bfbbe1e71e504e433..77ff762bfc959c8a8ec216b75510af5a12f17dc2 100644 GIT binary patch delta 9 QcmX@kG@EIH%EW;001^uW^8f$< delta 51 zcmbQubew5|il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_yk` HQSlc5Z|4p( diff --git a/src/resources/icons/type/Section@2x.png b/src/resources/icons/type/Section@2x.png index 37dc5cd359436892c70c8f69723b6b79cedd4b7b..bcb647b9eb7e458ddbbe02f28f75301b9243b2b7 100644 GIT binary patch delta 10 Rcmeyxa*kz!%EkaKCIA?m1F`@B delta 52 zcmX@d@{47Hil#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQBju(0FoRH@&Et; diff --git a/src/resources/icons/type/Service.png b/src/resources/icons/type/Service.png index dae63988f6eb7a6e857fb158fbfbbe0bca3f3177..87f6d189bdf0b3533fb1edc653d47d3ccf3f17d8 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Setting.png b/src/resources/icons/type/Setting.png index bfc5ecb5931f8dc1d7c82ab6a6605b9c5d3aa17a..6a6460812861a4e6b0e206911cb8b857fff9009c 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Shortcut.png b/src/resources/icons/type/Shortcut.png index 6f0d5d6f51b81bfe25be5d0897331fae8fc89e9e..5f5dcee8518ef19676b17878ccbd7d2e3db32c50 100644 GIT binary patch delta 10 RcmZ3?{GDln%Eo|TMgSJL1E~N2 delta 52 zcmey)w3vBLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H3NQfxb>9v1 diff --git a/src/resources/icons/type/Snippet@2x.png b/src/resources/icons/type/Snippet@2x.png index f5f11e93be18483a8ca159068b896377bd38f77c..7677000a124151d5a3a0b5e2449aa00a3c35e8d2 100644 GIT binary patch delta 10 RcmeC;y2m*|d87Ys762A81MUC- delta 53 zcmcb|*~K+MS&Km-*(1o8fuTx`fuW&=f#DYekbc3yP-?)y@G60U!D^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Structure.png b/src/resources/icons/type/Structure.png index 46bed4179e04c7650fb7cda68064465087ad7193..31db775822a732739786f85a56ab0c2631558278 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Style.png b/src/resources/icons/type/Style.png index bfc5ecb5931f8dc1d7c82ab6a6605b9c5d3aa17a..6a6460812861a4e6b0e206911cb8b857fff9009c 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Subroutine.png b/src/resources/icons/type/Subroutine.png index bfc5ecb5931f8dc1d7c82ab6a6605b9c5d3aa17a..6a6460812861a4e6b0e206911cb8b857fff9009c 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Syntax.png b/src/resources/icons/type/Syntax.png index 6f5a914a9f6517d8a4e30328b90f0bdd17d0e755..f58a61795de0fb06426fdbcdf9255f72fcf5f298 100644 GIT binary patch delta 10 RcmX@ZynuOv%Eo{iMgSG_1El}} delta 52 zcmZ3$e1>^~il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQL&y80DuP#k diff --git a/src/resources/icons/type/Table.png b/src/resources/icons/type/Table.png index 93e2aa2b15390fbd5d9be670fba798b4d6d92ed3..19f520a7acd746b2e7d30713e131febe04f36322 100644 GIT binary patch delta 9 QcmeBUdc-(EWn#cS01>keN4 diff --git a/src/resources/icons/type/Table@2x.png b/src/resources/icons/type/Table@2x.png index c7d86b6a39ebafbf45683546f09f6ef30e19cecc..2790afe7eaddf0fe094b852003a16b568a9f5e23 100644 GIT binary patch delta 9 QcmdnV)XOwMWn#cf01+Jn$p8QV delta 51 zcmeBW+Q~FQMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@Er G-v9tvln!A4 diff --git a/src/resources/icons/type/Tactic.png b/src/resources/icons/type/Tactic.png index 1a48a57b12f4558edae868848c77257aaee2384d..572ae67184e0b14e4bcdf71e82e64b8aec77c6e1 100644 GIT binary patch delta 176 zcmbQl^nr1L1TP0O0|SG`w7ZXil<~wslluSv|NqiWnh)eMmIV0)GdMiEkp|)`yKfXC~&X{E>&9e_kVu3m&cxR zzTGo#>p2`!U|!bP0l+XkK$?`w% delta 192 zcmeysIEiV3ge40z0|Ud`G=oP#N+H=J$d`d3cLoDPaUTQ2Zx#lI<~0lqRTCH(UM*u_ zFnq_rAhPGoc{e4XT7!wICM@?RO{$)lAX>uE!7A$k6yz-Mh%9Dc;1&j9Muu5)B!GfW zo-U3d9M_W*LYNqt*(L@E6r=_CGB+x)UH$Uu(4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3l|YGDou diff --git a/src/resources/icons/type/Tag.png b/src/resources/icons/type/Tag.png index 93e2aa2b15390fbd5d9be670fba798b4d6d92ed3..19f520a7acd746b2e7d30713e131febe04f36322 100644 GIT binary patch delta 9 QcmeBUdc-(EWn#cS01>keN4 diff --git a/src/resources/icons/type/Tag@2x.png b/src/resources/icons/type/Tag@2x.png index c7d86b6a39ebafbf45683546f09f6ef30e19cecc..2790afe7eaddf0fe094b852003a16b568a9f5e23 100644 GIT binary patch delta 9 QcmdnV)XOwMWn#cf01+Jn$p8QV delta 51 zcmeBW+Q~FQMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@Er G-v9tvln!A4 diff --git a/src/resources/icons/type/Test.png b/src/resources/icons/type/Test.png index 1a48a57b12f4558edae868848c77257aaee2384d..572ae67184e0b14e4bcdf71e82e64b8aec77c6e1 100644 GIT binary patch delta 176 zcmbQl^nr1L1TP0O0|SG`w7ZXil<~wslluSv|NqiWnh)eMmIV0)GdMiEkp|)`yKfXC~&X{E>&9e_kVu3m&cxR zzTGo#>p2`!U|!bP0l+XkK$?`w% delta 192 zcmeysIEiV3ge40z0|Ud`G=oP#N+H=J$d`d3cLoDPaUTQ2Zx#lI<~0lqRTCH(UM*u_ zFnq_rAhPGoc{e4XT7!wICM@?RO{$)lAX>uE!7A$k6yz-Mh%9Dc;1&j9Muu5)B!GfW zo-U3d9M_W*LYNqt*(L@E6r=_CGB+x)UH$Uu(4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3l|YGDou diff --git a/src/resources/icons/type/Trait.png b/src/resources/icons/type/Trait.png index 93e2aa2b15390fbd5d9be670fba798b4d6d92ed3..19f520a7acd746b2e7d30713e131febe04f36322 100644 GIT binary patch delta 9 QcmeBUdc-(EWn#cS01>keN4 diff --git a/src/resources/icons/type/Trait@2x.png b/src/resources/icons/type/Trait@2x.png index c7d86b6a39ebafbf45683546f09f6ef30e19cecc..2790afe7eaddf0fe094b852003a16b568a9f5e23 100644 GIT binary patch delta 9 QcmdnV)XOwMWn#cf01+Jn$p8QV delta 51 zcmeBW+Q~FQMN=W!BgmJ5p-PQ`p`nF=;THpte!;*{YQVtoDuIE)Y6b&?c)^@qfi@Er G-v9tvln!A4 diff --git a/src/resources/icons/type/Trigger.png b/src/resources/icons/type/Trigger.png index 1a48a57b12f4558edae868848c77257aaee2384d..572ae67184e0b14e4bcdf71e82e64b8aec77c6e1 100644 GIT binary patch delta 176 zcmbQl^nr1L1TP0O0|SG`w7ZXil<~wslluSv|NqiWnh)eMmIV0)GdMiEkp|)`yKfXC~&X{E>&9e_kVu3m&cxR zzTGo#>p2`!U|!bP0l+XkK$?`w% delta 192 zcmeysIEiV3ge40z0|Ud`G=oP#N+H=J$d`d3cLoDPaUTQ2Zx#lI<~0lqRTCH(UM*u_ zFnq_rAhPGoc{e4XT7!wICM@?RO{$)lAX>uE!7A$k6yz-Mh%9Dc;1&j9Muu5)B!GfW zo-U3d9M_W*LYNqt*(L@E6r=_CGB+x)UH$Uu(4KnhL&3l40%%+7@kToFc_;dFi48e^pvTe HsQ3l|YGDou diff --git a/src/resources/icons/type/Type.png b/src/resources/icons/type/Type.png index c8ca3933647062192d29c806a12a0ead11855e6c..70dfe4d7bc90fc644c42ba2d64b829e5de614765 100644 GIT binary patch delta 176 zcmbQl^nr1L1TP0O0|SG`w7ZXil<~wslluSv|JU5u;Sc08mIV0)GdMiEkp|)`yKfXC~&X{E>&9e_kVu3m&cxR zzTGo#>p2`!U|!bP0l+XkK=Q=j4zxEbxddW?il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQIUfY0D?;megFUf diff --git a/src/resources/icons/type/Union@2x.png b/src/resources/icons/type/Union@2x.png index 878edfe9a1b67d14d1973873838eef5d03cf4b23..c0936105867c4a1498515ebb6d5d3732f6f10709 100644 GIT binary patch delta 10 Rcmcb|yoq^&%Eo{`MgSLE1KR)q delta 52 zcmdnQe2;m8il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQE?(80Ebr&8vpLqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HRx<(sZSoE= diff --git a/src/resources/icons/type/Value@2x.png b/src/resources/icons/type/Value@2x.png index 9deba7f392f8b7a0265b6e5c8e1c8a989fea080a..fcabbdbf0bf8cad00a6955876270644ca2ec6fc6 100644 GIT binary patch delta 10 RcmX@eGL>b5%Eo|?i~trV1O@;A delta 52 zcmbQra*$<$il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HeqjUvY<>=& diff --git a/src/resources/icons/type/Variable.png b/src/resources/icons/type/Variable.png index 599b70d5f8b382e0c2a78af7d9134e15bc035cdd..84cee5014553ee1fca9e607843d31a198bf75ff9 100644 GIT binary patch delta 10 RcmZo>xz0R6Wn;i*MgSE^1Iqva delta 52 zcmcc4+{`jTMN=W!BgmJ5A$JA?LvbGi!*3P_hUPU43{?{t7+x)7U@&~gz#y{c%y~DZ Ijf&eC0gCJo@&Et; diff --git a/src/resources/icons/type/Variable@2x.png b/src/resources/icons/type/Variable@2x.png index 64fcb223dea83db99e6a89e5e062ec8a8e7bd85d..4be45091e5fac78683c6f9a302e9e518e911f92c 100644 GIT binary patch delta 10 Rcmcb~vX*6n%EkarCIA))15W?| delta 52 zcmZ3>a+76(il#!cN02WAL+%U)hT=X3hELTD3@x`981kktFg%rFU@%r^V2~7_=_ymc IQIUrU0EDy+j{pDw diff --git a/src/resources/icons/type/Variant.png b/src/resources/icons/type/Variant.png index 7b358ed8721883b5be8a402ce218bcbe47762f2b..8a1498766507cf0ac1495ab25aa5b244506dca7e 100644 GIT binary patch delta 10 RcmX@XJcoIL%Eo{SMgSF~1DOB- delta 52 zcmbQke1ds`il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HRx<(sZSoE= diff --git a/src/resources/icons/type/Variant@2x.png b/src/resources/icons/type/Variant@2x.png index 9deba7f392f8b7a0265b6e5c8e1c8a989fea080a..fcabbdbf0bf8cad00a6955876270644ca2ec6fc6 100644 GIT binary patch delta 10 RcmX@eGL>b5%Eo|?i~trV1O@;A delta 52 zcmbQra*$<$il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HeqjUvY<>=& diff --git a/src/resources/icons/type/Web.png b/src/resources/icons/type/Web.png index d7a026469ec53e8a79848497d468335b7cfc865e..942b17c83abc94a16c3ba501afe2b174f181ecf0 100644 GIT binary patch delta 10 RcmdnM*}^$Nd82v`df5@il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HuHym#iMtN> diff --git a/src/resources/icons/type/Word.png b/src/resources/icons/type/Word.png index 91921bf768cb2253156c041caafd89db9dbff410..f8f1d9649022b89b72cc0157d60b2fa8d056d2a6 100644 GIT binary patch delta 10 RcmX@cJd1gP%Eo{)MgSFi1Csy% delta 52 zcmbQme2jU5il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b HRx$zrZ6XdU diff --git a/src/resources/icons/type/Word@2x.png b/src/resources/icons/type/Word@2x.png index 9beea600daf0f951a8588665e8779341e1d1cc41..30a7c25631d8cf4a71f5d4b47eafd2142d45c82b 100644 GIT binary patch delta 10 RcmZ3*`j2IT%Eo{wCIA;@1H%9S delta 52 zcmeyzvWj(ril#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&O-b H#xel_d{_=! diff --git a/src/resources/icons/type/_DashAnnotations.png b/src/resources/icons/type/_DashAnnotations.png index 95d375122a84df4e04328ae4591e36992b0e82a3..ce249000ad1aed76e36bef489952814e3117fa8b 100644 GIT binary patch delta 9 QcmX@fG?!_D%EW-501_<&`2YX_ delta 51 zcmbQsbdqU;il#!cN02WALzNl>LqiJ#!!HIP{epp^)PRBERRRNp)eHs(@q#(K0&ONL G{s91Aa+76(il#!cN02WALzOB6LqjtI!_WUf`XvKHsR0ASs{{rHs~HRo;`x)}kGgGC H Date: Mon, 21 Mar 2016 00:46:21 -0400 Subject: [PATCH 070/273] Use Qt WebEngine by default with Qt 5.6+ Qt 5.6 does not ship Qt WebKit module any longer. --- src/src.pro | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/src.pro b/src/src.pro index c4d95e0bf..0bdb943c7 100644 --- a/src/src.pro +++ b/src/src.pro @@ -3,12 +3,16 @@ TEMPLATE = app QT += gui widgets sql CONFIG += c++11 silent -# Build features -webengine { +## Build options +# Browser engine +lessThan(QT_VERSION, 5.6):!webengine { + message("Browser engine: Qt WebKit") + QT += webkitwidgets + DEFINES += USE_WEBKIT +} else { + message("Browser engine: Qt WebEngine") QT += webenginewidgets DEFINES += USE_WEBENGINE -} else { - QT += webkitwidgets } portable { From 23cbd3753513a67ec4cb9e5c198ed29706c795d9 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 23 Mar 2016 00:10:41 -0400 Subject: [PATCH 071/273] ui: Fix nonworking QKeySequence::PreviousChild (fixes #518) Workarounding QTBUG-15746 with an explicit shortcut. --- src/ui/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fa372602b..dff20f12f 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -332,7 +332,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_tabBar->setCurrentIndex((m_tabBar->currentIndex() + 1) % m_tabBar->count()); }); - ui->actionPreviousTab->setShortcut(QKeySequence::PreviousChild); + /// TODO: Use QKeySequence::PreviousChild, when QTBUG-15746 is fixed. + ui->actionPreviousTab->setShortcut(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Tab); addAction(ui->actionPreviousTab); connect(ui->actionPreviousTab, &QAction::triggered, [this]() { m_tabBar->setCurrentIndex((m_tabBar->currentIndex() - 1 + m_tabBar->count()) % m_tabBar->count()); From 5abf7920550f849102f1f382d23a85129c1726f7 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 23 Mar 2016 22:39:29 -0400 Subject: [PATCH 072/273] ui: Remove unsused forward declaration --- src/ui/settingsdialog.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 32d9b0fdf..0da3c50d0 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -30,7 +30,6 @@ #include #include -class QAbstractButton; class QListWidgetItem; class QNetworkReply; class QTemporaryFile; From 8d0b4e5b068ffff23784ef4bec60eaed4f9447ef Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 24 Mar 2016 05:29:35 -0400 Subject: [PATCH 073/273] doc: Update copyright year --- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp | 2 +- src/core/application.cpp | 2 +- src/core/application.h | 2 +- src/core/extractor.cpp | 2 +- src/core/extractor.h | 2 +- src/core/settings.cpp | 2 +- src/core/settings.h | 2 +- src/main.cpp | 2 +- src/registry/docset.cpp | 2 +- src/registry/docset.h | 2 +- src/registry/docsetmetadata.cpp | 2 +- src/registry/docsetmetadata.h | 2 +- src/registry/docsetregistry.cpp | 2 +- src/registry/docsetregistry.h | 2 +- src/registry/listmodel.cpp | 2 +- src/registry/listmodel.h | 2 +- src/registry/searchmodel.cpp | 2 +- src/registry/searchmodel.h | 2 +- src/registry/searchquery.cpp | 2 +- src/registry/searchquery.h | 2 +- src/registry/searchresult.cpp | 2 +- src/registry/searchresult.h | 2 +- src/ui/aboutdialog.cpp | 2 +- src/ui/aboutdialog.h | 2 +- src/ui/docsetlistitemdelegate.cpp | 2 +- src/ui/docsetlistitemdelegate.h | 2 +- src/ui/mainwindow.h | 2 +- src/ui/networkaccessmanager.cpp | 2 +- src/ui/networkaccessmanager.h | 2 +- src/ui/progressitemdelegate.cpp | 2 +- src/ui/progressitemdelegate.h | 2 +- src/ui/searchitemdelegate.cpp | 2 +- src/ui/searchitemdelegate.h | 2 +- src/ui/settingsdialog.cpp | 2 +- src/ui/settingsdialog.h | 2 +- src/ui/widgets/searchablewebview.cpp | 2 +- src/ui/widgets/searchablewebview.h | 2 +- src/ui/widgets/searchedit.cpp | 2 +- src/ui/widgets/searchedit.h | 2 +- src/ui/widgets/shortcutedit.cpp | 2 +- src/ui/widgets/shortcutedit.h | 2 +- src/ui/widgets/webview.cpp | 2 +- src/ui/widgets/webview.h | 2 +- src/util/plist.cpp | 2 +- src/util/plist.h | 2 +- src/util/version.cpp | 2 +- src/util/version.h | 2 +- 52 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp index 4d067b772..05208865f 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h index 60e9d1e0f..99bbfadc5 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp index a1d1b3619..c6021ca92 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h index 274d7b170..722fed46d 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp index eae080c86..6755ea76a 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp index 24649b3d3..56782f1ae 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/core/application.cpp b/src/core/application.cpp index d2592ecef..dbe6231d8 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/core/application.h b/src/core/application.h index e5fc11a1e..3335a8f2b 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/core/extractor.cpp b/src/core/extractor.cpp index 1f71b4e6e..cf13d5756 100644 --- a/src/core/extractor.cpp +++ b/src/core/extractor.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/core/extractor.h b/src/core/extractor.h index 605384ca0..a9db21c78 100644 --- a/src/core/extractor.h +++ b/src/core/extractor.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/core/settings.cpp b/src/core/settings.cpp index c1a16f981..46f89d8c9 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/core/settings.h b/src/core/settings.h index c09b87bdd..5cbc95c89 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/main.cpp b/src/main.cpp index 2bf3ac22b..b7a661356 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index bccc4d4df..24531ed87 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/docset.h b/src/registry/docset.h index 39b0ac909..67cf42adb 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/docsetmetadata.cpp b/src/registry/docsetmetadata.cpp index 5399f7678..d8de96f05 100644 --- a/src/registry/docsetmetadata.cpp +++ b/src/registry/docsetmetadata.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/docsetmetadata.h b/src/registry/docsetmetadata.h index 5dda9778c..b39e2b9ec 100644 --- a/src/registry/docsetmetadata.h +++ b/src/registry/docsetmetadata.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index f81c07761..62384cd26 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index 808d4c1be..4d3b35328 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/listmodel.cpp b/src/registry/listmodel.cpp index d13e3d4e8..2dbbe01db 100644 --- a/src/registry/listmodel.cpp +++ b/src/registry/listmodel.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/listmodel.h b/src/registry/listmodel.h index 6c66bf3e0..e6de0692a 100644 --- a/src/registry/listmodel.h +++ b/src/registry/listmodel.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index 48fa9b96d..04b23ef8c 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index 61e9e7a89..daf7052d0 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/searchquery.cpp b/src/registry/searchquery.cpp index 021379b46..b9be73f9a 100644 --- a/src/registry/searchquery.cpp +++ b/src/registry/searchquery.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/searchquery.h b/src/registry/searchquery.h index bbebb99f4..a31c6692a 100644 --- a/src/registry/searchquery.h +++ b/src/registry/searchquery.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/searchresult.cpp b/src/registry/searchresult.cpp index 3b7d26b7f..734391cd2 100644 --- a/src/registry/searchresult.cpp +++ b/src/registry/searchresult.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/registry/searchresult.h b/src/registry/searchresult.h index e879daf2f..bff87f878 100644 --- a/src/registry/searchresult.h +++ b/src/registry/searchresult.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index 61d656f5c..665a8eca4 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h index 1ee9ab0db..8dfdacbc2 100644 --- a/src/ui/aboutdialog.h +++ b/src/ui/aboutdialog.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/ui/docsetlistitemdelegate.cpp b/src/ui/docsetlistitemdelegate.cpp index aa32635e1..731be0412 100644 --- a/src/ui/docsetlistitemdelegate.cpp +++ b/src/ui/docsetlistitemdelegate.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/docsetlistitemdelegate.h b/src/ui/docsetlistitemdelegate.h index a310b776e..d29abe0bc 100644 --- a/src/ui/docsetlistitemdelegate.h +++ b/src/ui/docsetlistitemdelegate.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index a841bf70a..b7a0b2f60 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/networkaccessmanager.cpp b/src/ui/networkaccessmanager.cpp index ccecae664..dad5ef961 100644 --- a/src/ui/networkaccessmanager.cpp +++ b/src/ui/networkaccessmanager.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/networkaccessmanager.h b/src/ui/networkaccessmanager.h index ac7900bda..e66f6ee9f 100644 --- a/src/ui/networkaccessmanager.h +++ b/src/ui/networkaccessmanager.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/progressitemdelegate.cpp b/src/ui/progressitemdelegate.cpp index 3d0b880b2..6836f2a71 100644 --- a/src/ui/progressitemdelegate.cpp +++ b/src/ui/progressitemdelegate.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/progressitemdelegate.h b/src/ui/progressitemdelegate.h index bc458f9ea..f15bcfdef 100644 --- a/src/ui/progressitemdelegate.h +++ b/src/ui/progressitemdelegate.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 013ee4f1b..4162f6ed7 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index 1c96cc7ae..6f9adb4c8 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 0a6e2e3a3..c81173137 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 0da3c50d0..605867fc1 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/searchablewebview.cpp b/src/ui/widgets/searchablewebview.cpp index e58cb21e2..fbf2cbb12 100644 --- a/src/ui/widgets/searchablewebview.cpp +++ b/src/ui/widgets/searchablewebview.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/searchablewebview.h b/src/ui/widgets/searchablewebview.h index 6384e1ce9..00a46b162 100644 --- a/src/ui/widgets/searchablewebview.h +++ b/src/ui/widgets/searchablewebview.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/searchedit.cpp b/src/ui/widgets/searchedit.cpp index 632096818..29227899e 100644 --- a/src/ui/widgets/searchedit.cpp +++ b/src/ui/widgets/searchedit.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/searchedit.h b/src/ui/widgets/searchedit.h index a2c19a7f2..fed84ebef 100644 --- a/src/ui/widgets/searchedit.h +++ b/src/ui/widgets/searchedit.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/shortcutedit.cpp b/src/ui/widgets/shortcutedit.cpp index 8dcc60ccf..698ce2695 100644 --- a/src/ui/widgets/shortcutedit.cpp +++ b/src/ui/widgets/shortcutedit.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/shortcutedit.h b/src/ui/widgets/shortcutedit.h index 7a8dceb21..41247bf6d 100644 --- a/src/ui/widgets/shortcutedit.h +++ b/src/ui/widgets/shortcutedit.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/webview.cpp b/src/ui/widgets/webview.cpp index 47564ef99..f88a68d48 100644 --- a/src/ui/widgets/webview.cpp +++ b/src/ui/widgets/webview.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/ui/widgets/webview.h b/src/ui/widgets/webview.h index 508de3966..af6ad63fa 100644 --- a/src/ui/widgets/webview.h +++ b/src/ui/widgets/webview.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** diff --git a/src/util/plist.cpp b/src/util/plist.cpp index c4aa408a6..dbf923d13 100644 --- a/src/util/plist.cpp +++ b/src/util/plist.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/util/plist.h b/src/util/plist.h index ebeb24fe3..ebfd7e733 100644 --- a/src/util/plist.h +++ b/src/util/plist.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/util/version.cpp b/src/util/version.cpp index 207e9e3d9..d2daa0ecc 100644 --- a/src/util/version.cpp +++ b/src/util/version.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. diff --git a/src/util/version.h b/src/util/version.h index cc74760f0..90373c9eb 100644 --- a/src/util/version.h +++ b/src/util/version.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Contact: http://zealdocs.org/contact.html ** ** This file is part of Zeal. From 23aac1aeb4f764e2d57d3375422b2d911c2ff101 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 24 Mar 2016 05:34:45 -0400 Subject: [PATCH 074/273] ui: Allow accessing online resources in web view (fixes #474) This removes a custom network manager that was blocking all requests to non-local resources. --- src/ui/mainwindow.cpp | 11 ++---- src/ui/mainwindow.h | 2 - src/ui/networkaccessmanager.cpp | 70 --------------------------------- src/ui/networkaccessmanager.h | 43 -------------------- 4 files changed, 4 insertions(+), 122 deletions(-) delete mode 100644 src/ui/networkaccessmanager.cpp delete mode 100644 src/ui/networkaccessmanager.h diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index dff20f12f..7454fb35b 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -25,7 +25,6 @@ #include "ui_mainwindow.h" #include "aboutdialog.h" -#include "networkaccessmanager.h" #include "searchitemdelegate.h" #include "settingsdialog.h" #include "core/application.h" @@ -108,11 +107,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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); + /// TODO: Custom headers and URL scheme for Qt WebEngine. +#ifndef USE_WEBENGINE + ui->webView->page()->setNetworkAccessManager(m_application->networkManager()); #endif // menu @@ -462,7 +459,7 @@ void MainWindow::createTab() newTab->page->load(QUrl(startPageUrl)); #else newTab->page->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); - newTab->page->setNetworkAccessManager(m_zealNetworkManager); + newTab->page->setNetworkAccessManager(m_application->networkManager()); newTab->page->mainFrame()->load(QUrl(startPageUrl)); #endif diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index b7a0b2f60..5fc43f1e3 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -61,7 +61,6 @@ class Settings; } class ListModel; -class NetworkAccessManager; class SearchModel; class SettingsDialog; @@ -143,7 +142,6 @@ private slots: QList m_tabs; SearchState *m_searchState = nullptr; - Zeal::NetworkAccessManager *m_zealNetworkManager = nullptr; Ui::MainWindow *ui = nullptr; Zeal::Core::Application *m_application = nullptr; diff --git a/src/ui/networkaccessmanager.cpp b/src/ui/networkaccessmanager.cpp deleted file mode 100644 index dad5ef961..000000000 --- a/src/ui/networkaccessmanager.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015-2016 Oleg Shparber -** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html -** -** This file is part of Zeal. -** -** Zeal 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. -** -** Zeal 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 Zeal. If not, see . -** -****************************************************************************/ - -#include "networkaccessmanager.h" - -#include - -using namespace Zeal; - -NetworkAccessManager::NetworkAccessManager(QObject *parent) : - QNetworkAccessManager(parent) -{ -} - -QNetworkReply *NetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, - const QNetworkRequest &req, - QIODevice *outgoingData) -{ - const QString scheme = req.url().scheme(); - - if (scheme == QLatin1String("qrc")) - return QNetworkAccessManager::createRequest(op, req, outgoingData); - - const bool nonFileScheme = scheme != QLatin1String("file"); - const bool nonLocalFile = !nonFileScheme && !req.url().host().isEmpty(); - - // Ignore requests which cause Zeal to hang - if (nonLocalFile || nonFileScheme) { - return QNetworkAccessManager::createRequest(QNetworkAccessManager::GetOperation, - QNetworkRequest()); - } -#ifdef Q_OS_WIN32 - // Fix for AngularJS docset - Windows doesn't allow ':'s in filenames, - // and bsdtar.exe replaces them with '_'s, so replace all ':'s in requests - // with '_'s. - QNetworkRequest winReq(req); - QUrl winUrl(req.url()); - QString winPath = winUrl.path(); - // absolute paths are of form /C:/..., so don't replace colons occuring - // within first 3 characters - while (winPath.lastIndexOf(':') > 2) - winPath = winPath.replace(winPath.lastIndexOf(':'), 1, "_"); - - winUrl.setPath(winPath); - winReq.setUrl(winUrl); - return QNetworkAccessManager::createRequest(op, winReq, outgoingData); -#else - return QNetworkAccessManager::createRequest(op, req, outgoingData); -#endif -} diff --git a/src/ui/networkaccessmanager.h b/src/ui/networkaccessmanager.h deleted file mode 100644 index e66f6ee9f..000000000 --- a/src/ui/networkaccessmanager.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015-2016 Oleg Shparber -** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html -** -** This file is part of Zeal. -** -** Zeal 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. -** -** Zeal 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 Zeal. If not, see . -** -****************************************************************************/ - -#ifndef NETWORKACCESSMANAGER_H -#define NETWORKACCESSMANAGER_H - -#include - -namespace Zeal { - -class NetworkAccessManager : public QNetworkAccessManager -{ - Q_OBJECT -public: - explicit NetworkAccessManager(QObject *parent = nullptr); - - QNetworkReply *createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, - QIODevice *outgoingData = nullptr) override; -}; - -} // namespace Zeal - -#endif // NETWORKACCESSMANAGER_H From 3ff3cf5923816dae4b3a5de615d7bd855224560d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 24 Mar 2016 05:36:15 -0400 Subject: [PATCH 075/273] 3rdparty: Minor refactoring in QxtGlobalShortcut --- .../qxtglobalshortcut/qxtglobalshortcut.cpp | 17 +++++++++-------- .../qxtglobalshortcut/qxtglobalshortcut.h | 9 ++++----- .../qxtglobalshortcut/qxtglobalshortcut_p.h | 15 ++++++++------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp index 05208865f..7351e0ee4 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp @@ -62,10 +62,7 @@ int QxtGlobalShortcutPrivate::ref = 0; QHash, QxtGlobalShortcut *> QxtGlobalShortcutPrivate::shortcuts; QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate(QxtGlobalShortcut *qq) : - q_ptr(qq), - enabled(true), - key(Qt::Key(0)), - mods(Qt::NoModifier) + q_ptr(qq) { #ifndef Q_OS_OSX if (ref == 0) @@ -96,24 +93,28 @@ bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence &shortcut) const quint32 nativeMods = nativeModifiers(mods); const bool res = registerShortcut(nativeKey, nativeMods); if (res) - shortcuts.insert(qMakePair(nativeKey, nativeMods), q); + shortcuts.insert({nativeKey, nativeMods}, q); else qWarning("QxtGlobalShortcut failed to register: %s", qPrintable(QKeySequence(key + mods).toString())); + return res; } bool QxtGlobalShortcutPrivate::unsetShortcut() { Q_Q(QxtGlobalShortcut); + bool res = false; const quint32 nativeKey = nativeKeycode(key); const quint32 nativeMods = nativeModifiers(mods); - if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == q) + if (shortcuts.value({nativeKey, nativeMods}) == q) res = unregisterShortcut(nativeKey, nativeMods); + if (res) - shortcuts.remove(qMakePair(nativeKey, nativeMods)); + shortcuts.remove({nativeKey, nativeMods}); else qWarning("QxtGlobalShortcut failed to unregister: %s", qPrintable(QKeySequence(key + mods).toString())); + key = Qt::Key(0); mods = Qt::KeyboardModifiers(0); return res; @@ -121,7 +122,7 @@ bool QxtGlobalShortcutPrivate::unsetShortcut() bool QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) { - QxtGlobalShortcut *shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods)); + QxtGlobalShortcut *shortcut = shortcuts.value({nativeKey, nativeMods}); if (!shortcut || !shortcut->isEnabled()) return false; diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h index 99bbfadc5..2e2d46b91 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h @@ -62,12 +62,11 @@ class QxtGlobalShortcut : public QObject { Q_OBJECT - QxtGlobalShortcutPrivate *d_ptr; + QxtGlobalShortcutPrivate *d_ptr = nullptr; Q_DECLARE_PRIVATE(QxtGlobalShortcut) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) - public: explicit QxtGlobalShortcut(QObject *parent = nullptr); explicit QxtGlobalShortcut(const QKeySequence &shortcut, QObject *parent = nullptr); @@ -78,10 +77,10 @@ class QxtGlobalShortcut : public QObject bool isEnabled() const; -public Q_SLOTS: - void setEnabled(bool enabled = true); +public slots: + void setEnabled(bool enabled); -Q_SIGNALS: +signals: void activated(); }; diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h index 722fed46d..de00a0d1e 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h @@ -62,22 +62,23 @@ class QxtGlobalShortcut; class QxtGlobalShortcutPrivate : public QAbstractNativeEventFilter { - QxtGlobalShortcut *q_ptr; + QxtGlobalShortcut *q_ptr = nullptr; Q_DECLARE_PUBLIC(QxtGlobalShortcut) public: QxtGlobalShortcutPrivate(QxtGlobalShortcut *qq); ~QxtGlobalShortcutPrivate() override; - bool enabled; - Qt::Key key; - Qt::KeyboardModifiers mods; - - bool setShortcut(const QKeySequence &shortcut); - bool unsetShortcut(); + bool enabled = true; + Qt::Key key = Qt::Key(0); + Qt::KeyboardModifiers mods = Qt::NoModifier; #ifndef Q_OS_OSX static int ref; #endif // Q_OS_OSX + + bool setShortcut(const QKeySequence &shortcut); + bool unsetShortcut(); + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; From fcbf2ff078edfa8f4e442e38379359e50eaff4ae Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 24 Mar 2016 05:36:37 -0400 Subject: [PATCH 076/273] ui: Fix coding style in SettingsDialog --- src/ui/settingsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index c81173137..dbc6ce695 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -400,7 +400,7 @@ void SettingsDialog::downloadProgress(qint64 received, qint64 total) if (!reply || !reply->isOpen()) return; - if (reply->property(DownloadTypeProperty).toInt() == DownloadDocset) { + if (reply->property(DownloadTypeProperty).toInt() == DownloadDocset) { const QString docsetName = reply->property(DocsetNameProperty).toString(); QTemporaryFile *tmpFile = m_tmpFiles[docsetName]; From 4f87b7236c4744761d9dee5e8aaeb24e51e0348b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 24 Mar 2016 06:39:50 -0400 Subject: [PATCH 077/273] qmake: Print info whether building is portable mode --- src/src.pro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/src.pro b/src/src.pro index 0bdb943c7..0cbb220d5 100644 --- a/src/src.pro +++ b/src/src.pro @@ -16,7 +16,10 @@ lessThan(QT_VERSION, 5.6):!webengine { } portable { + message("Portable build: Yes") DEFINES += PORTABLE_BUILD +} else { + message("Portable build: No") } VERSION = 0.2.1 From 932644bebc388f5061c8a3203e18f2417bb6a585 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 26 Mar 2016 20:08:27 -0400 Subject: [PATCH 078/273] ui: Fix tool tips in the contents tree view --- src/ui/searchitemdelegate.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 4162f6ed7..e661bd866 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -47,9 +47,7 @@ void SearchItemDelegate::setDecorationRoles(const QList &roles) bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { - /// FIXME: It should be view->visualRect(index).width() instead of viewport()->width() - /// Doesn't work for shot items in the TOC, bug? - if (sizeHint(option, index).width() < view->viewport()->width()) { + if (sizeHint(option, index).width() < view->visualRect(index).width()) { QToolTip::hideText(); return QStyledItemDelegate::helpEvent(event, view, option, index); } From 800648e38ec6760f3f31232d46ef37515e9174ca Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 26 Mar 2016 20:09:18 -0400 Subject: [PATCH 079/273] ui: Clarify SearchItemDelegate::helpEvent() logic --- src/ui/searchitemdelegate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index e661bd866..994ee9985 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -47,6 +47,9 @@ void SearchItemDelegate::setDecorationRoles(const QList &roles) bool SearchItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { + if (event->type() != QEvent::ToolTip) + return QStyledItemDelegate::helpEvent(event, view, option, index); + if (sizeHint(option, index).width() < view->visualRect(index).width()) { QToolTip::hideText(); return QStyledItemDelegate::helpEvent(event, view, option, index); From ed7ce6088cc6769531147b454b9afca955fdceed Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 26 Mar 2016 20:13:58 -0400 Subject: [PATCH 080/273] ui: Cleanup DocsetListItemDelegate --- src/ui/docsetlistitemdelegate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ui/docsetlistitemdelegate.cpp b/src/ui/docsetlistitemdelegate.cpp index 731be0412..d70bce1df 100644 --- a/src/ui/docsetlistitemdelegate.cpp +++ b/src/ui/docsetlistitemdelegate.cpp @@ -46,10 +46,9 @@ void DocsetListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem font.setItalic(true); const QFontMetrics fontMetrics(font); - const int textWidth = fontMetrics.width(text) + 2; QRect textRect = option.rect; - textRect.setLeft(textRect.right() - textWidth); + textRect.setLeft(textRect.right() - fontMetrics.width(text) - 2); painter->save(); From 3b3dc2db18f27bb3813ac02bf1dcbaae1928a44c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 26 Mar 2016 20:21:07 -0400 Subject: [PATCH 081/273] registry: Remove pointless QLatin1String --- src/registry/listmodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registry/listmodel.cpp b/src/registry/listmodel.cpp index 2dbbe01db..cdf4c59c0 100644 --- a/src/registry/listmodel.cpp +++ b/src/registry/listmodel.cpp @@ -79,8 +79,8 @@ QVariant ListModel::data(const QModelIndex &index, int role) const case Level::GroupLevel: { DocsetItem *docsetItem = reinterpret_cast(index.internalPointer()); const QString symbolType = docsetItem->groups.at(index.row())->symbolType; - return QString(QLatin1String("%1 (%2)")).arg(pluralize(symbolType), - QString::number(docsetItem->docset->symbolCount(symbolType))); + return QStringLiteral("%1 (%2)").arg(pluralize(symbolType), + QString::number(docsetItem->docset->symbolCount(symbolType))); } case Level::SymbolLevel: { GroupItem *groupItem = reinterpret_cast(index.internalPointer()); From a2df7f33b4db9047f0a43c8c022f3ec64f432f3d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 26 Mar 2016 20:36:50 -0400 Subject: [PATCH 082/273] ui: Ignore wheel events in the tab bar This fixes annoying behaviour with touchpads. Reference: QTBUG-8428. --- src/ui/mainwindow.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 7454fb35b..1ed999ff0 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -826,14 +826,24 @@ void MainWindow::closeEvent(QCloseEvent *event) bool MainWindow::eventFilter(QObject *object, QEvent *event) { - if (object == m_tabBar && event->type() == QEvent::MouseButtonRelease) { - QMouseEvent *e = reinterpret_cast(event); - if (e->button() == Qt::MiddleButton) { - const int index = m_tabBar->tabAt(e->pos()); - if (index >= 0) { - closeTab(index); - return true; + if (object == m_tabBar) { + switch (event->type()) { + case QEvent::MouseButtonRelease: { + QMouseEvent *e = reinterpret_cast(event); + if (e->button() == Qt::MiddleButton) { + const int index = m_tabBar->tabAt(e->pos()); + if (index != -1) { + closeTab(index); + return true; + } } + break; + } + case QEvent::Wheel: + /// TODO: Remove in case QTBUG-8428 is fixed on all platforms + return true; + default: + break; } } From 7cd72764eb78eb89eed985562941cf7eda3d5238 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 26 Mar 2016 20:50:17 -0400 Subject: [PATCH 083/273] 3rdparty: Fix segfault in QxtGlobalShortcut (#500) --- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp index 56782f1ae..15574f44f 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp @@ -126,7 +126,9 @@ quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) QScopedPointer keycodes( xcb_key_symbols_get_keycode(xcbKeySymbols, keysym)); - native = keycodes.data()[0]; // Use the first keycode + + if (!keycodes.isNull()) + native = keycodes.data()[0]; // Use the first keycode xcb_key_symbols_free(xcbKeySymbols); From 5fe6480bd70d638462e4a0d7833392bb33d14e57 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 27 Mar 2016 10:37:48 -0400 Subject: [PATCH 084/273] core: Fix character corruption in docset extraction (fixes #508) The problem is caused by lack of UTF-8 support in libarchive, and affects non-Latin Windows (e.g. Chinese). This change is rather a workaround, than a fix. --- src/core/extractor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/extractor.cpp b/src/core/extractor.cpp index cf13d5756..d7ba769e5 100644 --- a/src/core/extractor.cpp +++ b/src/core/extractor.cpp @@ -63,7 +63,12 @@ void Extractor::extract(const QString &filePath, const QString &destination, con /// TODO: Do not strip root directory in archive if it equals to 'root' archive_entry *entry; while (archive_read_next_header(info.archiveHandle, &entry) == ARCHIVE_OK) { +#ifndef Q_OS_WIN32 QString pathname = QString::fromUtf8(archive_entry_pathname(entry)); +#else + /// TODO: Remove once https://github.com/libarchive/libarchive/issues/587 is resolved. + QString pathname = QString::fromWCharArray(archive_entry_pathname_w(entry)); +#endif if (!root.isEmpty()) pathname.remove(0, pathname.indexOf(QLatin1String("/")) + 1); archive_entry_set_pathname(entry, qPrintable(destinationDir.absoluteFilePath(pathname))); From b110955c482e7e09578099ce3c93f9a1ff3c2e92 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 27 Mar 2016 18:21:56 -0400 Subject: [PATCH 085/273] ui: Update About dialog (#495) --- src/ui/forms/aboutdialog.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/forms/aboutdialog.ui b/src/ui/forms/aboutdialog.ui index 3b01eeb1f..46061a807 100644 --- a/src/ui/forms/aboutdialog.ui +++ b/src/ui/forms/aboutdialog.ui @@ -75,13 +75,13 @@ <strong>A simple offline documentation browser</strong> <br><br> -Copyright &copy; Zeal Developers, 2013-2015. +Copyright &copy; Oleg Shparber and other conributors, 2013-2016. <br> <a href="https://zealdocs.org">zealdocs.org</a> <br> -<a href="irc://irc.freenode.net/zealdocs">#zealdocs</a> on <a href="http://www.freenode.net">Freenode</a> +<a href="irc://irc.freenode.net/zealdocs">#zealdocs</a> on <a href="https://www.freenode.net">Freenode</a> <br><br> -Zeal is an open source software available under the terms of General Public License version 3 (<a href="http://www.gnu.org/copyleft/gpl.html">GPLv3</a>). +Zeal is an open source software available under the terms of General Public License version 3 (<a href="https://www.gnu.org/copyleft/gpl.html">GPLv3</a>). <br><br> Docsets are courtesy of <a href="https://kapeli.com/dash">Dash</a>. From d3bd271ba1704bb0783d19f1460581f7cc288a51 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 27 Mar 2016 18:29:47 -0400 Subject: [PATCH 086/273] ui: Fix up/down navigation when search text edit is focused --- src/ui/widgets/searchedit.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/ui/widgets/searchedit.cpp b/src/ui/widgets/searchedit.cpp index 29227899e..86243afdd 100644 --- a/src/ui/widgets/searchedit.cpp +++ b/src/ui/widgets/searchedit.cpp @@ -26,6 +26,7 @@ #include "registry/searchquery.h" #include +#include #include #include #include @@ -110,16 +111,9 @@ void SearchEdit::keyPressEvent(QKeyEvent *event) event->accept(); break; case Qt::Key_Down: - case Qt::Key_Up: { - const QModelIndex index = m_treeView->currentIndex(); - const int nextRow = index.row() + (event->key() == Qt::Key_Down ? 1 : -1); - if (nextRow >= 0 && nextRow < m_treeView->model()->rowCount()) { - const QModelIndex sibling = index.sibling(nextRow, 0); - m_treeView->setCurrentIndex(sibling); - } - event->accept(); + case Qt::Key_Up: + QCoreApplication::sendEvent(m_treeView, event); break; - } default: QLineEdit::keyPressEvent(event); break; From 1200f0da4a1265d4a17ea798fe2edaf75ad38101 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 27 Mar 2016 18:32:04 -0400 Subject: [PATCH 087/273] ui: Add support for Page Up/Down when search text edit is focused --- src/ui/widgets/searchedit.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ui/widgets/searchedit.cpp b/src/ui/widgets/searchedit.cpp index 86243afdd..3dbda4383 100644 --- a/src/ui/widgets/searchedit.cpp +++ b/src/ui/widgets/searchedit.cpp @@ -107,11 +107,10 @@ void SearchEdit::keyPressEvent(QKeyEvent *event) event->accept(); break; case Qt::Key_Return: - emit m_treeView->activated(m_treeView->selectionModel()->currentIndex()); - event->accept(); - break; case Qt::Key_Down: case Qt::Key_Up: + case Qt::Key_PageDown: + case Qt::Key_PageUp: QCoreApplication::sendEvent(m_treeView, event); break; default: From 1b4b360af198f7eaf585f804920efb96a278e222 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 28 Mar 2016 00:12:14 -0400 Subject: [PATCH 088/273] ui: Remove 'See also' label --- src/ui/forms/mainwindow.ui | 18 ------------------ src/ui/mainwindow.cpp | 1 - 2 files changed, 19 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index e6a4826df..786a4934a 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -110,24 +110,6 @@ 0 - - - - - 9 - - - - * { padding: 0 2px; } - - - See also - - - 2 - - - diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 1ed999ff0..f98c343ff 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -491,7 +491,6 @@ void MainWindow::displaySections() const bool hasResults = currentSearchState()->sectionsList->rowCount(); ui->sections->setVisible(hasResults); - ui->seeAlsoLabel->setVisible(hasResults); QList sizes = hasResults ? m_settings->sectionsSplitterSizes : QList({1, 0}); From 732ff9dc85ff5c96bf27fbb756da8fbf1913223b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 28 Mar 2016 00:12:51 -0400 Subject: [PATCH 089/273] Better indication if AppIndicator support is enabled --- src/ui/ui.pri | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/ui.pri b/src/ui/ui.pri index e839d71be..d6f23ac33 100644 --- a/src/ui/ui.pri +++ b/src/ui/ui.pri @@ -14,6 +14,8 @@ unix:!macx { CONFIG += link_pkgconfig PKGCONFIG += appindicator-0.1 gtk+-2.0 DEFINES += USE_APPINDICATOR - message("AppIndicator support enabled") + message("AppIndicator support: Yes") + } else { + message("AppIndicator support: No") } } From b26d655a7ab2c1ba4fc6212b8a1e019e98e1398b Mon Sep 17 00:00:00 2001 From: Sian Cao Date: Thu, 31 Mar 2016 10:52:22 +0800 Subject: [PATCH 090/273] ui: Prevent QWebEnginePage from stealing focus from the search input --- src/ui/mainwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index f98c343ff..0d3acd898 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -407,6 +407,9 @@ void MainWindow::queryCompleted() m_treeViewClicked = true; ui->treeView->setCurrentIndex(m_searchState->zealSearch->index(0, 0, QModelIndex())); ui->treeView->activated(ui->treeView->currentIndex()); +#if USE_WEBENGINE + ui->lineEdit->setFocus(Qt::MouseFocusReason); +#endif } void MainWindow::goToTab(int index) From 90bd8f9a669d817a17bd8daaf7147c369a6f0489 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 31 Mar 2016 09:05:09 -0400 Subject: [PATCH 091/273] ui: Add a comment for the QWebPageEngine focus fix --- src/ui/mainwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 0d3acd898..9b74f10fd 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -407,7 +407,9 @@ void MainWindow::queryCompleted() m_treeViewClicked = true; ui->treeView->setCurrentIndex(m_searchState->zealSearch->index(0, 0, QModelIndex())); ui->treeView->activated(ui->treeView->currentIndex()); -#if USE_WEBENGINE + +#ifdef USE_WEBENGINE + // Prevent QWebPageEngine::load() from stealing focus ui->lineEdit->setFocus(Qt::MouseFocusReason); #endif } From f3b2f164b2c6e24fbe16da9fcb02177892227ccd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 31 Mar 2016 19:12:49 -0400 Subject: [PATCH 092/273] ui: Small cleanup in MainWindow --- src/ui/mainwindow.cpp | 36 +++++++++--------------------------- src/ui/mainwindow.h | 3 --- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 9b74f10fd..ff63e0dd0 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -133,8 +133,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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); + connect(ui->actionBack, &QAction::triggered, ui->webView, &SearchableWebView::back); + connect(ui->actionForward, &QAction::triggered, ui->webView, &SearchableWebView::forward); // Help Menu connect(ui->actionSubmitFeedback, &QAction::triggered, [this]() { @@ -204,8 +204,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : }); 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->forwardButton, &QPushButton::clicked, ui->webView, &SearchableWebView::forward); + connect(ui->backButton, &QPushButton::clicked, ui->webView, &SearchableWebView::back); connect(ui->webView, &SearchableWebView::urlChanged, [this](const QUrl &url) { const QString name = docsetName(url); @@ -229,8 +229,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QDesktopServices::openUrl(url); }); - connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, - this, &MainWindow::onSearchComplete); + connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, [this]() { + m_searchState->zealSearch->setResults(m_application->docsetRegistry()->queryResults()); + }); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, this, [this](const QString &name) { @@ -394,10 +395,8 @@ QString MainWindow::docsetName(const QUrl &url) const QIcon MainWindow::docsetIcon(const QString &docsetName) const { - const Docset * const docset = m_application->docsetRegistry()->docset(docsetName); - if (!docset) - return QIcon(QStringLiteral(":/icons/logo/icon.png")); - return docset->icon(); + Docset *docset = m_application->docsetRegistry()->docset(docsetName); + return docset ? docset->icon() : QIcon(QStringLiteral(":/icons/logo/icon.png")); } void MainWindow::queryCompleted() @@ -608,11 +607,6 @@ void MainWindow::saveTabState() m_searchState->zoomFactor = ui->webView->zoomFactor(); } -void MainWindow::onSearchComplete() -{ - m_searchState->zealSearch->setResults(m_application->docsetRegistry()->queryResults()); -} - // Sets up the search box autocompletions. void MainWindow::setupSearchBoxCompletions() { @@ -653,18 +647,6 @@ void MainWindow::displayViewActions() displayTabs(); } -void MainWindow::back() -{ - ui->webView->back(); - displayViewActions(); -} - -void MainWindow::forward() -{ - ui->webView->forward(); - displayViewActions(); -} - QAction *MainWindow::addHistoryAction(QWebHistory *history, const QWebHistoryItem &item) { const QIcon icon = docsetIcon(docsetName(item.url())); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 5fc43f1e3..7348ffefe 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -110,9 +110,6 @@ public slots: private slots: void applySettings(); - void back(); - void forward(); - void onSearchComplete(); void openDocset(const QModelIndex &index); void queryCompleted(); void scrollSearch(); From a4c17e159dd93fc0086b20e395f46a4f36b76cd9 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 31 Mar 2016 19:13:41 -0400 Subject: [PATCH 093/273] ui: Add theme icons and tooltips for back and forward buttons --- src/ui/forms/mainwindow.ui | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 786a4934a..c92032887 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -154,16 +154,28 @@ + + Go back one page + + + + + + Go forward one page + + + + From b1d419d5a942b1a287c87581e7d285331a61d363 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 4 Apr 2016 00:27:12 -0400 Subject: [PATCH 094/273] ui: Cleanup web view focusing logic --- src/ui/mainwindow.cpp | 25 ++++++++----------------- src/ui/mainwindow.h | 2 -- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ff63e0dd0..38dd44cb6 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -194,14 +194,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : /// 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::clicked, this, &MainWindow::openDocset); + connect(ui->sections, &QListView::clicked, this, &MainWindow::openDocset); connect(ui->treeView, &QTreeView::activated, this, &MainWindow::openDocset); connect(ui->sections, &QListView::activated, this, &MainWindow::openDocset); connect(ui->forwardButton, &QPushButton::clicked, ui->webView, &SearchableWebView::forward); @@ -381,10 +375,10 @@ void MainWindow::openDocset(const QModelIndex &index) ui->webView->load(url); - if (!m_treeViewClicked) - ui->webView->focus(); - else - m_treeViewClicked = false; + // QWebEnginePage::load() always steals focus, so no need to do it twice. +#ifndef USE_WEBENGINE + ui->webView->focus(); +#endif } QString MainWindow::docsetName(const QUrl &url) const @@ -403,14 +397,11 @@ void MainWindow::queryCompleted() { displayTreeView(); - m_treeViewClicked = true; ui->treeView->setCurrentIndex(m_searchState->zealSearch->index(0, 0, QModelIndex())); - ui->treeView->activated(ui->treeView->currentIndex()); + openDocset(ui->treeView->currentIndex()); -#ifdef USE_WEBENGINE - // Prevent QWebPageEngine::load() from stealing focus + // Get focus back. QWebPageEngine::load() always steals focus. ui->lineEdit->setFocus(Qt::MouseFocusReason); -#endif } void MainWindow::goToTab(int index) diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 7348ffefe..be69771d2 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -149,8 +149,6 @@ private slots: QMenu *m_backMenu = nullptr; QMenu *m_forwardMenu = nullptr; - bool m_treeViewClicked = false; - QxtGlobalShortcut *m_globalShortcut = nullptr; QTabBar *m_tabBar = nullptr; From 9b9979fcabb7e922706983c5b2cfa2ddb82d6346 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 00:10:47 -0400 Subject: [PATCH 095/273] qmake: Improve browser engine selection New CONFIG options: zeal_qtwebengine and zeal_qtwebkit. --- src/src.pro | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/src.pro b/src/src.pro index 0cbb220d5..50e9666a8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -5,14 +5,26 @@ CONFIG += c++11 silent ## Build options # Browser engine -lessThan(QT_VERSION, 5.6):!webengine { - message("Browser engine: Qt WebKit") - QT += webkitwidgets - DEFINES += USE_WEBKIT +CONFIG(zeal_qtwebkit) { + qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit + else: error("Qt WebKit is not available.") +} else:CONFIG(zeal_qtwebengine) { + qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine + else: error("Qt WebEngine is not available.") } else { - message("Browser engine: Qt WebEngine") + qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine + else: qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit + else: error("Zeal requires Qt WebEngine or Qt WebKit.") +} + +equals(BROWSER_ENGINE, qtwebengine) { + message("Browser engine: Qt WebEngine.") QT += webenginewidgets DEFINES += USE_WEBENGINE +} else { + message("Browser engine: Qt WebKit.") + QT += webkitwidgets + DEFINES += USE_WEBKIT } portable { From 9787b420fe3aacefe68d7d25ea48151b5040935c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 00:12:20 -0400 Subject: [PATCH 096/273] qmake: Use CONFIG+=zeal_portable for portable builds --- src/src.pro | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/src.pro b/src/src.pro index 50e9666a8..767f6c162 100644 --- a/src/src.pro +++ b/src/src.pro @@ -27,11 +27,12 @@ equals(BROWSER_ENGINE, qtwebengine) { DEFINES += USE_WEBKIT } -portable { - message("Portable build: Yes") +# Portable build +CONFIG(zeal_portable) { + message("Portable build: Yes.") DEFINES += PORTABLE_BUILD } else { - message("Portable build: No") + message("Portable build: No.") } VERSION = 0.2.1 From 5452bc4b1451e4ad9bd7a88dcd87f820d18bac96 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 00:25:24 -0400 Subject: [PATCH 097/273] registry: Cleanup DocsetMetadata header --- src/registry/docsetmetadata.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/registry/docsetmetadata.h b/src/registry/docsetmetadata.h index b39e2b9ec..932319b41 100644 --- a/src/registry/docsetmetadata.h +++ b/src/registry/docsetmetadata.h @@ -24,17 +24,13 @@ #ifndef DOCSETMETADATA_H #define DOCSETMETADATA_H -#include #include +#include #include #include -class QJsonObject; - namespace Zeal { -/// TODO: Use QUrl - class DocsetMetadata { public: From 6676d916cb0f00769a9cd227ff263c79257988dd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 00:54:51 -0400 Subject: [PATCH 098/273] registry: Do not store search results in DocsetRegistry --- src/registry/docsetregistry.cpp | 16 +++++++--------- src/registry/docsetregistry.h | 4 +--- src/ui/mainwindow.cpp | 5 +++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index 62384cd26..d4d38cfdc 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -35,6 +35,9 @@ DocsetRegistry::DocsetRegistry(QObject *parent) : QObject(parent), m_thread(new QThread(this)) { + // Register for use in signal connections. + qRegisterMetaType>("QList"); + /// FIXME: Only search should be performed in a separate thread moveToThread(m_thread); m_thread->start(); @@ -131,19 +134,14 @@ void DocsetRegistry::search(const QString &query) void DocsetRegistry::_runQuery(const QString &query) { - m_queryResults.clear(); + QList results; for (Docset *docset : docsets()) - m_queryResults << docset->search(query); - - std::sort(m_queryResults.begin(), m_queryResults.end()); + results << docset->search(query); - emit queryCompleted(); -} + std::sort(results.begin(), results.end()); -const QList &DocsetRegistry::queryResults() -{ - return m_queryResults; + emit queryCompleted(results); } // Recursively finds and adds all docsets in a given directory. diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index 4d3b35328..07f59eab4 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -52,7 +52,6 @@ class DocsetRegistry : public QObject QList docsets() const; void search(const QString &query); - const QList &queryResults(); public slots: void addDocset(const QString &path); @@ -61,7 +60,7 @@ public slots: void docsetAdded(const QString &name); void docsetAboutToBeRemoved(const QString &name); void docsetRemoved(const QString &name); - void queryCompleted(); + void queryCompleted(const QList &results); private slots: void _addDocset(const QString &path); @@ -72,7 +71,6 @@ private slots: QThread *m_thread = nullptr; QMap m_docsets; - QList m_queryResults; }; } // namespace Zeal diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 38dd44cb6..e653be428 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -223,8 +223,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QDesktopServices::openUrl(url); }); - connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, [this]() { - m_searchState->zealSearch->setResults(m_application->docsetRegistry()->queryResults()); + connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, + this, [this](const QList &results) { + m_searchState->zealSearch->setResults(results); }); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, From 055757f5bff0f7a6327d2e3884637077c0f510bd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 00:55:45 -0400 Subject: [PATCH 099/273] registry: Improve forward declarations --- src/registry/docset.cpp | 1 + src/registry/docset.h | 4 ++-- src/registry/docsetregistry.cpp | 1 - src/registry/docsetregistry.h | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 24531ed87..df920b37c 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -24,6 +24,7 @@ #include "docset.h" #include "searchquery.h" +#include "searchresult.h" #include "util/plist.h" #include diff --git a/src/registry/docset.h b/src/registry/docset.h index 67cf42adb..66e311d5f 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -24,8 +24,6 @@ #ifndef DOCSET_H #define DOCSET_H -#include "searchresult.h" - #include #include #include @@ -33,6 +31,8 @@ namespace Zeal { +struct SearchResult; + class Docset { public: diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index d4d38cfdc..8a98f6a35 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -26,7 +26,6 @@ #include "searchresult.h" #include -#include #include using namespace Zeal; diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index 07f59eab4..30ce741dc 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -25,7 +25,6 @@ #define DOCSETREGISTRY_H #include "docset.h" -#include "searchresult.h" #include @@ -33,6 +32,8 @@ class QThread; namespace Zeal { +struct SearchResult; + class DocsetRegistry : public QObject { Q_OBJECT From 6a26db31dcacef1a6a2a4d5e1a9786dbf157d8ce Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 22:18:05 -0400 Subject: [PATCH 100/273] ui: Fix copyright year in mainwindow.cpp --- src/ui/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index e653be428..4a3b87bfd 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 Oleg Shparber +** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera ** Contact: http://zealdocs.org/contact.html ** @@ -315,6 +315,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->openUrlButton, &QPushButton::clicked, [this]() { const QUrl url(ui->webView->page()->history()->currentItem().url()); + qDebug("%s", qPrintable(url.toString())); if (url.scheme() != QLatin1String("qrc")) QDesktopServices::openUrl(url); }); From f3180f1f9d2f794eebef749e423e40c13a55c392 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 22:58:49 -0400 Subject: [PATCH 101/273] ui: Move New Tab and Close Tab actions to the File menu --- src/ui/forms/mainwindow.ui | 12 +++++------- src/ui/mainwindow.cpp | 3 --- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index c92032887..c818ec5dd 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -223,6 +223,9 @@ &File + + + @@ -248,8 +251,6 @@ &Tabs - - @@ -291,15 +292,12 @@ - New Tab - - - Ctrl+T + New &Tab - Close Tab + &Close Tab diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 4a3b87bfd..0ae7dca37 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -508,9 +508,6 @@ SearchState *MainWindow::currentSearchState() const void MainWindow::displayTabs() { ui->menuTabs->clear(); - ui->menuTabs->addAction(ui->actionNewTab); - ui->menuTabs->addAction(ui->actionCloseTab); - ui->menuTabs->addSeparator(); ui->menuTabs->addAction(ui->actionNextTab); ui->menuTabs->addAction(ui->actionPreviousTab); ui->menuTabs->addSeparator(); From 203bc30a94c85d08bcf4379ff9039fe461ff53bf Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 22:59:10 -0400 Subject: [PATCH 102/273] ui: s/goToTab/selectTab in MainWindow --- src/ui/mainwindow.cpp | 4 ++-- src/ui/mainwindow.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 0ae7dca37..46bac6aff 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -305,7 +305,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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::currentChanged, this, &MainWindow::selectTab); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); { @@ -406,7 +406,7 @@ void MainWindow::queryCompleted() ui->lineEdit->setFocus(Qt::MouseFocusReason); } -void MainWindow::goToTab(int index) +void MainWindow::selectTab(int index) { if (index == -1) return; diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index be69771d2..6912c60ce 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -114,7 +114,7 @@ private slots: void queryCompleted(); void scrollSearch(); void saveTabState(); - void goToTab(int index); + void selectTab(int index); void closeTab(int index = -1); private: From 9288181c7346ee768c1ac4fb0c332ec1730e2afd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 23:07:34 -0400 Subject: [PATCH 103/273] ui: Remove Next and Previous Tab items from the Tabs menu --- src/ui/forms/mainwindow.ui | 3 --- src/ui/mainwindow.cpp | 6 ------ 2 files changed, 9 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index c818ec5dd..b5d0be26d 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -251,9 +251,6 @@ &Tabs - - - diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 46bac6aff..c05d4998e 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -508,12 +508,6 @@ SearchState *MainWindow::currentSearchState() const void MainWindow::displayTabs() { ui->menuTabs->clear(); - ui->menuTabs->addAction(ui->actionNextTab); - ui->menuTabs->addAction(ui->actionPreviousTab); - ui->menuTabs->addSeparator(); - - ui->actionNextTab->setEnabled(m_tabBar->count() > 1); - ui->actionPreviousTab->setEnabled(m_tabBar->count() > 1); for (int i = 0; i < m_tabs.count(); i++) { SearchState *state = m_tabs.at(i); From 8eb4407d80d3672860112caff0f8e3c7a2ccbc4e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 5 Apr 2016 23:41:54 -0400 Subject: [PATCH 104/273] ui: Remove the Tabs menu, fix tab selection shortcuts Alt/Ctrl+9 now selects the last tab in the tab bar. This is consistent with major web browsers. --- src/ui/forms/mainwindow.ui | 6 --- src/ui/mainwindow.cpp | 104 ++++++++++++++++--------------------- src/ui/mainwindow.h | 2 +- 3 files changed, 45 insertions(+), 67 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index b5d0be26d..27d1a0b55 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -247,14 +247,8 @@ - - - &Tabs - - - diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c05d4998e..3992a7101 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -84,9 +84,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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")))); #ifdef USE_APPINDICATOR @@ -99,6 +96,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : // initialise key grabber connect(m_globalShortcut, &QxtGlobalShortcut::activated, this, &MainWindow::toggleWindow); + setupTabBar(); + QShortcut *focusSearch = new QShortcut(QKeySequence(QStringLiteral("Ctrl+K")), this); focusSearch->setContext(Qt::ApplicationShortcut); connect(focusSearch, &QShortcut::activated, @@ -296,23 +295,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : 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::selectTab); - connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); - - { - QHBoxLayout *layout = reinterpret_cast(ui->navigationBar->layout()); - layout->insertWidget(2, m_tabBar, 0, Qt::AlignBottom); - } - connect(ui->openUrlButton, &QPushButton::clicked, [this]() { const QUrl url(ui->webView->page()->history()->currentItem().url()); qDebug("%s", qPrintable(url.toString())); @@ -505,44 +487,6 @@ SearchState *MainWindow::currentSearchState() const return m_tabs.at(m_tabBar->currentIndex()); } -void MainWindow::displayTabs() -{ - ui->menuTabs->clear(); - - for (int i = 0; i < m_tabs.count(); i++) { - SearchState *state = m_tabs.at(i); -#ifdef USE_WEBENGINE - QString title = state->page->title(); -#else - QString title = state->page->history()->currentItem().title(); -#endif - QAction *action = ui->menuTabs->addAction(title); - action->setCheckable(true); - action->setChecked(i == m_tabBar->currentIndex()); - - if (i < 10) { -#ifdef Q_OS_LINUX - const QKeySequence shortcut = QString("Alt+%1").arg(QString::number((i + 1) % 10)); -#else - const QKeySequence shortcut = QString("Ctrl+%1").arg(QString::number((i + 1) % 10)); -#endif - - for (QAction *oldAction : actions()) { - if (oldAction->shortcut() == shortcut) - removeAction(oldAction); - } - - action->setShortcut(shortcut); - addAction(action); - } - - m_tabBar->setTabText(i, title); - connect(action, &QAction::triggered, [=]() { - m_tabBar->setCurrentIndex(i); - }); - } -} - void MainWindow::reloadTabState() { SearchState *searchState = currentSearchState(); @@ -605,6 +549,48 @@ void MainWindow::setupSearchBoxCompletions() ui->lineEdit->setCompletions(completions); } +void MainWindow::setupTabBar() +{ + m_tabBar = new QTabBar(this); + + m_tabBar->installEventFilter(this); + + 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::selectTab); + connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); + + for (int i = 1; i < 10; i++) { + QAction *action = new QAction(m_tabBar); +#ifdef Q_OS_LINUX + action->setShortcut(QStringLiteral("Alt+%1").arg(i)); +#else + action->setShortcut(QStringLiteral("Ctrl+%1").arg(i)); +#endif + if (i == 9) { + connect(action, &QAction::triggered, [=]() { + m_tabBar->setCurrentIndex(m_tabBar->count() - 1); + }); + } else { + connect(action, &QAction::triggered, [=]() { + m_tabBar->setCurrentIndex(i - 1); + }); + } + + addAction(action); + } + + QHBoxLayout *layout = reinterpret_cast(ui->navigationBar->layout()); + layout->insertWidget(2, m_tabBar, 0, Qt::AlignBottom); +} + void MainWindow::displayViewActions() { ui->actionBack->setEnabled(ui->webView->canGoBack()); @@ -627,8 +613,6 @@ void MainWindow::displayViewActions() addHistoryAction(history, history->currentItem())->setEnabled(false); for (const QWebHistoryItem &item: history->forwardItems(10)) m_forwardMenu->addAction(addHistoryAction(history, item)); - - displayTabs(); } QAction *MainWindow::addHistoryAction(QWebHistory *history, const QWebHistoryItem &item) diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 6912c60ce..54589ca62 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -123,8 +123,8 @@ private slots: void displaySections(); void saveSectionsSplitterState(); void setupSearchBoxCompletions(); + void setupTabBar(); void reloadTabState(); - void displayTabs(); SearchState *currentSearchState() const; QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; From ec1a294a9c721caf241507ac7c96be850a4a2feb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 6 Apr 2016 00:00:40 -0400 Subject: [PATCH 105/273] ui: s/SearchState/TabState in MainWindow --- src/ui/mainwindow.cpp | 92 +++++++++++++++++++++---------------------- src/ui/mainwindow.h | 11 ++---- 2 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 3992a7101..0cb015346 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -206,7 +206,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : Docset *docset = m_application->docsetRegistry()->docset(name); if (docset) - m_searchState->sectionsList->setResults(docset->relatedLinks(url)); + m_currentTabState->sectionsList->setResults(docset->relatedLinks(url)); displayViewActions(); }); @@ -224,33 +224,33 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, [this](const QList &results) { - m_searchState->zealSearch->setResults(results); + m_currentTabState->zealSearch->setResults(results); }); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, this, [this](const QString &name) { setupSearchBoxCompletions(); - for (SearchState *searchState : m_tabs) { + for (TabState *tabState : m_tabStates) { #ifdef USE_WEBENGINE - if (docsetName(searchState->page->url()) != name) + if (docsetName(tabState->page->url()) != name) continue; - searchState->page->load(QUrl(startPageUrl)); + tabState->page->load(QUrl(startPageUrl)); #else - if (docsetName(searchState->page->mainFrame()->url()) != name) + if (docsetName(tabState->page->mainFrame()->url()) != name) continue; - searchState->sectionsList->setResults(); + tabState->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); + tabState->zealSearch->removeSearchResultWithName(name); ui->treeView->setUpdatesEnabled(true); - searchState->page->mainFrame()->load(QUrl(startPageUrl)); + tabState->page->mainFrame()->load(QUrl(startPageUrl)); #endif /// TODO: Cleanup history } @@ -262,13 +262,13 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : }); connect(ui->lineEdit, &QLineEdit::textChanged, [this](const QString &text) { - if (!m_searchState || text == m_searchState->searchQuery) + if (!m_currentTabState || text == m_currentTabState->searchQuery) return; - m_searchState->searchQuery = text; + m_currentTabState->searchQuery = text; m_application->docsetRegistry()->search(text); if (text.isEmpty()) { - m_searchState->sectionsList->setResults(); + m_currentTabState->sectionsList->setResults(); displayTreeView(); } }); @@ -279,12 +279,12 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : // save the expanded items: connect(ui->treeView, &QTreeView::expanded, [this](QModelIndex index) { - if (m_searchState->expansions.indexOf(index) == -1) - m_searchState->expansions.append(index); + if (m_currentTabState->expansions.indexOf(index) == -1) + m_currentTabState->expansions.append(index); }); connect(ui->treeView, &QTreeView::collapsed, [this](QModelIndex index) { - m_searchState->expansions.removeOne(index); + m_currentTabState->expansions.removeOne(index); }); #ifdef Q_OS_WIN32 @@ -328,7 +328,7 @@ MainWindow::~MainWindow() { delete ui; - for (SearchState *state : m_tabs) { + for (TabState *state : m_tabStates) { delete state->zealSearch; delete state->sectionsList; delete state; @@ -381,7 +381,7 @@ void MainWindow::queryCompleted() { displayTreeView(); - ui->treeView->setCurrentIndex(m_searchState->zealSearch->index(0, 0, QModelIndex())); + ui->treeView->setCurrentIndex(m_currentTabState->zealSearch->index(0, 0, QModelIndex())); openDocset(ui->treeView->currentIndex()); // Get focus back. QWebPageEngine::load() always steals focus. @@ -394,7 +394,7 @@ void MainWindow::selectTab(int index) return; saveTabState(); - m_searchState = nullptr; + m_currentTabState = nullptr; reloadTabState(); } @@ -407,10 +407,10 @@ void MainWindow::closeTab(int index) return; /// TODO: proper deletion here - SearchState *state = m_tabs.takeAt(index); + TabState *state = m_tabStates.takeAt(index); - if (m_searchState == state) - m_searchState = nullptr; + if (m_currentTabState == state) + m_currentTabState = nullptr; delete state->zealSearch; delete state->sectionsList; @@ -418,7 +418,7 @@ void MainWindow::closeTab(int index) m_tabBar->removeTab(index); - if (m_tabs.count() == 0) + if (m_tabStates.count() == 0) createTab(); } @@ -426,7 +426,7 @@ void MainWindow::createTab() { saveTabState(); - SearchState *newTab = new SearchState(); + TabState *newTab = new TabState(); newTab->zealSearch = new Zeal::SearchModel(); newTab->sectionsList = new Zeal::SearchModel(); @@ -442,7 +442,7 @@ void MainWindow::createTab() newTab->page->mainFrame()->load(QUrl(startPageUrl)); #endif - m_tabs.append(newTab); + m_tabStates.append(newTab); const int index = m_tabBar->addTab(QStringLiteral("title")); @@ -451,10 +451,10 @@ void MainWindow::createTab() void MainWindow::displayTreeView() { - SearchState *searchState = currentSearchState(); + TabState *tabState = currentTabState(); - if (!searchState->searchQuery.isEmpty()) { - ui->treeView->setModel(searchState->zealSearch); + if (!tabState->searchQuery.isEmpty()) { + ui->treeView->setModel(tabState->zealSearch); ui->treeView->setRootIsDecorated(false); } else { ui->treeView->setModel(m_zealListModel); @@ -468,7 +468,7 @@ void MainWindow::displaySections() { saveSectionsSplitterState(); - const bool hasResults = currentSearchState()->sectionsList->rowCount(); + const bool hasResults = currentTabState()->sectionsList->rowCount(); ui->sections->setVisible(hasResults); QList sizes = hasResults ? m_settings->sectionsSplitterSizes @@ -482,33 +482,33 @@ void MainWindow::saveSectionsSplitterState() m_settings->sectionsSplitterSizes = ui->sectionsSplitter->sizes(); } -SearchState *MainWindow::currentSearchState() const +TabState *MainWindow::currentTabState() const { - return m_tabs.at(m_tabBar->currentIndex()); + return m_tabStates.at(m_tabBar->currentIndex()); } void MainWindow::reloadTabState() { - SearchState *searchState = currentSearchState(); + TabState *tabState = currentTabState(); - ui->lineEdit->setText(searchState->searchQuery); - ui->sections->setModel(searchState->sectionsList); + ui->lineEdit->setText(tabState->searchQuery); + ui->sections->setModel(tabState->sectionsList); displaySections(); displayTreeView(); // Bring back the selections and expansions ui->treeView->blockSignals(true); - for (const QModelIndex &selection: searchState->selections) + for (const QModelIndex &selection: tabState->selections) ui->treeView->selectionModel()->select(selection, QItemSelectionModel::Select); - for (const QModelIndex &expandedIndex: searchState->expansions) + for (const QModelIndex &expandedIndex: tabState->expansions) ui->treeView->expand(expandedIndex); ui->treeView->blockSignals(false); - ui->webView->setPage(searchState->page); - ui->webView->setZoomFactor(searchState->zoomFactor); + ui->webView->setPage(tabState->page); + ui->webView->setZoomFactor(tabState->zoomFactor); - m_searchState = searchState; + m_currentTabState = tabState; // scroll after the object gets loaded /// TODO: [Qt 5.4] QTimer::singleShot(100, this, &MainWindow::scrollSearch); @@ -519,20 +519,20 @@ void MainWindow::reloadTabState() void MainWindow::scrollSearch() { - ui->treeView->verticalScrollBar()->setValue(m_searchState->scrollPosition); - ui->sections->verticalScrollBar()->setValue(m_searchState->sectionsScroll); + ui->treeView->verticalScrollBar()->setValue(m_currentTabState->scrollPosition); + ui->sections->verticalScrollBar()->setValue(m_currentTabState->sectionsScroll); } void MainWindow::saveTabState() { - if (!m_searchState) + if (!m_currentTabState) return; - m_searchState->searchQuery = ui->lineEdit->text(); - m_searchState->selections = ui->treeView->selectionModel()->selectedIndexes(); - m_searchState->scrollPosition = ui->treeView->verticalScrollBar()->value(); - m_searchState->sectionsScroll = ui->sections->verticalScrollBar()->value(); - m_searchState->zoomFactor = ui->webView->zoomFactor(); + m_currentTabState->searchQuery = ui->lineEdit->text(); + m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); + m_currentTabState->scrollPosition = ui->treeView->verticalScrollBar()->value(); + m_currentTabState->sectionsScroll = ui->sections->verticalScrollBar()->value(); + m_currentTabState->zoomFactor = ui->webView->zoomFactor(); } // Sets up the search box autocompletions. diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 54589ca62..73ae7c7cb 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -66,9 +66,7 @@ class SettingsDialog; } -// Represents per tab search state. -// needs to contain [search input, search model, section model, url] -struct SearchState +struct TabState { QWebPage *page; // model representing sections @@ -125,7 +123,7 @@ private slots: void setupSearchBoxCompletions(); void setupTabBar(); void reloadTabState(); - SearchState *currentSearchState() const; + TabState *currentTabState() const; QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; QAction *addHistoryAction(QWebHistory *history, const QWebHistoryItem &item); @@ -136,9 +134,8 @@ private slots: void createTrayIcon(); void removeTrayIcon(); - QList m_tabs; - - SearchState *m_searchState = nullptr; + QList m_tabStates; + TabState *m_currentTabState = nullptr; Ui::MainWindow *ui = nullptr; Zeal::Core::Application *m_application = nullptr; From dcfb747ffc789bbd1c35afe2d00bef6d47b12362 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 6 Apr 2016 00:12:50 -0400 Subject: [PATCH 106/273] ui: Fix tab titles --- src/ui/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 0cb015346..f9e284ab9 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -211,7 +211,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : displayViewActions(); }); - connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &) { + connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &text) { + m_tabBar->setTabText(m_tabBar->currentIndex(), text); displayViewActions(); }); From c233171c6d8e1ddb7c3bab04f2f64e403917d75e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 6 Apr 2016 00:13:23 -0400 Subject: [PATCH 107/273] ui: Refactor MainWindow::TabState --- src/ui/mainwindow.cpp | 66 +++++++++++++++++++++---------------------- src/ui/mainwindow.h | 20 ++++++------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index f9e284ab9..a9e223201 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -206,7 +206,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : Docset *docset = m_application->docsetRegistry()->docset(name); if (docset) - m_currentTabState->sectionsList->setResults(docset->relatedLinks(url)); + m_currentTabState->tocModel->setResults(docset->relatedLinks(url)); displayViewActions(); }); @@ -225,7 +225,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, [this](const QList &results) { - m_currentTabState->zealSearch->setResults(results); + m_currentTabState->searchModel->setResults(results); }); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, @@ -233,25 +233,25 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : setupSearchBoxCompletions(); for (TabState *tabState : m_tabStates) { #ifdef USE_WEBENGINE - if (docsetName(tabState->page->url()) != name) + if (docsetName(tabState->webPage->url()) != name) continue; - tabState->page->load(QUrl(startPageUrl)); + tabState->webPage->load(QUrl(startPageUrl)); #else - if (docsetName(tabState->page->mainFrame()->url()) != name) + if (docsetName(tabState->webPage->mainFrame()->url()) != name) continue; - tabState->sectionsList->setResults(); + tabState->tocModel->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); - tabState->zealSearch->removeSearchResultWithName(name); + tabState->searchModel->removeSearchResultWithName(name); ui->treeView->setUpdatesEnabled(true); - tabState->page->mainFrame()->load(QUrl(startPageUrl)); + tabState->webPage->mainFrame()->load(QUrl(startPageUrl)); #endif /// TODO: Cleanup history } @@ -269,7 +269,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_currentTabState->searchQuery = text; m_application->docsetRegistry()->search(text); if (text.isEmpty()) { - m_currentTabState->sectionsList->setResults(); + m_currentTabState->tocModel->setResults(); displayTreeView(); } }); @@ -330,8 +330,8 @@ MainWindow::~MainWindow() delete ui; for (TabState *state : m_tabStates) { - delete state->zealSearch; - delete state->sectionsList; + delete state->searchModel; + delete state->tocModel; delete state; } } @@ -382,7 +382,7 @@ void MainWindow::queryCompleted() { displayTreeView(); - ui->treeView->setCurrentIndex(m_currentTabState->zealSearch->index(0, 0, QModelIndex())); + ui->treeView->setCurrentIndex(m_currentTabState->searchModel->index(0, 0, QModelIndex())); openDocset(ui->treeView->currentIndex()); // Get focus back. QWebPageEngine::load() always steals focus. @@ -413,8 +413,8 @@ void MainWindow::closeTab(int index) if (m_currentTabState == state) m_currentTabState = nullptr; - delete state->zealSearch; - delete state->sectionsList; + delete state->searchModel; + delete state->tocModel; delete state; m_tabBar->removeTab(index); @@ -428,19 +428,19 @@ void MainWindow::createTab() saveTabState(); TabState *newTab = new TabState(); - newTab->zealSearch = new Zeal::SearchModel(); - newTab->sectionsList = new Zeal::SearchModel(); + newTab->searchModel = new Zeal::SearchModel(); + newTab->tocModel = new Zeal::SearchModel(); - connect(newTab->zealSearch, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); - connect(newTab->sectionsList, &SearchModel::queryCompleted, this, &MainWindow::displaySections); + connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); + connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::displaySections); - newTab->page = new QWebPage(ui->webView); + newTab->webPage = new QWebPage(ui->webView); #ifdef USE_WEBENGINE - newTab->page->load(QUrl(startPageUrl)); + newTab->webPage->load(QUrl(startPageUrl)); #else - newTab->page->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); - newTab->page->setNetworkAccessManager(m_application->networkManager()); - newTab->page->mainFrame()->load(QUrl(startPageUrl)); + newTab->webPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); + newTab->webPage->setNetworkAccessManager(m_application->networkManager()); + newTab->webPage->mainFrame()->load(QUrl(startPageUrl)); #endif m_tabStates.append(newTab); @@ -455,7 +455,7 @@ void MainWindow::displayTreeView() TabState *tabState = currentTabState(); if (!tabState->searchQuery.isEmpty()) { - ui->treeView->setModel(tabState->zealSearch); + ui->treeView->setModel(tabState->searchModel); ui->treeView->setRootIsDecorated(false); } else { ui->treeView->setModel(m_zealListModel); @@ -469,7 +469,7 @@ void MainWindow::displaySections() { saveSectionsSplitterState(); - const bool hasResults = currentTabState()->sectionsList->rowCount(); + const bool hasResults = currentTabState()->tocModel->rowCount(); ui->sections->setVisible(hasResults); QList sizes = hasResults ? m_settings->sectionsSplitterSizes @@ -493,7 +493,7 @@ void MainWindow::reloadTabState() TabState *tabState = currentTabState(); ui->lineEdit->setText(tabState->searchQuery); - ui->sections->setModel(tabState->sectionsList); + ui->sections->setModel(tabState->tocModel); displaySections(); displayTreeView(); @@ -506,8 +506,8 @@ void MainWindow::reloadTabState() ui->treeView->expand(expandedIndex); ui->treeView->blockSignals(false); - ui->webView->setPage(tabState->page); - ui->webView->setZoomFactor(tabState->zoomFactor); + ui->webView->setPage(tabState->webPage); + ui->webView->setZoomFactor(tabState->webViewZoomFactor); m_currentTabState = tabState; @@ -520,8 +520,8 @@ void MainWindow::reloadTabState() void MainWindow::scrollSearch() { - ui->treeView->verticalScrollBar()->setValue(m_currentTabState->scrollPosition); - ui->sections->verticalScrollBar()->setValue(m_currentTabState->sectionsScroll); + ui->treeView->verticalScrollBar()->setValue(m_currentTabState->searchScrollPosition); + ui->sections->verticalScrollBar()->setValue(m_currentTabState->tocScrollPosition); } void MainWindow::saveTabState() @@ -531,9 +531,9 @@ void MainWindow::saveTabState() m_currentTabState->searchQuery = ui->lineEdit->text(); m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); - m_currentTabState->scrollPosition = ui->treeView->verticalScrollBar()->value(); - m_currentTabState->sectionsScroll = ui->sections->verticalScrollBar()->value(); - m_currentTabState->zoomFactor = ui->webView->zoomFactor(); + m_currentTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); + m_currentTabState->tocScrollPosition = ui->sections->verticalScrollBar()->value(); + m_currentTabState->webViewZoomFactor = ui->webView->zoomFactor(); } // Sets up the search box autocompletions. diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 73ae7c7cb..a8f1a0a9e 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -68,22 +68,20 @@ class SettingsDialog; struct TabState { - QWebPage *page; - // model representing sections - Zeal::SearchModel *sectionsList; - // model representing searched for items - Zeal::SearchModel *zealSearch; - // query being searched for QString searchQuery; - // list of selected indices + // Content/Search results tree view state + Zeal::SearchModel *searchModel = nullptr; QModelIndexList selections; - // list of expanded indices QModelIndexList expansions; + int searchScrollPosition; - int scrollPosition; - int sectionsScroll; - int zoomFactor; + // TOC list view state + Zeal::SearchModel *tocModel = nullptr; + int tocScrollPosition; + + QWebPage *webPage = nullptr; + int webViewZoomFactor; }; class MainWindow : public QMainWindow From 1f76b949dc79cbf54c035a976208ba35e7f53c5d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 6 Apr 2016 00:20:49 -0400 Subject: [PATCH 108/273] ui: Reorder MainWindow methods --- src/ui/mainwindow.cpp | 24 ++++++++++++------------ src/ui/mainwindow.h | 6 ++++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a9e223201..5928a4d30 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -488,6 +488,18 @@ TabState *MainWindow::currentTabState() const return m_tabStates.at(m_tabBar->currentIndex()); } +void MainWindow::saveTabState() +{ + if (!m_currentTabState) + return; + + m_currentTabState->searchQuery = ui->lineEdit->text(); + m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); + m_currentTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); + m_currentTabState->tocScrollPosition = ui->sections->verticalScrollBar()->value(); + m_currentTabState->webViewZoomFactor = ui->webView->zoomFactor(); +} + void MainWindow::reloadTabState() { TabState *tabState = currentTabState(); @@ -524,18 +536,6 @@ void MainWindow::scrollSearch() ui->sections->verticalScrollBar()->setValue(m_currentTabState->tocScrollPosition); } -void MainWindow::saveTabState() -{ - if (!m_currentTabState) - return; - - m_currentTabState->searchQuery = ui->lineEdit->text(); - m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); - m_currentTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); - m_currentTabState->tocScrollPosition = ui->sections->verticalScrollBar()->value(); - m_currentTabState->webViewZoomFactor = ui->webView->zoomFactor(); -} - // Sets up the search box autocompletions. void MainWindow::setupSearchBoxCompletions() { diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index a8f1a0a9e..d81b33389 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -109,7 +109,6 @@ private slots: void openDocset(const QModelIndex &index); void queryCompleted(); void scrollSearch(); - void saveTabState(); void selectTab(int index); void closeTab(int index = -1); @@ -120,8 +119,11 @@ private slots: void saveSectionsSplitterState(); void setupSearchBoxCompletions(); void setupTabBar(); - void reloadTabState(); + TabState *currentTabState() const; + void saveTabState(); + void reloadTabState(); + QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; QAction *addHistoryAction(QWebHistory *history, const QWebHistoryItem &item); From fdc269642238924365a11453362919c9279ee3dc Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 6 Apr 2016 00:44:05 -0400 Subject: [PATCH 109/273] ui: Remove redundant save/reloadTabState calls in MainWindow --- src/ui/mainwindow.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 5928a4d30..868710639 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -190,8 +190,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->sections->setItemDelegate(new SearchItemDelegate(ui->sections)); createTab(); - /// FIXME: QTabBar does not emit currentChanged() after the first addTab() call - reloadTabState(); connect(ui->treeView, &QTreeView::clicked, this, &MainWindow::openDocset); connect(ui->sections, &QListView::clicked, this, &MainWindow::openDocset); @@ -425,8 +423,6 @@ void MainWindow::closeTab(int index) void MainWindow::createTab() { - saveTabState(); - TabState *newTab = new TabState(); newTab->searchModel = new Zeal::SearchModel(); newTab->tocModel = new Zeal::SearchModel(); From 116b5472937abbe19d0e162a92705e59ffb75ea5 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 00:19:32 -0400 Subject: [PATCH 110/273] ui: Fix splitter and window geometry not saved on app quit --- src/ui/mainwindow.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 868710639..c1559c0f3 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -325,6 +325,11 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : MainWindow::~MainWindow() { + m_settings->verticalSplitterGeometry = ui->splitter->saveState(); + saveSectionsSplitterState(); + + m_settings->windowGeometry = saveGeometry(); + delete ui; for (TabState *state : m_tabStates) { @@ -765,10 +770,6 @@ void MainWindow::changeEvent(QEvent *event) void MainWindow::closeEvent(QCloseEvent *event) { - m_settings->verticalSplitterGeometry = ui->splitter->saveState(); - saveSectionsSplitterState(); - - m_settings->windowGeometry = saveGeometry(); if (m_settings->showSystrayIcon && m_settings->hideOnClose) { event->ignore(); toggleWindow(); From 79c27e0c7a60c26ceb6e9ab617f3d3415e472653 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 00:36:18 -0400 Subject: [PATCH 111/273] ui: Remove timeout before restoring scrollbars' positions --- src/ui/mainwindow.cpp | 11 ++--------- src/ui/mainwindow.h | 1 - 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c1559c0f3..b5bf10004 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -524,17 +524,10 @@ void MainWindow::reloadTabState() m_currentTabState = tabState; - // scroll after the object gets loaded - /// TODO: [Qt 5.4] QTimer::singleShot(100, this, &MainWindow::scrollSearch); - QTimer::singleShot(100, this, SLOT(scrollSearch())); - - displayViewActions(); -} - -void MainWindow::scrollSearch() -{ ui->treeView->verticalScrollBar()->setValue(m_currentTabState->searchScrollPosition); ui->sections->verticalScrollBar()->setValue(m_currentTabState->tocScrollPosition); + + displayViewActions(); } // Sets up the search box autocompletions. diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index d81b33389..a9d0a1f36 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -108,7 +108,6 @@ private slots: void applySettings(); void openDocset(const QModelIndex &index); void queryCompleted(); - void scrollSearch(); void selectTab(int index); void closeTab(int index = -1); From 101691cfcd1fd6c514872d6ca1f621c643d7a0c6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 00:43:07 -0400 Subject: [PATCH 112/273] ui: Remove debug output in MainWindow --- src/ui/mainwindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index b5bf10004..cf61186ac 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -296,7 +296,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->openUrlButton, &QPushButton::clicked, [this]() { const QUrl url(ui->webView->page()->history()->currentItem().url()); - qDebug("%s", qPrintable(url.toString())); if (url.scheme() != QLatin1String("qrc")) QDesktopServices::openUrl(url); }); From eb24d25519f6062d2c4bacda22457cd1e1e50917 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 00:48:09 -0400 Subject: [PATCH 113/273] ui: More s/sections/toc in MainWindow --- src/ui/forms/mainwindow.ui | 4 ++-- src/ui/mainwindow.cpp | 34 +++++++++++++++++----------------- src/ui/mainwindow.h | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 27d1a0b55..890034c53 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -78,7 +78,7 @@ - + Qt::Vertical @@ -111,7 +111,7 @@ 0 - + QFrame::NoFrame diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index cf61186ac..9c0759779 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -187,14 +187,14 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : }); ui->treeView->setItemDelegate(delegate); - ui->sections->setItemDelegate(new SearchItemDelegate(ui->sections)); + ui->tocListView->setItemDelegate(new SearchItemDelegate(ui->tocListView)); createTab(); connect(ui->treeView, &QTreeView::clicked, this, &MainWindow::openDocset); - connect(ui->sections, &QListView::clicked, this, &MainWindow::openDocset); + connect(ui->tocListView, &QListView::clicked, this, &MainWindow::openDocset); connect(ui->treeView, &QTreeView::activated, this, &MainWindow::openDocset); - connect(ui->sections, &QListView::activated, this, &MainWindow::openDocset); + connect(ui->tocListView, &QListView::activated, this, &MainWindow::openDocset); connect(ui->forwardButton, &QPushButton::clicked, ui->webView, &SearchableWebView::forward); connect(ui->backButton, &QPushButton::clicked, ui->webView, &SearchableWebView::back); @@ -315,7 +315,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : #ifdef Q_OS_OSX ui->treeView->setAttribute(Qt::WA_MacShowFocusRect, false); - ui->sections->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->tocView->setAttribute(Qt::WA_MacShowFocusRect, false); #endif if (m_settings->checkForUpdate) @@ -325,7 +325,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : MainWindow::~MainWindow() { m_settings->verticalSplitterGeometry = ui->splitter->saveState(); - saveSectionsSplitterState(); + saveTocSplitterState(); m_settings->windowGeometry = saveGeometry(); @@ -432,7 +432,7 @@ void MainWindow::createTab() newTab->tocModel = new Zeal::SearchModel(); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); - connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::displaySections); + connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::showToc); newTab->webPage = new QWebPage(ui->webView); #ifdef USE_WEBENGINE @@ -465,22 +465,22 @@ void MainWindow::displayTreeView() ui->treeView->reset(); } -void MainWindow::displaySections() +void MainWindow::showToc() { - saveSectionsSplitterState(); + saveTocSplitterState(); const bool hasResults = currentTabState()->tocModel->rowCount(); - ui->sections->setVisible(hasResults); + ui->tocListView->setVisible(hasResults); QList sizes = hasResults ? m_settings->sectionsSplitterSizes : QList({1, 0}); - ui->sectionsSplitter->setSizes(sizes); + ui->tocSplitter->setSizes(sizes); } -void MainWindow::saveSectionsSplitterState() +void MainWindow::saveTocSplitterState() { - if (ui->sections->isVisible()) - m_settings->sectionsSplitterSizes = ui->sectionsSplitter->sizes(); + if (ui->tocListView->isVisible()) + m_settings->sectionsSplitterSizes = ui->tocSplitter->sizes(); } TabState *MainWindow::currentTabState() const @@ -496,7 +496,7 @@ void MainWindow::saveTabState() m_currentTabState->searchQuery = ui->lineEdit->text(); m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); m_currentTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); - m_currentTabState->tocScrollPosition = ui->sections->verticalScrollBar()->value(); + m_currentTabState->tocScrollPosition = ui->tocListView->verticalScrollBar()->value(); m_currentTabState->webViewZoomFactor = ui->webView->zoomFactor(); } @@ -505,9 +505,9 @@ void MainWindow::reloadTabState() TabState *tabState = currentTabState(); ui->lineEdit->setText(tabState->searchQuery); - ui->sections->setModel(tabState->tocModel); + ui->tocListView->setModel(tabState->tocModel); - displaySections(); + showToc(); displayTreeView(); // Bring back the selections and expansions @@ -524,7 +524,7 @@ void MainWindow::reloadTabState() m_currentTabState = tabState; ui->treeView->verticalScrollBar()->setValue(m_currentTabState->searchScrollPosition); - ui->sections->verticalScrollBar()->setValue(m_currentTabState->tocScrollPosition); + ui->tocListView->verticalScrollBar()->setValue(m_currentTabState->tocScrollPosition); displayViewActions(); } diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index a9d0a1f36..4b418cce4 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -114,8 +114,8 @@ private slots: private: void displayViewActions(); void displayTreeView(); - void displaySections(); - void saveSectionsSplitterState(); + void showToc(); + void saveTocSplitterState(); void setupSearchBoxCompletions(); void setupTabBar(); From 8752e8076a0734837206c1dbec79ba8c7a3a18a0 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 22:14:39 -0400 Subject: [PATCH 114/273] ui: Fix TOC splitter handle not hiding --- src/ui/forms/mainwindow.ui | 41 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 890034c53..b4bffba93 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -93,37 +93,16 @@ false - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - true - - - - + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + From 37427c078a9441929863766a18d71cb5c30acd2a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 22:40:55 -0400 Subject: [PATCH 115/273] registry: Implement SearchModel::isEmpty() method --- src/registry/searchmodel.cpp | 5 +++++ src/registry/searchmodel.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index 04b23ef8c..b898141f8 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -34,6 +34,11 @@ SearchModel::SearchModel(QObject *parent) : { } +bool SearchModel::isEmpty() const +{ + return rowCount() == 0; +} + QVariant SearchModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index daf7052d0..0b3fe32cc 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -41,6 +41,8 @@ class SearchModel : public QAbstractItemModel explicit SearchModel(QObject *parent = nullptr); + bool isEmpty() const; + QVariant data(const QModelIndex &index, int role) const override; QModelIndex index(int row, int column, const QModelIndex &parent) const override; QModelIndex parent(const QModelIndex &child) const override; From 8579fed5783bdf3122739536aaf32cc10707ca8e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 7 Apr 2016 22:43:11 -0400 Subject: [PATCH 116/273] core, ui: Fix saving and restoring of the TOC splitter state --- src/core/settings.cpp | 13 ++----------- src/core/settings.h | 2 +- src/ui/mainwindow.cpp | 31 +++++++++++++------------------ src/ui/mainwindow.h | 3 +-- 4 files changed, 17 insertions(+), 32 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 46f89d8c9..6b76c9a36 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -121,12 +121,7 @@ void Settings::load() m_settings->beginGroup(GroupState); windowGeometry = m_settings->value(QStringLiteral("window_geometry")).toByteArray(); verticalSplitterGeometry = m_settings->value(QStringLiteral("splitter_geometry")).toByteArray(); - - sectionsSplitterSizes = QList(); - QList splitterSizes = m_settings->value(QStringLiteral("sections_geometry")).toList(); - for (QVariant splitterSize: splitterSizes) - sectionsSplitterSizes << splitterSize.toInt(); - + tocSplitterState = m_settings->value(QStringLiteral("toc_splitter_state")).toByteArray(); m_settings->endGroup(); m_settings->beginGroup(GroupInternal); @@ -171,14 +166,10 @@ void Settings::save() m_settings->endGroup(); #endif - QList splitterSizes; - for (int splitterSize: sectionsSplitterSizes) - splitterSizes << splitterSize; - m_settings->beginGroup(GroupState); m_settings->setValue(QStringLiteral("window_geometry"), windowGeometry); m_settings->setValue(QStringLiteral("splitter_geometry"), verticalSplitterGeometry); - m_settings->setValue(QStringLiteral("sections_geometry"), splitterSizes); + m_settings->setValue(QStringLiteral("toc_splitter_state"), tocSplitterState); m_settings->endGroup(); m_settings->beginGroup(GroupInternal); diff --git a/src/core/settings.h b/src/core/settings.h index 5cbc95c89..20cef3dae 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -89,7 +89,7 @@ class Settings : public QObject // State QByteArray windowGeometry; QByteArray verticalSplitterGeometry; - QList sectionsSplitterSizes; + QByteArray tocSplitterState; explicit Settings(QObject *parent = nullptr); ~Settings() override; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 9c0759779..c4cc6f6b0 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -188,6 +188,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->treeView->setItemDelegate(delegate); ui->tocListView->setItemDelegate(new SearchItemDelegate(ui->tocListView)); + connect(ui->tocSplitter, &QSplitter::splitterMoved, this, [this]() { + if (ui->tocListView->isVisible()) + m_settings->tocSplitterState = ui->tocSplitter->saveState(); + }); createTab(); @@ -325,8 +329,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : MainWindow::~MainWindow() { m_settings->verticalSplitterGeometry = ui->splitter->saveState(); - saveTocSplitterState(); - m_settings->windowGeometry = saveGeometry(); delete ui; @@ -432,7 +434,7 @@ void MainWindow::createTab() newTab->tocModel = new Zeal::SearchModel(); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); - connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::showToc); + connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); newTab->webPage = new QWebPage(ui->webView); #ifdef USE_WEBENGINE @@ -465,22 +467,15 @@ void MainWindow::displayTreeView() ui->treeView->reset(); } -void MainWindow::showToc() +void MainWindow::toggleToc() { - saveTocSplitterState(); - - const bool hasResults = currentTabState()->tocModel->rowCount(); - ui->tocListView->setVisible(hasResults); - QList sizes = hasResults - ? m_settings->sectionsSplitterSizes - : QList({1, 0}); - ui->tocSplitter->setSizes(sizes); -} + if (!currentTabState()->tocModel->isEmpty()) { + ui->tocListView->show(); + ui->tocSplitter->restoreState(m_settings->tocSplitterState); + } else { + ui->tocListView->hide(); + } -void MainWindow::saveTocSplitterState() -{ - if (ui->tocListView->isVisible()) - m_settings->sectionsSplitterSizes = ui->tocSplitter->sizes(); } TabState *MainWindow::currentTabState() const @@ -507,7 +502,7 @@ void MainWindow::reloadTabState() ui->lineEdit->setText(tabState->searchQuery); ui->tocListView->setModel(tabState->tocModel); - showToc(); + toggleToc(); displayTreeView(); // Bring back the selections and expansions diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 4b418cce4..054de5c7e 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -114,8 +114,7 @@ private slots: private: void displayViewActions(); void displayTreeView(); - void showToc(); - void saveTocSplitterState(); + void toggleToc(); void setupSearchBoxCompletions(); void setupTabBar(); From e1e8f1d05cf5f03ef11fc6c91d4e101998f07c00 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 8 Apr 2016 22:48:15 -0400 Subject: [PATCH 117/273] app, core: Move interinstance communication to Application --- src/core/application.cpp | 29 +++++++++++++++++++++++++---- src/core/application.h | 2 +- src/main.cpp | 17 +++-------------- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index dbe6231d8..82e0450aa 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -46,6 +46,8 @@ using namespace Zeal; using namespace Zeal::Core; namespace { +const char LocalServerName[] = "ZealLocalServer"; + const char ReleasesApiUrl[] = "http://api.zealdocs.org/v1/releases"; } @@ -94,9 +96,11 @@ Application::Application(const SearchQuery &query, QObject *parent) : m_mainWindow->bringToFront(); }); + + // Remove in case previous instance crashed /// TODO: Verify if removeServer() is needed - QLocalServer::removeServer(localServerName()); // remove in case previous instance crashed - m_localServer->listen(localServerName()); + QLocalServer::removeServer(LocalServerName); + m_localServer->listen(LocalServerName); // Extractor setup m_extractor->moveToThread(m_extractorThread); @@ -133,9 +137,26 @@ Application::~Application() delete m_docsetRegistry; } -QString Application::localServerName() +/*! + * \internal + * \brief Hands over \a query to already running application instance, if it exists. + * \param query A query to execute search with. + * \param preventActivation If \c true, application window will not activated. + * \return \c true if communication with another instance was successful. + */ +bool Application::send(const SearchQuery &query, bool preventActivation) { - return QStringLiteral("ZealLocalServer"); + QScopedPointer socket(new QLocalSocket()); + socket->connectToServer(LocalServerName); + + if (!socket->waitForConnected(500)) + return false; + + QDataStream out(socket.data()); + out << query; + out << preventActivation; + socket->flush(); + return true; } QNetworkAccessManager *Application::networkManager() const diff --git a/src/core/application.h b/src/core/application.h index 3335a8f2b..8fb34d270 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -50,7 +50,7 @@ class Application : public QObject explicit Application(const SearchQuery &query, QObject *parent = nullptr); ~Application() override; - static QString localServerName(); + static bool send(const SearchQuery &query, bool preventActivation); QNetworkAccessManager *networkManager() const; Settings *settings() const; diff --git a/src/main.cpp b/src/main.cpp index b7a661356..fa61a24de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,10 +26,8 @@ #include #include -#include #include #include -#include #include #include #include @@ -191,19 +189,10 @@ int main(int argc, char *argv[]) } #endif - // Detect already running instance and optionally pass a search query to it. - if (!clParams.force) { - QScopedPointer socket(new QLocalSocket()); - socket->connectToServer(Zeal::Core::Application::localServerName()); - - if (socket->waitForConnected(500)) { - QDataStream out(socket.data()); - out << clParams.query; - out << clParams.preventActivation; - socket->flush(); - return 0; - } + if (!clParams.force + && Zeal::Core::Application::send(clParams.query, clParams.preventActivation)) { + return 0; } // Check for SQLite plugin From 9c6d1d41450e944520c59663e4acdba8534ac1c1 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 8 Apr 2016 22:48:41 -0400 Subject: [PATCH 118/273] app: Minor cleanup --- src/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fa61a24de..87c481266 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,11 +37,13 @@ #include #endif +using namespace Zeal; + struct CommandLineParameters { bool force; bool preventActivation; - Zeal::SearchQuery query; + SearchQuery query; #ifdef Q_OS_WIN32 bool registerProtocolHandlers; bool unregisterProtocolHandlers; @@ -190,10 +192,8 @@ int main(int argc, char *argv[]) #endif // Detect already running instance and optionally pass a search query to it. - if (!clParams.force - && Zeal::Core::Application::send(clParams.query, clParams.preventActivation)) { + if (!clParams.force && Core::Application::send(clParams.query, clParams.preventActivation)) return 0; - } // Check for SQLite plugin /// TODO: Specific to docset format and should be handled accordingly in the future @@ -208,7 +208,7 @@ int main(int argc, char *argv[]) QDir::setSearchPaths(QStringLiteral("typeIcon"), {QStringLiteral(":/icons/type")}); - QScopedPointer app(new Zeal::Core::Application(clParams.query)); + QScopedPointer app(new Core::Application(clParams.query)); return qapp->exec(); } From 11b44d34e9f442046636902bc4b6b7ef5b0a0fe6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 8 Apr 2016 22:53:14 -0400 Subject: [PATCH 119/273] ui: Create SettingsDialog on demand --- src/ui/mainwindow.cpp | 12 +++--------- src/ui/mainwindow.h | 1 - 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c4cc6f6b0..21a9b8f03 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -77,7 +77,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_application(app), m_settings(app->settings()), m_zealListModel(new ListModel(app->docsetRegistry(), this)), - m_settingsDialog(new SettingsDialog(app, this)), m_globalShortcut(new QxtGlobalShortcut(m_settings->showShortcut, this)) { ui->setupUi(this); @@ -122,9 +121,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } connect(ui->actionQuit, &QAction::triggered, qApp, &QCoreApplication::quit); - connect(ui->actionOptions, &QAction::triggered, [=]() { + connect(ui->actionOptions, &QAction::triggered, [this]() { m_globalShortcut->setEnabled(false); - m_settingsDialog->exec(); + QScopedPointer dialog(new SettingsDialog(m_application, this)); + dialog->exec(); m_globalShortcut->setEnabled(true); }); @@ -688,12 +688,6 @@ void MainWindow::createTrayIcon() if (reason != QSystemTrayIcon::Trigger && reason != QSystemTrayIcon::DoubleClick) return; - // Disable, when settings window is open - if (m_settingsDialog->isVisible()) { - m_settingsDialog->activateWindow(); - return; - } - toggleWindow(); }); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 054de5c7e..7a6145d80 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -139,7 +139,6 @@ private slots: Zeal::Core::Application *m_application = nullptr; Zeal::Core::Settings *m_settings = nullptr; Zeal::ListModel *m_zealListModel = nullptr; - Zeal::SettingsDialog *m_settingsDialog = nullptr; QMenu *m_backMenu = nullptr; QMenu *m_forwardMenu = nullptr; From 6876c2cda40bf613fcdf0f1eb501bb06242c3dba Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 8 Apr 2016 22:57:28 -0400 Subject: [PATCH 120/273] registry: Optimize SearchModel::isEmpty() --- src/registry/searchmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index b898141f8..04572a25c 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -36,7 +36,7 @@ SearchModel::SearchModel(QObject *parent) : bool SearchModel::isEmpty() const { - return rowCount() == 0; + return m_dataList.isEmpty(); } QVariant SearchModel::data(const QModelIndex &index, int role) const From a2b8671b4f3b11efe1011cde7fb874cb209ceb45 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 8 Apr 2016 23:13:49 -0400 Subject: [PATCH 121/273] ui: Remove unnecessary forward declaration --- src/ui/mainwindow.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 7a6145d80..6cd2a223b 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -62,9 +62,7 @@ class Settings; class ListModel; class SearchModel; -class SettingsDialog; - -} +} // namespace Core struct TabState { From fb55e40672064b998b59b1f39fc0980b55854301 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 8 Apr 2016 23:16:51 -0400 Subject: [PATCH 122/273] core, ui: Replace QWebEngine related defines with typedefs --- src/core/settings.cpp | 2 +- src/ui/mainwindow.cpp | 2 ++ src/ui/mainwindow.h | 16 ++++++++++------ src/ui/settingsdialog.cpp | 3 ++- src/ui/widgets/searchablewebview.h | 9 ++++++--- src/ui/widgets/webview.h | 11 ++++++----- 6 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 6b76c9a36..39eab496d 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -31,7 +31,7 @@ #ifdef USE_WEBENGINE #include -#define QWebSettings QWebEngineSettings +typedef QWebEngineSettings QWebSettings; #else #include #endif diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 21a9b8f03..b1020a88c 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -49,6 +49,8 @@ #include #include #include + +typedef QWebEngineHistory QWebHistory; #else #include #include diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 6cd2a223b..9e3b22fb8 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -31,9 +31,16 @@ #include #ifdef USE_WEBENGINE -#define QWebPage QWebEnginePage -#define QWebHistory QWebEngineHistory -#define QWebHistoryItem QWebEngineHistoryItem +class QWebEngineHistory; +class QWebEngineHistoryItem; +class QWebEnginePage; +typedef QWebEngineHistory QWebHistory; +typedef QWebEngineHistoryItem QWebHistoryItem; +typedef QWebEnginePage QWebPage; +#else +class QWebHistory; +class QWebHistoryItem; +class QWebPage; #endif #ifdef USE_APPINDICATOR @@ -45,9 +52,6 @@ class QxtGlobalShortcut; class QSystemTrayIcon; class QTabBar; -class QWebHistory; -class QWebHistoryItem; -class QWebPage; namespace Ui { class MainWindow; diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index dbc6ce695..7f9d46da6 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -46,7 +46,8 @@ #ifdef USE_WEBENGINE #include -#define QWebSettings QWebEngineSettings + +typedef QWebEngineSettings QWebSettings; #else #include #endif diff --git a/src/ui/widgets/searchablewebview.h b/src/ui/widgets/searchablewebview.h index 00a46b162..af0b2e650 100644 --- a/src/ui/widgets/searchablewebview.h +++ b/src/ui/widgets/searchablewebview.h @@ -26,12 +26,15 @@ #include -#ifdef USE_WEBENGINE - #define QWebPage QWebEnginePage -#endif class QLineEdit; + +#ifdef USE_WEBENGINE +class QWebEnginePage; +typedef QWebEnginePage QWebPage; +#else class QWebPage; +#endif class WebView; diff --git a/src/ui/widgets/webview.h b/src/ui/widgets/webview.h index af6ad63fa..4e96248f1 100644 --- a/src/ui/widgets/webview.h +++ b/src/ui/widgets/webview.h @@ -25,12 +25,13 @@ #define WEBVIEW_H #ifdef USE_WEBENGINE - #include - #include - #define QWebView QWebEngineView - #define QWebPage QWebEnginePage +#include +#include + +typedef QWebEnginePage QWebPage; +typedef QWebEngineView QWebView; #else - #include +#include #endif class WebView : public QWebView From 54fe8a4e932497c22be0c9e612b760710295af00 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 12 Apr 2016 02:22:05 -0400 Subject: [PATCH 123/273] core: Fix minimum font size setting not set on app start (fixes #526) --- src/core/settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 39eab496d..3b6892d10 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -92,6 +92,7 @@ void Settings::load() m_settings->beginGroup(GroupBrowser); minimumFontSize = m_settings->value(QStringLiteral("minimum_font_size"), QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumFontSize)).toInt(); + QWebSettings::globalSettings()->setFontSize(QWebSettings::MinimumFontSize, minimumFontSize); m_settings->endGroup(); m_settings->beginGroup(GroupProxy); From c71db8aa1ad35c1c43b4404172b77e8481d6618d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 12 Apr 2016 22:49:29 -0400 Subject: [PATCH 124/273] Do not use Doxygen style for TODO comments --- .../qxtglobalshortcut_win.cpp | 2 +- src/core/application.cpp | 4 ++-- src/core/extractor.cpp | 4 ++-- src/core/settings.cpp | 6 +++--- src/core/settings.h | 13 ++++++------ src/main.cpp | 6 +++--- src/registry/docset.cpp | 20 +++++++++---------- src/registry/docset.h | 2 +- src/registry/docsetmetadata.cpp | 2 +- src/registry/docsetregistry.cpp | 4 ++-- src/registry/listmodel.cpp | 2 +- src/registry/searchmodel.cpp | 2 +- src/registry/searchmodel.h | 2 +- src/registry/searchquery.cpp | 2 +- src/registry/searchresult.h | 2 +- src/ui/mainwindow.cpp | 18 ++++++++--------- src/ui/searchitemdelegate.cpp | 2 +- src/ui/settingsdialog.cpp | 20 +++++++++---------- src/ui/settingsdialog.h | 2 +- src/ui/widgets/searchablewebview.cpp | 6 +++--- src/util/plist.cpp | 4 ++-- src/util/version.h | 2 +- 22 files changed, 64 insertions(+), 63 deletions(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp index 6755ea76a..322a8cf71 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp @@ -83,7 +83,7 @@ quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifier native |= MOD_ALT; if (modifiers & Qt::MetaModifier) native |= MOD_WIN; - /// TODO: resolve these? + // TODO: resolve these? //if (modifiers & Qt::KeypadModifier) //if (modifiers & Qt::GroupSwitchModifier) return native; diff --git a/src/core/application.cpp b/src/core/application.cpp index 82e0450aa..813238929 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -98,7 +98,7 @@ Application::Application(const SearchQuery &query, QObject *parent) : }); // Remove in case previous instance crashed - /// TODO: Verify if removeServer() is needed + // TODO: Verify if removeServer() is needed QLocalServer::removeServer(LocalServerName); m_localServer->listen(LocalServerName); @@ -263,7 +263,7 @@ QString Application::userAgent() QString Application::userAgentJson() const { - /// TODO: [Qt 5.4] Remove else branch + // TODO: [Qt 5.4] Remove else branch #if QT_VERSION >= 0x050400 QJsonObject app = { {QStringLiteral("version"), QCoreApplication::applicationVersion()}, diff --git a/src/core/extractor.cpp b/src/core/extractor.cpp index d7ba769e5..46de0ffbd 100644 --- a/src/core/extractor.cpp +++ b/src/core/extractor.cpp @@ -60,13 +60,13 @@ void Extractor::extract(const QString &filePath, const QString &destination, con if (!root.isEmpty()) destinationDir = destinationDir.absoluteFilePath(root); - /// TODO: Do not strip root directory in archive if it equals to 'root' + // TODO: Do not strip root directory in archive if it equals to 'root' archive_entry *entry; while (archive_read_next_header(info.archiveHandle, &entry) == ARCHIVE_OK) { #ifndef Q_OS_WIN32 QString pathname = QString::fromUtf8(archive_entry_pathname(entry)); #else - /// TODO: Remove once https://github.com/libarchive/libarchive/issues/587 is resolved. + // TODO: Remove once https://github.com/libarchive/libarchive/issues/587 is resolved. QString pathname = QString::fromWCharArray(archive_entry_pathname_w(entry)); #endif if (!root.isEmpty()) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3b6892d10..abf4d2de9 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -57,7 +57,7 @@ Settings::Settings(QObject *parent) : QSettings::IniFormat, this)) #endif { - /// TODO: Move to user style sheet (related to #268) + // TODO: Move to user style sheet (related to #268) #ifndef USE_WEBENGINE QWebSettings::globalSettings() ->setUserStyleSheetUrl(QUrl(QStringLiteral("qrc:///browser/highlight.css"))); @@ -73,7 +73,7 @@ Settings::~Settings() void Settings::load() { - /// TODO: Put everything in groups + // TODO: Put everything in groups startMinimized = m_settings->value(QStringLiteral("start_minimized"), false).toBool(); checkForUpdate = m_settings->value(QStringLiteral("check_for_update"), true).toBool(); @@ -136,7 +136,7 @@ void Settings::load() void Settings::save() { - /// TODO: Put everything in groups + // TODO: Put everything in groups m_settings->setValue(QStringLiteral("start_minimized"), startMinimized); m_settings->setValue(QStringLiteral("check_for_update"), checkForUpdate); diff --git a/src/core/settings.h b/src/core/settings.h index 20cef3dae..c7c30c274 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -35,13 +35,14 @@ class Settings : public QObject { Q_OBJECT public: - /// NOTE: This public members are here just for simplification and should go away - /// once a more advanced settings management come in place. + /* This public members are here just for simplification and should go away + * once a more advanced settings management come in place. + */ // Startup bool startMinimized; bool checkForUpdate; - /// TODO: bool restoreLastState; + // TODO: bool restoreLastState; // System Tray bool showSystrayIcon; @@ -50,12 +51,12 @@ class Settings : public QObject // Global Shortcuts QKeySequence showShortcut; - /// TODO: QKeySequence searchSelectedTextShortcut; + // TODO: QKeySequence searchSelectedTextShortcut; // Browser int minimumFontSize; - /// TODO: bool askOnExternalLink; - /// TODO: QString customCss; + // TODO: bool askOnExternalLink; + // TODO: QString customCss; // Network enum ProxyType : unsigned int { diff --git a/src/main.cpp b/src/main.cpp index 87c481266..98842eac9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,7 +67,7 @@ CommandLineParameters parseCommandLine(const QStringList &arguments) parser.addHelpOption(); parser.addVersionOption(); - /// TODO: [Qt 5.4] parser.addOption({{"f", "force"}, "Force the application run."}); + // TODO: [Qt 5.4] parser.addOption({{"f", "force"}, "Force the application run."}); parser.addOption(QCommandLineOption({QStringLiteral("f"), QStringLiteral("force")}, QObject::tr("Force the application run."))); @@ -94,7 +94,7 @@ CommandLineParameters parseCommandLine(const QStringList &arguments) } #endif - /// TODO: Support dash-feed:// protocol + // TODO: Support dash-feed:// protocol const QString arg = QUrl::fromPercentEncoding(parser.positionalArguments().value(0).toUtf8()); if (arg.startsWith(QLatin1String("dash:"))) { @@ -196,7 +196,7 @@ int main(int argc, char *argv[]) return 0; // Check for SQLite plugin - /// TODO: Specific to docset format and should be handled accordingly in the future + // TODO: Specific to docset format and should be handled accordingly in the future if (!QSqlDatabase::isDriverAvailable(QStringLiteral("QSQLITE"))) { const int ret = QMessageBox::critical(nullptr, QStringLiteral("Zeal"), QObject::tr("Qt SQLite driver is not available."), diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index df920b37c..03e7744fa 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -71,13 +71,13 @@ Docset::Docset(const QString &path) : break; } - /// TODO: Report errors here and below + // TODO: Report errors here and below if (!dir.cd(QStringLiteral("Contents"))) return; - /// TODO: 'info.plist' is invalid according to Apple, and must alsways be 'Info.plist' - /// https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPRuntimeConfig/ - /// Articles/ConfigFiles.html + // TODO: 'info.plist' is invalid according to Apple, and must alsways be 'Info.plist' + // https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPRuntimeConfig + // /Articles/ConfigFiles.html Util::Plist plist; if (dir.exists(QStringLiteral("Info.plist"))) plist.read(dir.absoluteFilePath(QStringLiteral("Info.plist"))); @@ -93,7 +93,7 @@ Docset::Docset(const QString &path) : // Fallback if meta.json is absent if (!plist.contains(InfoPlist::CFBundleName)) { m_name = m_title = plist[InfoPlist::CFBundleName].toString(); - /// TODO: Remove when MainWindow::docsetName() will not use directory name + // TODO: Remove when MainWindow::docsetName() will not use directory name m_name.replace(QLatin1Char(' '), QLatin1Char('_')); } else { m_name = QFileInfo(m_path).fileName().remove(QStringLiteral(".docset")); @@ -105,7 +105,7 @@ Docset::Docset(const QString &path) : m_title.replace(QLatin1Char('_'), QLatin1Char(' ')); } - /// TODO: Verify if this is needed + // TODO: Verify if this is needed if (plist.contains(InfoPlist::DashDocSetFamily) && plist[InfoPlist::DashDocSetFamily].toString() == QLatin1String("cheatsheet")) { m_name = m_name + QLatin1String("cheats"); @@ -145,7 +145,7 @@ Docset::Docset(const QString &path) : m_keywords << kw; } - /// TODO: Use 'unknown' instead of CFBundleName? (See #383) + // TODO: Use 'unknown' instead of CFBundleName? (See #383) m_keywords << plist.value(InfoPlist::CFBundleName, m_name).toString().toLower(); // Try to find index path if metadata is missing one @@ -302,7 +302,7 @@ QList Docset::search(const QString &query) const path += QLatin1Char('#') + anchor; } - /// TODO: Third should be type + // TODO: Third should be type results.append(SearchResult{itemName, QString(), parseSymbolType(query.value(1).toString()), const_cast(this), path, sanitizedQuery}); @@ -423,7 +423,7 @@ void Docset::countSymbols() } } -/// TODO: Fetch and cache only portions of symbols +// TODO: Fetch and cache only portions of symbols void Docset::loadSymbols(const QString &symbolType) const { for (const QString &symbol : m_symbolStrings.values(symbolType)) @@ -499,7 +499,7 @@ void Docset::createIndex() QString Docset::parseSymbolType(const QString &str) { - /// Dash symbol aliases + // Dash symbol aliases const static QHash aliases = { // Attribute {QStringLiteral("Package Attributes"), QStringLiteral("Attribute")}, diff --git a/src/registry/docset.h b/src/registry/docset.h index 66e311d5f..1aab534cd 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -62,7 +62,7 @@ class Docset QList search(const QString &query) const; QList relatedLinks(const QUrl &url) const; - /// FIXME: This is an ugly workaround before we have a proper docset sources implementation + // FIXME: This is an ugly workaround before we have a proper docset sources implementation bool hasUpdate = false; private: diff --git a/src/registry/docsetmetadata.cpp b/src/registry/docsetmetadata.cpp index d8de96f05..9b3c5a0ce 100644 --- a/src/registry/docsetmetadata.cpp +++ b/src/registry/docsetmetadata.cpp @@ -48,7 +48,7 @@ DocsetMetadata::DocsetMetadata(const QJsonObject &jsonObject) m_rawIcon2x = QByteArray::fromBase64(jsonObject[QStringLiteral("icon2x")].toString() .toLocal8Bit()); - /// TODO: Check on a high-resolution screen + // TODO: Check on a high-resolution screen if (qApp->devicePixelRatio() > 1.0) { QPixmap pixmap = QPixmap::fromImage(QImage::fromData(m_rawIcon2x)); pixmap.setDevicePixelRatio(2.0); diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index 8a98f6a35..b9a26298c 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -37,7 +37,7 @@ DocsetRegistry::DocsetRegistry(QObject *parent) : // Register for use in signal connections. qRegisterMetaType>("QList"); - /// FIXME: Only search should be performed in a separate thread + // FIXME: Only search should be performed in a separate thread moveToThread(m_thread); m_thread->start(); } @@ -106,7 +106,7 @@ void DocsetRegistry::_addDocset(const QString &path) { Docset *docset = new Docset(path); - /// TODO: Emit error + // TODO: Emit error if (!docset->isValid()) { qWarning("Could not load docset from '%s'. Please reinstall the docset.", qPrintable(path)); delete docset; diff --git a/src/registry/listmodel.cpp b/src/registry/listmodel.cpp index cdf4c59c0..a83be84e6 100644 --- a/src/registry/listmodel.cpp +++ b/src/registry/listmodel.cpp @@ -193,7 +193,7 @@ void ListModel::addDocset(const QString &name) void ListModel::removeDocset(const QString &name) { const int index = m_docsetItems.keys().indexOf(name); - /// TODO: Investigate why this can happen (see #420) + // TODO: Investigate why this can happen (see #420) if (index == -1) return; diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index 04572a25c..e43433ce1 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -77,7 +77,7 @@ QModelIndex SearchModel::index(int row, int column, const QModelIndex &parent) c if (parent.isValid() || m_dataList.count() <= row || column > 1) return QModelIndex(); - /// FIXME: const_cast + // FIXME: const_cast SearchResult *item = const_cast(&m_dataList.at(row)); return createIndex(row, column, item); } diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index 0b3fe32cc..d4e821dc3 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -34,7 +34,7 @@ class SearchModel : public QAbstractItemModel { Q_OBJECT public: - /// TODO: Standardise roles across app + // TODO: Standardise roles across app enum ItemDataRole { DocsetIconRole = Qt::UserRole }; diff --git a/src/registry/searchquery.cpp b/src/registry/searchquery.cpp index b9be73f9a..05b27fd3d 100644 --- a/src/registry/searchquery.cpp +++ b/src/registry/searchquery.cpp @@ -94,7 +94,7 @@ bool SearchQuery::hasKeywords() const bool SearchQuery::hasKeyword(const QString &keyword) const { // Temporary workaround for #333 - /// TODO: Remove once #167 is implemented + // TODO: Remove once #167 is implemented for (const QString &kw : m_keywords) { if (keyword.startsWith(kw, Qt::CaseInsensitive)) return true; diff --git a/src/registry/searchresult.h b/src/registry/searchresult.h index bff87f878..a5125c628 100644 --- a/src/registry/searchresult.h +++ b/src/registry/searchresult.h @@ -40,7 +40,7 @@ struct SearchResult QString path; - /// TODO: Remove + // TODO: Remove QString query; bool operator<(const SearchResult &r) const; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index b1020a88c..af972bec3 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -59,7 +59,7 @@ typedef QWebEngineHistory QWebHistory; #include -/// TODO: [Qt 5.5] Remove in favour of native Qt support (QTBUG-31762) +// TODO: [Qt 5.5] Remove in favour of native Qt support (QTBUG-31762) #ifdef USE_APPINDICATOR #undef signals #include @@ -107,7 +107,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : restoreGeometry(m_settings->windowGeometry); ui->splitter->restoreState(m_settings->verticalSplitterGeometry); - /// TODO: Custom headers and URL scheme for Qt WebEngine. + // TODO: Custom headers and URL scheme for Qt WebEngine. #ifndef USE_WEBENGINE ui->webView->page()->setNetworkAccessManager(m_application->networkManager()); #endif @@ -257,7 +257,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : tabState->webPage->mainFrame()->load(QUrl(startPageUrl)); #endif - /// TODO: Cleanup history + // TODO: Cleanup history } }); @@ -312,7 +312,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_tabBar->setCurrentIndex((m_tabBar->currentIndex() + 1) % m_tabBar->count()); }); - /// TODO: Use QKeySequence::PreviousChild, when QTBUG-15746 is fixed. + // TODO: Use QKeySequence::PreviousChild, when QTBUG-15746 is fixed. ui->actionPreviousTab->setShortcut(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Tab); addAction(ui->actionPreviousTab); connect(ui->actionPreviousTab, &QAction::triggered, [this]() { @@ -357,11 +357,11 @@ void MainWindow::openDocset(const QModelIndex &index) if (urlStr.isNull()) return; - /// TODO: Keep anchor separately from file address + // TODO: Keep anchor separately from file address QStringList urlParts = urlStr.toString().split(QLatin1Char('#')); QUrl url = QUrl::fromLocalFile(urlParts[0]); if (urlParts.count() > 1) - /// NOTE: QUrl::DecodedMode is a fix for #121. Let's hope it doesn't break anything. + // NOTE: QUrl::DecodedMode is a fix for #121. Let's hope it doesn't break anything. url.setFragment(urlParts[1], QUrl::DecodedMode); ui->webView->load(url); @@ -413,7 +413,7 @@ void MainWindow::closeTab(int index) if (index == -1) return; - /// TODO: proper deletion here + // TODO: proper deletion here TabState *state = m_tabStates.takeAt(index); if (m_currentTabState == state) @@ -675,7 +675,7 @@ void MainWindow::createTrayIcon() gtk_widget_show_all(m_appIndicatorMenu); - /// NOTE: Zeal icon has to be installed, otherwise app indicator won't be shown + // NOTE: Zeal icon has to be installed, otherwise app indicator won't be shown m_appIndicator = app_indicator_new("zeal", "zeal", APP_INDICATOR_CATEGORY_OTHER); app_indicator_set_status(m_appIndicator, APP_INDICATOR_STATUS_ACTIVE); @@ -775,7 +775,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) break; } case QEvent::Wheel: - /// TODO: Remove in case QTBUG-8428 is fixed on all platforms + // TODO: Remove in case QTBUG-8428 is fixed on all platforms return true; default: break; diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 994ee9985..e2e28bb46 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -73,7 +73,7 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op roles.append(role); } - /// TODO: Implemented via initStyleOption() overload + // TODO: Implemented via initStyleOption() overload if (!roles.isEmpty()) { opt.features |= QStyleOptionViewItem::HasDecoration; opt.icon = index.data(roles.first()).value(); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 7f9d46da6..6c83dd400 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -57,10 +57,10 @@ using namespace Zeal; namespace { const char ApiServerUrl[] = "http://api.zealdocs.org/v1"; const char RedirectServerUrl[] = "http://go.zealdocs.org"; -/// TODO: Each source plugin should have its own cache +// TODO: Each source plugin should have its own cache const char DocsetListCacheFileName[] = "com.kapeli.json"; -/// TODO: Make the timeout period configurable +// TODO: Make the timeout period configurable constexpr int CacheTimeout = 24 * 60 * 60 * 1000; // 24 hours in microseconds // QNetworkReply properties @@ -281,7 +281,7 @@ void SettingsDialog::downloadCompleted() if (redirectUrl.isRelative()) redirectUrl = reply->request().url().resolved(redirectUrl); - /// TODO: Verify if scheme can be missing + // TODO: Verify if scheme can be missing if (redirectUrl.scheme().isEmpty()) redirectUrl.setScheme(reply->request().url().scheme()); @@ -345,7 +345,7 @@ void SettingsDialog::downloadCompleted() ? m_availableDocsets[docsetName] : m_userFeeds[docsetName]; - /// TODO: Implement an explicit and verbose docset update logic + // TODO: Implement an explicit and verbose docset update logic QDir dir(m_application->settings()->docsetPath); const QString docsetDirName = docsetName + QLatin1String(".docset"); if (dir.exists(docsetDirName)) { @@ -437,7 +437,7 @@ void SettingsDialog::extractionCompleted(const QString &filePath) { QString docsetName; - /// FIXME: Come up with a better approach + // FIXME: Come up with a better approach for (const QString &key : m_tmpFiles.keys()) { if (m_tmpFiles[key]->fileName() == filePath) { docsetName = key; @@ -471,7 +471,7 @@ void SettingsDialog::extractionError(const QString &filePath, const QString &err const QString docsetName = QFileInfo(filePath).baseName() + QLatin1String(".docset"); QMessageBox::warning(this, tr("Extraction Error"), QString(tr("Cannot extract docset %1: %2")).arg(docsetName, errorString)); - /// TODO: Update list item state (hide progress bar) + // TODO: Update list item state (hide progress bar) delete m_tmpFiles.take(docsetName); } @@ -479,7 +479,7 @@ void SettingsDialog::extractionProgress(const QString &filePath, qint64 extracte { QString docsetName; - /// FIXME: Come up with a better approach + // FIXME: Come up with a better approach for (const QString &key : m_tmpFiles.keys()) { if (m_tmpFiles[key]->fileName() == filePath) { docsetName = key; @@ -551,7 +551,7 @@ void SettingsDialog::on_tabWidget_currentChanged(int current) return; } - /// TODO: Show more user friendly labels, like "5 hours ago" + // TODO: Show more user friendly labels, like "5 hours ago" ui->lastUpdatedLabel->setText(fi.lastModified().toString(Qt::SystemLocaleShortDate)); processDocsetList(jsonDoc.array()); } @@ -635,7 +635,7 @@ void SettingsDialog::processDocsetList(const QJsonArray &list) m_availableDocsets.insert(metadata.name(), metadata); } - /// TODO: Move into dedicated method + // TODO: Move into dedicated method for (const DocsetMetadata &metadata : m_availableDocsets) { QListWidgetItem *listItem = new QListWidgetItem(metadata.icon(), metadata.title(), ui->availableDocsetList); @@ -839,7 +839,7 @@ QString SettingsDialog::cacheLocation(const QString &fileName) #else const QDir cacheDir(QCoreApplication::applicationDirPath() + QLatin1String("/cache")); #endif - /// TODO: Report error + // TODO: Report error QDir().mkpath(cacheDir.path()); return cacheDir.filePath(fileName); diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 605867fc1..6ad1cb267 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -87,7 +87,7 @@ private slots: qint64 m_combinedTotal = 0; qint64 m_combinedReceived = 0; - /// TODO: Create a special model + // TODO: Create a special model QMap m_availableDocsets; QMap m_userFeeds; diff --git a/src/ui/widgets/searchablewebview.cpp b/src/ui/widgets/searchablewebview.cpp index fbf2cbb12..d08eb09b5 100644 --- a/src/ui/widgets/searchablewebview.cpp +++ b/src/ui/widgets/searchablewebview.cpp @@ -191,8 +191,8 @@ void SearchableWebView::hideSearch() void SearchableWebView::find(const QString &text) { #ifdef USE_WEBENGINE - /// FIXME: There's no way to just show highlight when search term is already selected. - /// So we need a workaround before switching to Qt WebEngine. + // FIXME: There's no way to just show highlight when search term is already selected. + // So we need a workaround before switching to Qt WebEngine. m_webView->findText(text); #else if (m_webView->selectedText() != text) { @@ -224,7 +224,7 @@ void SearchableWebView::moveLineEdit() { int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); #ifdef USE_WEBENGINE - /// FIXME: scrollbar width + // FIXME: scrollbar width #else frameWidth += m_webView->page()->currentFrame()->scrollBarGeometry(Qt::Vertical).width(); #endif diff --git a/src/util/plist.cpp b/src/util/plist.cpp index dbf923d13..d77098859 100644 --- a/src/util/plist.cpp +++ b/src/util/plist.cpp @@ -36,7 +36,7 @@ bool Plist::read(const QString &fileName) { QScopedPointer file(new QFile(fileName)); if (!file->open(QIODevice::ReadOnly)) { - /// TODO: Report/log error + // TODO: Report/log error m_hasError = true; return false; } @@ -49,7 +49,7 @@ bool Plist::read(const QString &fileName) continue; if (xml.name() != QLatin1String("key")) - continue; /// TODO: Should it fail here? + continue; // TODO: Should it fail here? const QString key = xml.readElementText(); diff --git a/src/util/version.h b/src/util/version.h index 90373c9eb..f06d73930 100644 --- a/src/util/version.h +++ b/src/util/version.h @@ -29,7 +29,7 @@ namespace Zeal { namespace Util { // Based on Semantic Versioning (http://semver.org/) -/// TODO: Add support for prerelease tags and build metadata +// TODO: Add support for prerelease tags and build metadata class Version { From 9f2c4b7650a76965388d3665faef46cc3518271f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 12 Apr 2016 22:53:24 -0400 Subject: [PATCH 125/273] ui: Move File->Options to Edit->Preferences --- src/ui/forms/mainwindow.ui | 12 +++++++++--- src/ui/mainwindow.cpp | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index b4bffba93..cb59ac318 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -205,7 +205,6 @@ - @@ -226,7 +225,14 @@ + + + &Edit + + + + @@ -235,9 +241,9 @@ &Quit - + - &Options + Prefere&nces diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index af972bec3..10faacae1 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -123,7 +123,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } connect(ui->actionQuit, &QAction::triggered, qApp, &QCoreApplication::quit); - connect(ui->actionOptions, &QAction::triggered, [this]() { + connect(ui->actionPreferences, &QAction::triggered, [this]() { m_globalShortcut->setEnabled(false); QScopedPointer dialog(new SettingsDialog(m_application, this)); dialog->exec(); From 3ddb171bf3af9fb37777d02df1047a84b78fb2de Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 12 Apr 2016 23:08:25 -0400 Subject: [PATCH 126/273] ui: Expose SearchableWebView's search bar toggling methods --- src/ui/widgets/searchablewebview.cpp | 46 ++++++++++++++-------------- src/ui/widgets/searchablewebview.h | 4 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/ui/widgets/searchablewebview.cpp b/src/ui/widgets/searchablewebview.cpp index d08eb09b5..1da6f458c 100644 --- a/src/ui/widgets/searchablewebview.cpp +++ b/src/ui/widgets/searchablewebview.cpp @@ -51,7 +51,7 @@ SearchableWebView::SearchableWebView(QWidget *parent) : connect(m_searchLineEdit, &QLineEdit::textChanged, this, &SearchableWebView::find); QShortcut *shortcut = new QShortcut(QKeySequence::Find, this); - connect(shortcut, &QShortcut::activated, this, &SearchableWebView::showSearch); + connect(shortcut, &QShortcut::activated, this, &SearchableWebView::showSearchBar); connect(m_webView, &QWebView::loadFinished, [&](bool ok) { Q_UNUSED(ok) @@ -94,7 +94,7 @@ bool SearchableWebView::eventFilter(QObject *object, QEvent *event) QKeyEvent *keyEvent = reinterpret_cast(event); switch (keyEvent->key()) { case Qt::Key_Escape: - hideSearch(); + hideSearchBar(); return true; case Qt::Key_Enter: case Qt::Key_Return: @@ -138,6 +138,26 @@ void SearchableWebView::forward() m_webView->forward(); } +void SearchableWebView::showSearchBar() +{ + m_searchLineEdit->show(); + m_searchLineEdit->setFocus(); + if (!m_searchLineEdit->text().isEmpty()) { + m_searchLineEdit->selectAll(); + find(m_searchLineEdit->text()); + } +} + +void SearchableWebView::hideSearchBar() +{ + m_searchLineEdit->hide(); +#ifdef USE_WEBENGINE + m_webView->findText(QString()); +#else + m_webView->findText(QString(), QWebPage::HighlightAllOccurrences); +#endif +} + bool SearchableWebView::canGoBack() const { return m_webView->history()->canGoBack(); @@ -152,7 +172,7 @@ void SearchableWebView::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Slash: - showSearch(); + showSearchBar(); event->accept(); break; default: @@ -168,26 +188,6 @@ void SearchableWebView::resizeEvent(QResizeEvent *event) moveLineEdit(); } -void SearchableWebView::showSearch() -{ - m_searchLineEdit->show(); - m_searchLineEdit->setFocus(); - if (!m_searchLineEdit->text().isEmpty()) { - m_searchLineEdit->selectAll(); - find(m_searchLineEdit->text()); - } -} - -void SearchableWebView::hideSearch() -{ - m_searchLineEdit->hide(); -#ifdef USE_WEBENGINE - m_webView->findText(QString()); -#else - m_webView->findText(QString(), QWebPage::HighlightAllOccurrences); -#endif -} - void SearchableWebView::find(const QString &text) { #ifdef USE_WEBENGINE diff --git a/src/ui/widgets/searchablewebview.h b/src/ui/widgets/searchablewebview.h index af0b2e650..557e18e6e 100644 --- a/src/ui/widgets/searchablewebview.h +++ b/src/ui/widgets/searchablewebview.h @@ -65,14 +65,14 @@ class SearchableWebView : public QWidget public slots: void back(); void forward(); + void showSearchBar(); + void hideSearchBar(); protected: void keyPressEvent(QKeyEvent *event) override; void resizeEvent(QResizeEvent *event) override; private: - void showSearch(); - void hideSearch(); void find(const QString &text); void findNext(const QString &text, bool backward = false); void moveLineEdit(); From 5c17e4b560e29df49be551d67549af0e25dffd6b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 12 Apr 2016 23:12:04 -0400 Subject: [PATCH 127/273] ui: Add Edit->Find menu item --- src/ui/forms/mainwindow.ui | 7 +++++++ src/ui/mainwindow.cpp | 7 ++++++- src/ui/widgets/searchablewebview.cpp | 4 ---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index cb59ac318..7ae06e835 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -229,6 +229,8 @@ &Edit + + @@ -296,6 +298,11 @@ &Check for updates... + + + &Find + + diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 10faacae1..77d19597d 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -112,7 +112,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->webView->page()->setNetworkAccessManager(m_application->networkManager()); #endif - // menu + // Menu + // File if (QKeySequence(QKeySequence::Quit) != QKeySequence(QStringLiteral("Ctrl+Q"))) { ui->actionQuit->setShortcuts(QList{QKeySequence(QStringLiteral("Ctrl+Q")), QKeySequence::Quit}); @@ -123,6 +124,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } connect(ui->actionQuit, &QAction::triggered, qApp, &QCoreApplication::quit); + // Edit + ui->actionFind->setShortcut(QKeySequence::Find); + connect(ui->actionFind, &QAction::triggered, ui->webView, &SearchableWebView::showSearchBar); + connect(ui->actionPreferences, &QAction::triggered, [this]() { m_globalShortcut->setEnabled(false); QScopedPointer dialog(new SettingsDialog(m_application, this)); diff --git a/src/ui/widgets/searchablewebview.cpp b/src/ui/widgets/searchablewebview.cpp index 1da6f458c..1125598b9 100644 --- a/src/ui/widgets/searchablewebview.cpp +++ b/src/ui/widgets/searchablewebview.cpp @@ -26,7 +26,6 @@ #include "webview.h" #include -#include #include #include @@ -50,9 +49,6 @@ SearchableWebView::SearchableWebView(QWidget *parent) : m_searchLineEdit->installEventFilter(this); connect(m_searchLineEdit, &QLineEdit::textChanged, this, &SearchableWebView::find); - QShortcut *shortcut = new QShortcut(QKeySequence::Find, this); - connect(shortcut, &QShortcut::activated, this, &SearchableWebView::showSearchBar); - connect(m_webView, &QWebView::loadFinished, [&](bool ok) { Q_UNUSED(ok) moveLineEdit(); From 5bca1fcf7cbced797d824ded0067c4c39a83ad5f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 12 Apr 2016 23:18:15 -0400 Subject: [PATCH 128/273] ui: Fix double separator in the File menu --- src/ui/forms/mainwindow.ui | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 7ae06e835..25dbf25ab 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -205,7 +205,6 @@ - From fcefbf222b8a3bced919a6248dd9c737f32a3c72 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 13 Apr 2016 00:14:32 -0400 Subject: [PATCH 129/273] ui: Set FreeDesktop icons for menu actions --- src/ui/forms/mainwindow.ui | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 25dbf25ab..9906b1fd6 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -238,16 +238,25 @@ + + + &Quit + + + Prefere&nces + + + About &Zeal @@ -268,6 +277,9 @@ + + + New &Tab @@ -298,6 +310,9 @@ + + + &Find From e7062cd2d9c50f8b096fb10b5c03bf76aa6b4564 Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Mon, 11 Apr 2016 22:21:18 -0700 Subject: [PATCH 130/273] ui: Fix rename tocView to tocListView --- src/ui/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 77d19597d..ce5624785 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -326,7 +326,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : #ifdef Q_OS_OSX ui->treeView->setAttribute(Qt::WA_MacShowFocusRect, false); - ui->tocView->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->tocListView->setAttribute(Qt::WA_MacShowFocusRect, false); #endif if (m_settings->checkForUpdate) From fefa9f8af2f1060b24d6ca9fe95fb2a15bbc7c22 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 15 Apr 2016 00:59:25 -0400 Subject: [PATCH 131/273] resources: Add Pattern type icon --- src/resources/icons/type/Pattern.png | Bin 0 -> 420 bytes src/resources/icons/type/Pattern@2x.png | Bin 0 -> 813 bytes src/resources/zeal.qrc | 2 ++ 3 files changed, 2 insertions(+) create mode 100644 src/resources/icons/type/Pattern.png create mode 100644 src/resources/icons/type/Pattern@2x.png diff --git a/src/resources/icons/type/Pattern.png b/src/resources/icons/type/Pattern.png new file mode 100644 index 0000000000000000000000000000000000000000..25c6a615e4e9a95b72b94b535250e36c17e502f0 GIT binary patch literal 420 zcmV;V0bBlwP)9l)%EH!Na7etA)eFrLMA#_V@Gu|Nr#$ z@6OS>v$m6`s)fPCq^z)wxV)Xn%d`9Y`KPIbtFMf%vXG~$gsZTN#mKJWs;-Fe z@#($4ovE#dq^E$evyZ#Jo1>L;#2d9Y_EG z010qNS#tmY3ljhU3ljkVnw%H_004YRL_t&t9Yw)Q4goL#ip*Z zjQp{J{c!o{Vnv5olo_QAxcwYiq3s)fPCq^z)w<>uPByq&wgq0rL4@$&2H z>*3<#*0s5r!NR1hu#Dm3)~>RTt+9^e=GwBgl&7hLz`>)duZ!X1)!^dO-QUlqs)WD7 zqN}iq?Cs>t&$!>=(zLjjrm2IguZsQs{O9T3x4WCJv5mgLq4V_a)z`$p!=}5wo~5aR zzQLffwvxTTpQWgRzQCZXu8OR$i?Fkhv9yu4xR$)Woxi}JtFDQ#vyQ8-h@_{2zQCWV zu86O*j-;o7zQCUF@#)>(&abkKy}zBQt%tq7ousFLwYZd{r+}!eg|xVoyuY2gzMG?_ ze-(@54gdfE2XsKNm~L4ft^GWA zg$IgD#9wM0a(C}L=etYXsFfgKN&mn&Hf93=mTZ^JQ=fsF1c52}*7Ur8G@;dOiwVBK zi{$S3*+0w*057juW#iZ5KR}&0#SL7aaLei0VFj&9Z~-ooBwGV$#f*SC2h4zt0tPTN z08pobfH4OEl%cAsir3xGEvl-js;a80io$|7j9;GsV5b=H33xRCfV`7E005|#dYc3Q rfE>C%Ru%vNz(`_|_W%IkL+}0r{7+X=crCaf00000NkvXXu0mjf)>y7o literal 0 HcmV?d00001 diff --git a/src/resources/zeal.qrc b/src/resources/zeal.qrc index 862ab3979..b61104e47 100644 --- a/src/resources/zeal.qrc +++ b/src/resources/zeal.qrc @@ -140,6 +140,8 @@ icons/type/Package@2x.png icons/type/Parameter.png icons/type/Parameter@2x.png + icons/type/Pattern.png + icons/type/Pattern@2x.png icons/type/Plugin.png icons/type/Plugin@2x.png icons/type/Procedure.png From a0b457adaf56d5937534074cdda04901109c565a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Fri, 15 Apr 2016 01:13:07 -0400 Subject: [PATCH 132/273] ui: Cleanup headers --- src/ui/mainwindow.cpp | 2 -- src/ui/settingsdialog.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ce5624785..68e62a325 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -33,7 +33,6 @@ #include "registry/listmodel.h" #include "registry/searchmodel.h" -#include #include #include #include @@ -43,7 +42,6 @@ #include #include #include -#include #ifdef USE_WEBENGINE #include diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 6c83dd400..580ff405e 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -22,10 +22,10 @@ ****************************************************************************/ #include "settingsdialog.h" +#include "ui_settingsdialog.h" #include "docsetlistitemdelegate.h" #include "progressitemdelegate.h" -#include "ui_settingsdialog.h" #include "core/application.h" #include "core/settings.h" #include "registry/docsetregistry.h" From 2d96d6e8421bf49db10caa04999ec1a7b834fc0b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 16 Apr 2016 22:32:14 -0400 Subject: [PATCH 133/273] core: Add Core::Application::instance() method --- src/core/application.cpp | 10 ++++++++++ src/core/application.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/core/application.cpp b/src/core/application.cpp index 813238929..c86c13874 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -137,6 +137,16 @@ Application::~Application() delete m_docsetRegistry; } +/*! + * \internal + * \brief Returns a pointer to the Core::Application instance. + * If no instance has been created, then \c nullptr is returned. + */ +Application *Application::instance() +{ + return m_instance; +} + /*! * \internal * \brief Hands over \a query to already running application instance, if it exists. diff --git a/src/core/application.h b/src/core/application.h index 8fb34d270..7b47805f8 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -50,6 +50,8 @@ class Application : public QObject explicit Application(const SearchQuery &query, QObject *parent = nullptr); ~Application() override; + static Application *instance(); + static bool send(const SearchQuery &query, bool preventActivation); QNetworkAccessManager *networkManager() const; From 04e4ee37483edd15204ae8e6d2bd73941e7cf53f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 16 Apr 2016 23:13:08 -0400 Subject: [PATCH 134/273] app, ui: Unify and improve message boxes --- src/main.cpp | 2 +- src/ui/mainwindow.cpp | 6 +++--- src/ui/settingsdialog.cpp | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 98842eac9..6a3a42e46 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) if (!QSqlDatabase::isDriverAvailable(QStringLiteral("QSQLITE"))) { const int ret = QMessageBox::critical(nullptr, QStringLiteral("Zeal"), QObject::tr("Qt SQLite driver is not available."), - QMessageBox::Close, QMessageBox::Help); + QMessageBox::Close | QMessageBox::Help); if (ret == QMessageBox::Help) QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/contact.html"))); return 0; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 68e62a325..c362843e8 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -162,13 +162,13 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_application, &Core::Application::updateCheckDone, [this](const QString &version) { if (version.isEmpty()) { QMessageBox::information(this, QStringLiteral("Zeal"), - tr("You are using the latest version of Zeal.")); + tr("You are using the latest version.")); return; } const int ret = QMessageBox::information(this, QStringLiteral("Zeal"), - QString(tr("A new version %1 is available. Open download page?")).arg(version), - QMessageBox::Yes, QMessageBox::No); + QString(tr("Zeal %1 is available. Open download page?")).arg(version), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (ret == QMessageBox::Yes) QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/download.html"))); }); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 580ff405e..b5ba94af3 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -199,12 +199,12 @@ void SettingsDialog::removeSelectedDocsets() int ret; if (selectonModel->selectedIndexes().count() == 1) { const QString docsetTitle = selectonModel->selectedIndexes().first().data().toString(); - ret = QMessageBox::question(this, tr("Remove Docset"), - QString(tr("Do you really want to remove %1 docset?")) + ret = QMessageBox::question(this, QStringLiteral("Zeal"), + QString(tr("Remove %1 docset?")) .arg(docsetTitle)); } else { - ret = QMessageBox::question(this, tr("Remove Docsets"), - QString(tr("Do you really want to remove %1 docsets?")) + ret = QMessageBox::question(this, QStringLiteral("Zeal"), + QString(tr("Remove %1 docsets?")) .arg(selectonModel->selectedIndexes().count())); } @@ -246,7 +246,7 @@ void SettingsDialog::downloadCompleted() if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::OperationCanceledError) { - const int ret = QMessageBox::warning(this, tr("Network Error"), reply->errorString(), + const int ret = QMessageBox::warning(this, QStringLiteral("Zeal"), reply->errorString(), QMessageBox::Ok | QMessageBox::Retry); if (ret == QMessageBox::Retry) { @@ -312,7 +312,7 @@ void SettingsDialog::downloadCompleted() const QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); if (jsonError.error != QJsonParseError::NoError) { - QMessageBox::warning(this, tr("Error"), + QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Corrupted docset list: ") + jsonError.errorString()); break; } @@ -327,7 +327,7 @@ void SettingsDialog::downloadCompleted() = DocsetMetadata::fromDashFeed(reply->request().url(), reply->readAll()); if (metadata.urls().isEmpty()) { - QMessageBox::critical(this, QStringLiteral("Zeal"), tr("Invalid docset feed!")); + QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Invalid docset feed!")); break; } @@ -469,7 +469,7 @@ void SettingsDialog::extractionCompleted(const QString &filePath) void SettingsDialog::extractionError(const QString &filePath, const QString &errorString) { const QString docsetName = QFileInfo(filePath).baseName() + QLatin1String(".docset"); - QMessageBox::warning(this, tr("Extraction Error"), + QMessageBox::warning(this, QStringLiteral("Zeal"), QString(tr("Cannot extract docset %1: %2")).arg(docsetName, errorString)); // TODO: Update list item state (hide progress bar) delete m_tmpFiles.take(docsetName); @@ -698,7 +698,7 @@ void SettingsDialog::removeDocsets(const QStringList &names) watcher->setFuture(future); connect(watcher, &QFutureWatcher::finished, [=] { if (!watcher->result()) { - QMessageBox::warning(this, tr("Error"), + QMessageBox::warning(this, QStringLiteral("Zeal"), QString(tr("Cannot delete docset %1!")).arg(title)); } From 8b745598e901c5825808f3014bf808306ab3176a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 16 Apr 2016 23:14:03 -0400 Subject: [PATCH 135/273] ui: Fix coding style in SettingsDialog --- src/ui/settingsdialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index b5ba94af3..5f11f11c3 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -835,12 +835,12 @@ int SettingsDialog::percent(qint64 fraction, qint64 total) QString SettingsDialog::cacheLocation(const QString &fileName) { #ifndef PORTABLE_BUILD - const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); + const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); #else - const QDir cacheDir(QCoreApplication::applicationDirPath() + QLatin1String("/cache")); + const QDir cacheDir(QCoreApplication::applicationDirPath() + QLatin1String("/cache")); #endif - // TODO: Report error - QDir().mkpath(cacheDir.path()); + // TODO: Report error + QDir().mkpath(cacheDir.path()); - return cacheDir.filePath(fileName); + return cacheDir.filePath(fileName); } From 334e8971957629aece9971eb3045b920d7435fdf Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 16 Apr 2016 23:26:06 -0400 Subject: [PATCH 136/273] ui: Use Ctrl+Q only if QKeySequence::Quit is empty --- src/ui/mainwindow.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c362843e8..80d45a945 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -112,14 +112,12 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : // Menu // File - if (QKeySequence(QKeySequence::Quit) != QKeySequence(QStringLiteral("Ctrl+Q"))) { - ui->actionQuit->setShortcuts(QList{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::Quit}); - } + // Some platform plugins do not define QKeySequence::Quit. + if (QKeySequence(QKeySequence::Quit).isEmpty()) + ui->actionQuit->setShortcut(QStringLiteral("Ctrl+Q")); + else + ui->actionQuit->setShortcut(QKeySequence::Quit); + connect(ui->actionQuit, &QAction::triggered, qApp, &QCoreApplication::quit); // Edit From e0381f47c14ea0252cab698d9bc5870c9f48ed46 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 17 Apr 2016 02:41:17 -0400 Subject: [PATCH 137/273] ui: Switch to HTTPS for go.zealdocs.org --- src/ui/settingsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 5f11f11c3..df65eb637 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -56,7 +56,7 @@ using namespace Zeal; namespace { const char ApiServerUrl[] = "http://api.zealdocs.org/v1"; -const char RedirectServerUrl[] = "http://go.zealdocs.org"; +const char RedirectServerUrl[] = "https://go.zealdocs.org"; // TODO: Each source plugin should have its own cache const char DocsetListCacheFileName[] = "com.kapeli.json"; From a2f83366c5d1b1696ff3074d30a599d713a08c93 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 17 Apr 2016 03:07:48 -0400 Subject: [PATCH 138/273] doc: Use go.zealdocs.org for the contact link --- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp | 2 +- src/core/application.cpp | 2 +- src/core/application.h | 2 +- src/core/extractor.cpp | 2 +- src/core/extractor.h | 2 +- src/core/settings.cpp | 2 +- src/core/settings.h | 2 +- src/main.cpp | 4 ++-- src/registry/docset.cpp | 2 +- src/registry/docset.h | 2 +- src/registry/docsetmetadata.cpp | 2 +- src/registry/docsetmetadata.h | 2 +- src/registry/docsetregistry.cpp | 2 +- src/registry/docsetregistry.h | 2 +- src/registry/listmodel.cpp | 2 +- src/registry/listmodel.h | 2 +- src/registry/searchmodel.cpp | 2 +- src/registry/searchmodel.h | 2 +- src/registry/searchquery.cpp | 2 +- src/registry/searchquery.h | 2 +- src/registry/searchresult.cpp | 2 +- src/registry/searchresult.h | 2 +- src/ui/aboutdialog.cpp | 2 +- src/ui/aboutdialog.h | 2 +- src/ui/docsetlistitemdelegate.cpp | 2 +- src/ui/docsetlistitemdelegate.h | 2 +- src/ui/mainwindow.cpp | 2 +- src/ui/mainwindow.h | 2 +- src/ui/progressitemdelegate.cpp | 2 +- src/ui/progressitemdelegate.h | 2 +- src/ui/searchitemdelegate.cpp | 2 +- src/ui/searchitemdelegate.h | 2 +- src/ui/settingsdialog.cpp | 2 +- src/ui/settingsdialog.h | 2 +- src/ui/widgets/searchablewebview.cpp | 2 +- src/ui/widgets/searchablewebview.h | 2 +- src/ui/widgets/searchedit.cpp | 2 +- src/ui/widgets/searchedit.h | 2 +- src/ui/widgets/shortcutedit.cpp | 2 +- src/ui/widgets/shortcutedit.h | 2 +- src/ui/widgets/webview.cpp | 2 +- src/ui/widgets/webview.h | 2 +- src/util/plist.cpp | 2 +- src/util/plist.h | 2 +- src/util/version.cpp | 2 +- src/util/version.h | 2 +- 51 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp index 7351e0ee4..4b1accce2 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h index 2e2d46b91..1c958383f 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp index c6021ca92..406426b66 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h index de00a0d1e..7bea6cc9c 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp index 322a8cf71..d2eafe2d4 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp index 15574f44f..bcb39c943 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/core/application.cpp b/src/core/application.cpp index c86c13874..53ec1b3b0 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/core/application.h b/src/core/application.h index 7b47805f8..6826e8b79 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/core/extractor.cpp b/src/core/extractor.cpp index 46de0ffbd..c5e06c373 100644 --- a/src/core/extractor.cpp +++ b/src/core/extractor.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/core/extractor.h b/src/core/extractor.h index a9db21c78..d3485a1a2 100644 --- a/src/core/extractor.h +++ b/src/core/extractor.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/core/settings.cpp b/src/core/settings.cpp index abf4d2de9..775cc4a0e 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/core/settings.h b/src/core/settings.h index c7c30c274..475d63fa1 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/main.cpp b/src/main.cpp index 6a3a42e46..f03c8c480 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) QObject::tr("Qt SQLite driver is not available."), QMessageBox::Close | QMessageBox::Help); if (ret == QMessageBox::Help) - QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/contact.html"))); + QDesktopServices::openUrl(QUrl(QStringLiteral("https://go.zealdocs.org/l/contact"))); return 0; } diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 03e7744fa..dcb7e53b4 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/docset.h b/src/registry/docset.h index 1aab534cd..9f32ff939 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/docsetmetadata.cpp b/src/registry/docsetmetadata.cpp index 9b3c5a0ce..672d34a31 100644 --- a/src/registry/docsetmetadata.cpp +++ b/src/registry/docsetmetadata.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/docsetmetadata.h b/src/registry/docsetmetadata.h index 932319b41..29a1136a2 100644 --- a/src/registry/docsetmetadata.h +++ b/src/registry/docsetmetadata.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index b9a26298c..e04754099 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index 30ce741dc..8eacf5a1f 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/listmodel.cpp b/src/registry/listmodel.cpp index a83be84e6..ebeb81635 100644 --- a/src/registry/listmodel.cpp +++ b/src/registry/listmodel.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/listmodel.h b/src/registry/listmodel.h index e6de0692a..a837e21cd 100644 --- a/src/registry/listmodel.h +++ b/src/registry/listmodel.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index e43433ce1..0480c5ce8 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index d4e821dc3..6a5e73629 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/searchquery.cpp b/src/registry/searchquery.cpp index 05b27fd3d..07af65327 100644 --- a/src/registry/searchquery.cpp +++ b/src/registry/searchquery.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/searchquery.h b/src/registry/searchquery.h index a31c6692a..cf89d722e 100644 --- a/src/registry/searchquery.h +++ b/src/registry/searchquery.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/searchresult.cpp b/src/registry/searchresult.cpp index 734391cd2..06ee8e011 100644 --- a/src/registry/searchresult.cpp +++ b/src/registry/searchresult.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/searchresult.h b/src/registry/searchresult.h index a5125c628..46f393405 100644 --- a/src/registry/searchresult.h +++ b/src/registry/searchresult.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index 665a8eca4..a9992fad6 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h index 8dfdacbc2..1851fc8fb 100644 --- a/src/ui/aboutdialog.h +++ b/src/ui/aboutdialog.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/docsetlistitemdelegate.cpp b/src/ui/docsetlistitemdelegate.cpp index d70bce1df..52eacc687 100644 --- a/src/ui/docsetlistitemdelegate.cpp +++ b/src/ui/docsetlistitemdelegate.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/docsetlistitemdelegate.h b/src/ui/docsetlistitemdelegate.h index d29abe0bc..b5a0f45ff 100644 --- a/src/ui/docsetlistitemdelegate.h +++ b/src/ui/docsetlistitemdelegate.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 80d45a945..285c05717 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 9e3b22fb8..5a4ef0a39 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/progressitemdelegate.cpp b/src/ui/progressitemdelegate.cpp index 6836f2a71..bd1342d62 100644 --- a/src/ui/progressitemdelegate.cpp +++ b/src/ui/progressitemdelegate.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/progressitemdelegate.h b/src/ui/progressitemdelegate.h index f15bcfdef..ace6f8e75 100644 --- a/src/ui/progressitemdelegate.h +++ b/src/ui/progressitemdelegate.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index e2e28bb46..7c64e79c1 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index 6f9adb4c8..7c88e83d1 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index df65eb637..1a0aec6c5 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 6ad1cb267..17656b486 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/searchablewebview.cpp b/src/ui/widgets/searchablewebview.cpp index 1125598b9..8a6b3e138 100644 --- a/src/ui/widgets/searchablewebview.cpp +++ b/src/ui/widgets/searchablewebview.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/searchablewebview.h b/src/ui/widgets/searchablewebview.h index 557e18e6e..25787a99e 100644 --- a/src/ui/widgets/searchablewebview.h +++ b/src/ui/widgets/searchablewebview.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/searchedit.cpp b/src/ui/widgets/searchedit.cpp index 3dbda4383..40707cd78 100644 --- a/src/ui/widgets/searchedit.cpp +++ b/src/ui/widgets/searchedit.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/searchedit.h b/src/ui/widgets/searchedit.h index fed84ebef..84b9666be 100644 --- a/src/ui/widgets/searchedit.h +++ b/src/ui/widgets/searchedit.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/shortcutedit.cpp b/src/ui/widgets/shortcutedit.cpp index 698ce2695..5e9dd90ad 100644 --- a/src/ui/widgets/shortcutedit.cpp +++ b/src/ui/widgets/shortcutedit.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/shortcutedit.h b/src/ui/widgets/shortcutedit.h index 41247bf6d..3c1ea5265 100644 --- a/src/ui/widgets/shortcutedit.h +++ b/src/ui/widgets/shortcutedit.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/webview.cpp b/src/ui/widgets/webview.cpp index f88a68d48..1355a1760 100644 --- a/src/ui/widgets/webview.cpp +++ b/src/ui/widgets/webview.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/ui/widgets/webview.h b/src/ui/widgets/webview.h index 4e96248f1..564071a45 100644 --- a/src/ui/widgets/webview.h +++ b/src/ui/widgets/webview.h @@ -2,7 +2,7 @@ ** ** Copyright (C) 2015-2016 Oleg Shparber ** Copyright (C) 2013-2014 Jerzy Kozera -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/util/plist.cpp b/src/util/plist.cpp index d77098859..f60f72a3b 100644 --- a/src/util/plist.cpp +++ b/src/util/plist.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/util/plist.h b/src/util/plist.h index ebfd7e733..ebf0b37a1 100644 --- a/src/util/plist.h +++ b/src/util/plist.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/util/version.cpp b/src/util/version.cpp index d2daa0ecc..90a6dc323 100644 --- a/src/util/version.cpp +++ b/src/util/version.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/util/version.h b/src/util/version.h index f06d73930..6045c4765 100644 --- a/src/util/version.h +++ b/src/util/version.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015-2016 Oleg Shparber -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** From 3a178eaba1affdfe98f1068bdd0cbdbf6eadbb6c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 19 Apr 2016 22:48:48 -0400 Subject: [PATCH 139/273] ui: Do not set Qt::ApplicationShortcut for Ctrl+K --- src/ui/mainwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 285c05717..8d7d0b062 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -97,8 +97,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : setupTabBar(); - QShortcut *focusSearch = new QShortcut(QKeySequence(QStringLiteral("Ctrl+K")), this); - focusSearch->setContext(Qt::ApplicationShortcut); + QShortcut *focusSearch = new QShortcut(QStringLiteral("Ctrl+K"), this); connect(focusSearch, &QShortcut::activated, ui->lineEdit, static_cast(&SearchEdit::setFocus)); From c11a5452e4ca1a2f37ce4f4f598d47935a126c7c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 20 Apr 2016 23:39:30 -0400 Subject: [PATCH 140/273] ui: Move TabState inside MainWindow implementation --- src/ui/mainwindow.cpp | 18 ++++++++++++++++++ src/ui/mainwindow.h | 28 +++++----------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 8d7d0b062..625172502 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -71,6 +71,24 @@ namespace { const char startPageUrl[] = "qrc:///browser/start.html"; } +struct TabState +{ + QString searchQuery; + + // Content/Search results tree view state + Zeal::SearchModel *searchModel = nullptr; + QModelIndexList selections; + QModelIndexList expansions; + int searchScrollPosition; + + // TOC list view state + Zeal::SearchModel *tocModel = nullptr; + int tocScrollPosition; + + QWebPage *webPage = nullptr; + int webViewZoomFactor; +}; + MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 5a4ef0a39..510b23e3e 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -26,9 +26,7 @@ #include "registry/searchquery.h" -#include #include -#include #ifdef USE_WEBENGINE class QWebEngineHistory; @@ -50,41 +48,25 @@ struct _GtkWidget; class QxtGlobalShortcut; +class QModelIndex; class QSystemTrayIcon; class QTabBar; namespace Ui { class MainWindow; -} +} // namespace Ui namespace Zeal { namespace Core { class Application; class Settings; -} - -class ListModel; -class SearchModel; } // namespace Core -struct TabState -{ - QString searchQuery; - - // Content/Search results tree view state - Zeal::SearchModel *searchModel = nullptr; - QModelIndexList selections; - QModelIndexList expansions; - int searchScrollPosition; - - // TOC list view state - Zeal::SearchModel *tocModel = nullptr; - int tocScrollPosition; +class ListModel; +} // namespace Zeal - QWebPage *webPage = nullptr; - int webViewZoomFactor; -}; +struct TabState; class MainWindow : public QMainWindow { From 5f644d86b24714175691fcb2a24d63f4b1c3c0ca Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 21 Apr 2016 01:45:41 -0400 Subject: [PATCH 141/273] ui: Create search models within TabState --- src/ui/mainwindow.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 625172502..5df29e63a 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -73,6 +73,18 @@ const char startPageUrl[] = "qrc:///browser/start.html"; struct TabState { + explicit TabState() + { + searchModel = new Zeal::SearchModel(); + tocModel = new Zeal::SearchModel(); + } + + ~TabState() + { + delete searchModel; + delete tocModel; + } + QString searchQuery; // Content/Search results tree view state @@ -352,12 +364,7 @@ MainWindow::~MainWindow() m_settings->windowGeometry = saveGeometry(); delete ui; - - for (TabState *state : m_tabStates) { - delete state->searchModel; - delete state->tocModel; - delete state; - } + qDeleteAll(m_tabStates); } void MainWindow::search(const SearchQuery &query) @@ -437,8 +444,6 @@ void MainWindow::closeTab(int index) if (m_currentTabState == state) m_currentTabState = nullptr; - delete state->searchModel; - delete state->tocModel; delete state; m_tabBar->removeTab(index); @@ -450,8 +455,6 @@ void MainWindow::closeTab(int index) void MainWindow::createTab() { TabState *newTab = new TabState(); - newTab->searchModel = new Zeal::SearchModel(); - newTab->tocModel = new Zeal::SearchModel(); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); From 9a247bc9ef703ac44f0fcc7115d6b805c47ed92e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 21 Apr 2016 01:46:34 -0400 Subject: [PATCH 142/273] ui: Set initial values in tab states --- src/ui/mainwindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 5df29e63a..c0313b247 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -91,14 +91,14 @@ struct TabState Zeal::SearchModel *searchModel = nullptr; QModelIndexList selections; QModelIndexList expansions; - int searchScrollPosition; + int searchScrollPosition = 0; // TOC list view state Zeal::SearchModel *tocModel = nullptr; - int tocScrollPosition; + int tocScrollPosition = 0; QWebPage *webPage = nullptr; - int webViewZoomFactor; + int webViewZoomFactor = 0; }; MainWindow::MainWindow(Core::Application *app, QWidget *parent) : From ecb5e3d40d2875d2882ac5b2a535adc4601fc5b8 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 21 Apr 2016 02:03:43 -0400 Subject: [PATCH 143/273] ui: Avoid redundant rebuild of the View menu --- src/ui/mainwindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c0313b247..9d452d519 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -247,7 +247,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &text) { m_tabBar->setTabText(m_tabBar->currentIndex(), text); - displayViewActions(); }); connect(ui->webView, &SearchableWebView::linkClicked, [this](const QUrl &url) { From 2ffd829142c3fbca7ad2f2098da23b4b915a9fec Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 12:23:44 -0400 Subject: [PATCH 144/273] ui: Fix leaked QWeb(Engine)Page for each closed tab --- src/ui/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 9d452d519..a4c76ed1e 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -77,12 +77,14 @@ struct TabState { searchModel = new Zeal::SearchModel(); tocModel = new Zeal::SearchModel(); + webPage = new QWebPage(); } ~TabState() { delete searchModel; delete tocModel; + delete webPage; } QString searchQuery; @@ -458,7 +460,6 @@ void MainWindow::createTab() connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); - newTab->webPage = new QWebPage(ui->webView); #ifdef USE_WEBENGINE newTab->webPage->load(QUrl(startPageUrl)); #else From 9b1287181bbc3acb5ed8aee0033d00b030bf52c4 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 12:31:56 -0400 Subject: [PATCH 145/273] ui: Encapsulate WebKit/WebEngine API differences in TabState --- src/ui/mainwindow.cpp | 50 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a4c76ed1e..3179a5401 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -77,7 +77,12 @@ struct TabState { searchModel = new Zeal::SearchModel(); tocModel = new Zeal::SearchModel(); + webPage = new QWebPage(); +#ifndef USE_WEBENGINE + webPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); + webPage->setNetworkAccessManager(Core::Application::instance()->networkManager()); +#endif } ~TabState() @@ -87,6 +92,23 @@ struct TabState delete webPage; } + QUrl url() const { +#ifdef USE_WEBENGINE + return webPage->url(); +#else + return webPage->mainFrame()->url(); +#endif + } + + void loadUrl(const QUrl &url) + { +#ifdef USE_WEBENGINE + webPage->load(url); +#else + webPage->mainFrame()->load(url); +#endif + } + QString searchQuery; // Content/Search results tree view state @@ -136,11 +158,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : restoreGeometry(m_settings->windowGeometry); ui->splitter->restoreState(m_settings->verticalSplitterGeometry); - // TODO: Custom headers and URL scheme for Qt WebEngine. -#ifndef USE_WEBENGINE - ui->webView->page()->setNetworkAccessManager(m_application->networkManager()); -#endif - // Menu // File // Some platform plugins do not define QKeySequence::Quit. @@ -267,13 +284,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : this, [this](const QString &name) { setupSearchBoxCompletions(); for (TabState *tabState : m_tabStates) { -#ifdef USE_WEBENGINE - if (docsetName(tabState->webPage->url()) != name) - continue; - - tabState->webPage->load(QUrl(startPageUrl)); -#else - if (docsetName(tabState->webPage->mainFrame()->url()) != name) + if (docsetName(tabState->url()) != name) continue; tabState->tocModel->setResults(); @@ -286,8 +297,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : tabState->searchModel->removeSearchResultWithName(name); ui->treeView->setUpdatesEnabled(true); - tabState->webPage->mainFrame()->load(QUrl(startPageUrl)); -#endif + tabState->loadUrl(QUrl(startPageUrl)); + // TODO: Cleanup history } }); @@ -460,16 +471,7 @@ void MainWindow::createTab() connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); -#ifdef USE_WEBENGINE - newTab->webPage->load(QUrl(startPageUrl)); -#else - newTab->webPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); - newTab->webPage->setNetworkAccessManager(m_application->networkManager()); - newTab->webPage->mainFrame()->load(QUrl(startPageUrl)); -#endif - - m_tabStates.append(newTab); - + newTab->loadUrl(QUrl(startPageUrl)); const int index = m_tabBar->addTab(QStringLiteral("title")); m_tabBar->setCurrentIndex(index); From 57814cd0348fd093140d596bb6c046f99a552edd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 12:45:40 -0400 Subject: [PATCH 146/273] ui: Remove single-use MainWindow::selectTab() --- src/ui/mainwindow.cpp | 19 ++++++++----------- src/ui/mainwindow.h | 1 - 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 3179a5401..0cda4e494 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -432,16 +432,6 @@ void MainWindow::queryCompleted() ui->lineEdit->setFocus(Qt::MouseFocusReason); } -void MainWindow::selectTab(int index) -{ - if (index == -1) - return; - - saveTabState(); - m_currentTabState = nullptr; - reloadTabState(); -} - void MainWindow::closeTab(int index) { if (index == -1) @@ -578,7 +568,14 @@ void MainWindow::setupTabBar() m_tabBar->setElideMode(Qt::ElideRight); m_tabBar->setStyleSheet(QStringLiteral("QTabBar::tab { width: 150px; }")); - connect(m_tabBar, &QTabBar::currentChanged, this, &MainWindow::selectTab); + connect(m_tabBar, &QTabBar::currentChanged, this, [this](int index) { + if (index == -1) + return; + + saveTabState(); + m_currentTabState = nullptr; + reloadTabState(); + }); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); for (int i = 1; i < 10; i++) { diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 510b23e3e..8e8710b89 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -92,7 +92,6 @@ private slots: void applySettings(); void openDocset(const QModelIndex &index); void queryCompleted(); - void selectTab(int index); void closeTab(int index = -1); private: From f5b998de2833f4c9cd9d5e1c2d97892e828d6e17 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 13:02:13 -0400 Subject: [PATCH 147/273] ui: Do not save current search term twice --- src/ui/mainwindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 0cda4e494..57ff51e58 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -503,7 +503,6 @@ void MainWindow::saveTabState() if (!m_currentTabState) return; - m_currentTabState->searchQuery = ui->lineEdit->text(); m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); m_currentTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); m_currentTabState->tocScrollPosition = ui->tocListView->verticalScrollBar()->value(); From ab0a007d60653aa041e3bd72a715745947033fe6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 13:24:19 -0400 Subject: [PATCH 148/273] ui: Retrieve current tab state dynamically This is a step having real tabs in a tab widgets, instead of the current surrogate approach. --- src/ui/mainwindow.cpp | 108 +++++++++++++++++++----------------------- src/ui/mainwindow.h | 3 -- 2 files changed, 48 insertions(+), 63 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 57ff51e58..3458716ef 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -259,7 +259,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : Docset *docset = m_application->docsetRegistry()->docset(name); if (docset) - m_currentTabState->tocModel->setResults(docset->relatedLinks(url)); + currentTabState()->tocModel->setResults(docset->relatedLinks(url)); displayViewActions(); }); @@ -277,7 +277,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, this, [this](const QList &results) { - m_currentTabState->searchModel->setResults(results); + currentTabState()->searchModel->setResults(results); }); connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, @@ -309,13 +309,13 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : }); connect(ui->lineEdit, &QLineEdit::textChanged, [this](const QString &text) { - if (!m_currentTabState || text == m_currentTabState->searchQuery) + if (text == currentTabState()->searchQuery) return; - m_currentTabState->searchQuery = text; + currentTabState()->searchQuery = text; m_application->docsetRegistry()->search(text); if (text.isEmpty()) { - m_currentTabState->tocModel->setResults(); + currentTabState()->tocModel->setResults(); displayTreeView(); } }); @@ -324,14 +324,14 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->actionNewTab, &QAction::triggered, this, &MainWindow::createTab); addAction(ui->actionNewTab); - // save the expanded items: + // Save expanded items connect(ui->treeView, &QTreeView::expanded, [this](QModelIndex index) { - if (m_currentTabState->expansions.indexOf(index) == -1) - m_currentTabState->expansions.append(index); + if (currentTabState()->expansions.indexOf(index) == -1) + currentTabState()->expansions.append(index); }); connect(ui->treeView, &QTreeView::collapsed, [this](QModelIndex index) { - m_currentTabState->expansions.removeOne(index); + currentTabState()->expansions.removeOne(index); }); #ifdef Q_OS_WIN32 @@ -425,7 +425,7 @@ void MainWindow::queryCompleted() { displayTreeView(); - ui->treeView->setCurrentIndex(m_currentTabState->searchModel->index(0, 0, QModelIndex())); + ui->treeView->setCurrentIndex(currentTabState()->searchModel->index(0, 0, QModelIndex())); openDocset(ui->treeView->currentIndex()); // Get focus back. QWebPageEngine::load() always steals focus. @@ -440,13 +440,7 @@ void MainWindow::closeTab(int index) if (index == -1) return; - // TODO: proper deletion here - TabState *state = m_tabStates.takeAt(index); - - if (m_currentTabState == state) - m_currentTabState = nullptr; - - delete state; + delete m_tabStates.takeAt(index); m_tabBar->removeTab(index); @@ -498,46 +492,6 @@ TabState *MainWindow::currentTabState() const return m_tabStates.at(m_tabBar->currentIndex()); } -void MainWindow::saveTabState() -{ - if (!m_currentTabState) - return; - - m_currentTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); - m_currentTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); - m_currentTabState->tocScrollPosition = ui->tocListView->verticalScrollBar()->value(); - m_currentTabState->webViewZoomFactor = ui->webView->zoomFactor(); -} - -void MainWindow::reloadTabState() -{ - TabState *tabState = currentTabState(); - - ui->lineEdit->setText(tabState->searchQuery); - ui->tocListView->setModel(tabState->tocModel); - - toggleToc(); - displayTreeView(); - - // 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->setZoomFactor(tabState->webViewZoomFactor); - - m_currentTabState = tabState; - - ui->treeView->verticalScrollBar()->setValue(m_currentTabState->searchScrollPosition); - ui->tocListView->verticalScrollBar()->setValue(m_currentTabState->tocScrollPosition); - - displayViewActions(); -} - // Sets up the search box autocompletions. void MainWindow::setupSearchBoxCompletions() { @@ -568,12 +522,46 @@ void MainWindow::setupTabBar() m_tabBar->setStyleSheet(QStringLiteral("QTabBar::tab { width: 150px; }")); connect(m_tabBar, &QTabBar::currentChanged, this, [this](int index) { + static const char PreviousTabIndexProperty[] = "previousTabIndex"; + if (index == -1) return; - saveTabState(); - m_currentTabState = nullptr; - reloadTabState(); + // Save previous tab state + const QVariant previousTabIndex = m_tabBar->property(PreviousTabIndexProperty); + if (previousTabIndex.isValid() && previousTabIndex.toInt() < m_tabStates.size()) { + TabState *previousTabState = m_tabStates.at(previousTabIndex.toInt()); + previousTabState->selections = ui->treeView->selectionModel()->selectedIndexes(); + previousTabState->searchScrollPosition = ui->treeView->verticalScrollBar()->value(); + previousTabState->tocScrollPosition = ui->tocListView->verticalScrollBar()->value(); + previousTabState->webViewZoomFactor = ui->webView->zoomFactor(); + } + + // Load current tab state + m_tabBar->setProperty(PreviousTabIndexProperty, index); + TabState *tabState = m_tabStates.at(index); + + ui->lineEdit->setText(tabState->searchQuery); + ui->tocListView->setModel(tabState->tocModel); + + toggleToc(); + displayTreeView(); + + // 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->setZoomFactor(tabState->webViewZoomFactor); + + ui->treeView->verticalScrollBar()->setValue(tabState->searchScrollPosition); + ui->tocListView->verticalScrollBar()->setValue(tabState->tocScrollPosition); + + displayViewActions(); }); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 8e8710b89..4a40535f9 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -102,8 +102,6 @@ private slots: void setupTabBar(); TabState *currentTabState() const; - void saveTabState(); - void reloadTabState(); QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; @@ -116,7 +114,6 @@ private slots: void removeTrayIcon(); QList m_tabStates; - TabState *m_currentTabState = nullptr; Ui::MainWindow *ui = nullptr; Zeal::Core::Application *m_application = nullptr; From de9cb0915fe08a681e17a0762b3f2891a4fa71eb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 21:34:12 -0400 Subject: [PATCH 149/273] ui: Fix missing tab titles --- src/ui/mainwindow.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 3458716ef..f0c2128e1 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -264,8 +264,11 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : displayViewActions(); }); - connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &text) { - m_tabBar->setTabText(m_tabBar->currentIndex(), text); + connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &title) { + if (title.isEmpty()) + return; + + m_tabBar->setTabText(m_tabBar->currentIndex(), title); }); connect(ui->webView, &SearchableWebView::linkClicked, [this](const QUrl &url) { From 9aa056770ec22883c3cdf8fd53228577cab49bf5 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 21:38:27 -0400 Subject: [PATCH 150/273] res: Remove 'Zeal' from the stat page's title --- src/resources/browser/start.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resources/browser/start.html b/src/resources/browser/start.html index 326ec2b0f..2a53b774c 100644 --- a/src/resources/browser/start.html +++ b/src/resources/browser/start.html @@ -1,6 +1,6 @@ - Zeal - Start Page + Start Page From e003a1444d9f48b9dd00bd7d649486814c5cd36c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 21:40:04 -0400 Subject: [PATCH 151/273] ui: Include page title in the window title (#343) --- src/ui/mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index f0c2128e1..5dae5577e 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -268,6 +268,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : if (title.isEmpty()) return; + setWindowTitle(QStringLiteral("%1 - Zeal").arg(title)); m_tabBar->setTabText(m_tabBar->currentIndex(), title); }); From b6220c894f05ab47a2dbb42c8a1b6978601314d8 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 21:43:41 -0400 Subject: [PATCH 152/273] ui: Add API for creating tabs at any position --- src/ui/mainwindow.cpp | 11 +++++++---- src/ui/mainwindow.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 5dae5577e..2bfa141ca 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -325,7 +325,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : }); ui->actionNewTab->setShortcut(QKeySequence::AddTab); - connect(ui->actionNewTab, &QAction::triggered, this, &MainWindow::createTab); + connect(ui->actionNewTab, &QAction::triggered, this, [this]() { createTab(); }); addAction(ui->actionNewTab); // Save expanded items @@ -452,16 +452,19 @@ void MainWindow::closeTab(int index) createTab(); } -void MainWindow::createTab() +void MainWindow::createTab(int index) { - TabState *newTab = new TabState(); + if (index == -1) + index = m_tabStates.size(); + TabState *newTab = new TabState(); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); newTab->loadUrl(QUrl(startPageUrl)); - const int index = m_tabBar->addTab(QStringLiteral("title")); + m_tabStates.insert(index, newTab); + m_tabBar->insertTab(index, tr("Loading...")); m_tabBar->setCurrentIndex(index); } diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 4a40535f9..bed611080 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -77,7 +77,7 @@ class MainWindow : public QMainWindow void search(const Zeal::SearchQuery &query); void bringToFront(); - void createTab(); + void createTab(int index = -1); public slots: void toggleWindow(); From 4cec3c5c7557dcfa0c3fadb7d9bbe20ec01da86a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 1 May 2016 22:13:18 -0400 Subject: [PATCH 153/273] doc: Use HTTPS for gnu.org link --- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp | 2 +- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp | 2 +- src/core/application.cpp | 2 +- src/core/application.h | 2 +- src/core/extractor.cpp | 2 +- src/core/extractor.h | 2 +- src/core/settings.cpp | 2 +- src/core/settings.h | 2 +- src/main.cpp | 2 +- src/registry/docset.cpp | 2 +- src/registry/docset.h | 2 +- src/registry/docsetmetadata.cpp | 2 +- src/registry/docsetmetadata.h | 2 +- src/registry/docsetregistry.cpp | 2 +- src/registry/docsetregistry.h | 2 +- src/registry/listmodel.cpp | 2 +- src/registry/listmodel.h | 2 +- src/registry/searchmodel.cpp | 2 +- src/registry/searchmodel.h | 2 +- src/registry/searchquery.cpp | 2 +- src/registry/searchquery.h | 2 +- src/registry/searchresult.cpp | 2 +- src/registry/searchresult.h | 2 +- src/ui/aboutdialog.cpp | 2 +- src/ui/aboutdialog.h | 2 +- src/ui/docsetlistitemdelegate.cpp | 2 +- src/ui/docsetlistitemdelegate.h | 2 +- src/ui/mainwindow.cpp | 2 +- src/ui/mainwindow.h | 2 +- src/ui/progressitemdelegate.cpp | 2 +- src/ui/progressitemdelegate.h | 2 +- src/ui/searchitemdelegate.cpp | 2 +- src/ui/searchitemdelegate.h | 2 +- src/ui/settingsdialog.cpp | 2 +- src/ui/settingsdialog.h | 2 +- src/ui/widgets/searchablewebview.cpp | 2 +- src/ui/widgets/searchablewebview.h | 2 +- src/ui/widgets/searchedit.cpp | 2 +- src/ui/widgets/searchedit.h | 2 +- src/ui/widgets/shortcutedit.cpp | 2 +- src/ui/widgets/shortcutedit.h | 2 +- src/ui/widgets/webview.cpp | 2 +- src/ui/widgets/webview.h | 2 +- src/util/plist.cpp | 2 +- src/util/plist.h | 2 +- src/util/version.cpp | 2 +- src/util/version.h | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp index 4b1accce2..0790f0dcc 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ /**************************************************************************** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h index 1c958383f..4ffbf60a2 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ /**************************************************************************** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp index 406426b66..cc74c79e6 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ /**************************************************************************** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h index 7bea6cc9c..45704e22f 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ /**************************************************************************** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp index d2eafe2d4..849d18413 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ /**************************************************************************** diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp index bcb39c943..b4f343098 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ /**************************************************************************** diff --git a/src/core/application.cpp b/src/core/application.cpp index 53ec1b3b0..54c43af78 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/core/application.h b/src/core/application.h index 6826e8b79..63b495d1d 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/core/extractor.cpp b/src/core/extractor.cpp index c5e06c373..97c68e014 100644 --- a/src/core/extractor.cpp +++ b/src/core/extractor.cpp @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/core/extractor.h b/src/core/extractor.h index d3485a1a2..1d09191c9 100644 --- a/src/core/extractor.h +++ b/src/core/extractor.h @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 775cc4a0e..0dc04e7b0 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/core/settings.h b/src/core/settings.h index 475d63fa1..20866961d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/main.cpp b/src/main.cpp index f03c8c480..45f164cff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index dcb7e53b4..671e443eb 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/docset.h b/src/registry/docset.h index 9f32ff939..a3b4d8f95 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/docsetmetadata.cpp b/src/registry/docsetmetadata.cpp index 672d34a31..f8cfb94a3 100644 --- a/src/registry/docsetmetadata.cpp +++ b/src/registry/docsetmetadata.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/docsetmetadata.h b/src/registry/docsetmetadata.h index 29a1136a2..b5b8ca4f7 100644 --- a/src/registry/docsetmetadata.h +++ b/src/registry/docsetmetadata.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index e04754099..ef0ea5d55 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index 8eacf5a1f..bac4c3cc6 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/listmodel.cpp b/src/registry/listmodel.cpp index ebeb81635..81dd22d91 100644 --- a/src/registry/listmodel.cpp +++ b/src/registry/listmodel.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/listmodel.h b/src/registry/listmodel.h index a837e21cd..c10ac4d44 100644 --- a/src/registry/listmodel.h +++ b/src/registry/listmodel.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index 0480c5ce8..25be61958 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index 6a5e73629..941741cdd 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/searchquery.cpp b/src/registry/searchquery.cpp index 07af65327..de51af78f 100644 --- a/src/registry/searchquery.cpp +++ b/src/registry/searchquery.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/searchquery.h b/src/registry/searchquery.h index cf89d722e..5b62c9039 100644 --- a/src/registry/searchquery.h +++ b/src/registry/searchquery.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/searchresult.cpp b/src/registry/searchresult.cpp index 06ee8e011..c6447d0d3 100644 --- a/src/registry/searchresult.cpp +++ b/src/registry/searchresult.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/registry/searchresult.h b/src/registry/searchresult.h index 46f393405..98443e2c4 100644 --- a/src/registry/searchresult.h +++ b/src/registry/searchresult.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index a9992fad6..27ae9bbb9 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h index 1851fc8fb..bf4e0ee95 100644 --- a/src/ui/aboutdialog.h +++ b/src/ui/aboutdialog.h @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/docsetlistitemdelegate.cpp b/src/ui/docsetlistitemdelegate.cpp index 52eacc687..d7fa3a7f2 100644 --- a/src/ui/docsetlistitemdelegate.cpp +++ b/src/ui/docsetlistitemdelegate.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/docsetlistitemdelegate.h b/src/ui/docsetlistitemdelegate.h index b5a0f45ff..0d12ce9a8 100644 --- a/src/ui/docsetlistitemdelegate.h +++ b/src/ui/docsetlistitemdelegate.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 2bfa141ca..fd1733dc3 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index bed611080..ecb56820c 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/progressitemdelegate.cpp b/src/ui/progressitemdelegate.cpp index bd1342d62..9c72c97d2 100644 --- a/src/ui/progressitemdelegate.cpp +++ b/src/ui/progressitemdelegate.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/progressitemdelegate.h b/src/ui/progressitemdelegate.h index ace6f8e75..d3bc70b7e 100644 --- a/src/ui/progressitemdelegate.h +++ b/src/ui/progressitemdelegate.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index 7c64e79c1..fa33974f1 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index 7c88e83d1..bc6505717 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 1a0aec6c5..1e9be859d 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/settingsdialog.h b/src/ui/settingsdialog.h index 17656b486..dc97e5117 100644 --- a/src/ui/settingsdialog.h +++ b/src/ui/settingsdialog.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/searchablewebview.cpp b/src/ui/widgets/searchablewebview.cpp index 8a6b3e138..93e919f41 100644 --- a/src/ui/widgets/searchablewebview.cpp +++ b/src/ui/widgets/searchablewebview.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/searchablewebview.h b/src/ui/widgets/searchablewebview.h index 25787a99e..1b1f5bb56 100644 --- a/src/ui/widgets/searchablewebview.h +++ b/src/ui/widgets/searchablewebview.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/searchedit.cpp b/src/ui/widgets/searchedit.cpp index 40707cd78..0ec39a1b1 100644 --- a/src/ui/widgets/searchedit.cpp +++ b/src/ui/widgets/searchedit.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/searchedit.h b/src/ui/widgets/searchedit.h index 84b9666be..e7ba28237 100644 --- a/src/ui/widgets/searchedit.h +++ b/src/ui/widgets/searchedit.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/shortcutedit.cpp b/src/ui/widgets/shortcutedit.cpp index 5e9dd90ad..c2da98bd0 100644 --- a/src/ui/widgets/shortcutedit.cpp +++ b/src/ui/widgets/shortcutedit.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/shortcutedit.h b/src/ui/widgets/shortcutedit.h index 3c1ea5265..f068ca005 100644 --- a/src/ui/widgets/shortcutedit.h +++ b/src/ui/widgets/shortcutedit.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/webview.cpp b/src/ui/widgets/webview.cpp index 1355a1760..224bb5c58 100644 --- a/src/ui/widgets/webview.cpp +++ b/src/ui/widgets/webview.cpp @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/ui/widgets/webview.h b/src/ui/widgets/webview.h index 564071a45..ae2d87fcc 100644 --- a/src/ui/widgets/webview.h +++ b/src/ui/widgets/webview.h @@ -17,7 +17,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/util/plist.cpp b/src/util/plist.cpp index f60f72a3b..6695264b1 100644 --- a/src/util/plist.cpp +++ b/src/util/plist.cpp @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/util/plist.h b/src/util/plist.h index ebf0b37a1..22a98d7e1 100644 --- a/src/util/plist.h +++ b/src/util/plist.h @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/util/version.cpp b/src/util/version.cpp index 90a6dc323..8dd1fc301 100644 --- a/src/util/version.cpp +++ b/src/util/version.cpp @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ diff --git a/src/util/version.h b/src/util/version.h index 6045c4765..be59e180d 100644 --- a/src/util/version.h +++ b/src/util/version.h @@ -16,7 +16,7 @@ ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License -** along with Zeal. If not, see . +** along with Zeal. If not, see . ** ****************************************************************************/ From 2610f0ff3becd3da735db4bf5cc99bdecd4ba717 Mon Sep 17 00:00:00 2001 From: Vladislav Tronko Date: Wed, 20 Apr 2016 21:45:50 +0300 Subject: [PATCH 154/273] core, ui: Add option for new tabs to be open next to current one --- src/core/settings.cpp | 9 +++++++++ src/core/settings.h | 3 +++ src/ui/forms/settingsdialog.ui | 16 ++++++++++++++++ src/ui/mainwindow.cpp | 4 +++- src/ui/settingsdialog.cpp | 4 ++++ 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 0dc04e7b0..e9b2446d2 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -41,6 +41,7 @@ namespace { const char GroupBrowser[] = "browser"; const char GroupDocsets[] = "docsets"; const char GroupGlobalShortcuts[] = "global_shortcuts"; +const char GroupTabs[] = "tabs"; const char GroupInternal[] = "internal"; const char GroupState[] = "state"; const char GroupProxy[] = "proxy"; @@ -89,6 +90,10 @@ void Settings::load() #endif m_settings->endGroup(); + m_settings->beginGroup(GroupTabs); + openNewTabAfterActive = m_settings->value(QStringLiteral("open_new_tab_after_active"), false).toBool(); + m_settings->endGroup(); + m_settings->beginGroup(GroupBrowser); minimumFontSize = m_settings->value(QStringLiteral("minimum_font_size"), QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumFontSize)).toInt(); @@ -148,6 +153,10 @@ void Settings::save() m_settings->setValue(QStringLiteral("show"), showShortcut); m_settings->endGroup(); + m_settings->beginGroup(GroupTabs); + m_settings->setValue(QStringLiteral("open_new_tab_after_active"), openNewTabAfterActive); + m_settings->endGroup(); + m_settings->beginGroup(GroupBrowser); m_settings->setValue(QStringLiteral("minimum_font_size"), minimumFontSize); m_settings->endGroup(); diff --git a/src/core/settings.h b/src/core/settings.h index 20866961d..eee115960 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -53,6 +53,9 @@ class Settings : public QObject QKeySequence showShortcut; // TODO: QKeySequence searchSelectedTextShortcut; + // Tabs Behavior + bool openNewTabAfterActive; + // Browser int minimumFontSize; // TODO: bool askOnExternalLink; diff --git a/src/ui/forms/settingsdialog.ui b/src/ui/forms/settingsdialog.ui index 8b35742e5..e1a8c11d2 100644 --- a/src/ui/forms/settingsdialog.ui +++ b/src/ui/forms/settingsdialog.ui @@ -141,6 +141,22 @@ + + + + Tabs behavior + + + + + + Open new tab after active + + + + + + diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fd1733dc3..361c88bac 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -454,7 +454,9 @@ void MainWindow::closeTab(int index) void MainWindow::createTab(int index) { - if (index == -1) + if (m_settings->openNewTabAfterActive) + index = m_tabBar->currentIndex() + 1; + else if (index == -1) index = m_tabStates.size(); TabState *newTab = new TabState(); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 1e9be859d..0b6722bad 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -762,6 +762,8 @@ void SettingsDialog::loadSettings() ui->toolButton->setKeySequence(settings->showShortcut); + ui->openNewTabAfterActive->setChecked(settings->openNewTabAfterActive); + // ui->minFontSize->setValue(settings->minimumFontSize); ui->storageEdit->setText(QDir::toNativeSeparators(settings->docsetPath)); @@ -798,6 +800,8 @@ void SettingsDialog::saveSettings() settings->showShortcut = ui->toolButton->keySequence(); + settings->openNewTabAfterActive = ui->openNewTabAfterActive->isChecked(); + // settings->minimumFontSize = ui->minFontSize->text().toInt(); From 82beb88b1bd9e7134220de8bad3a03711ba0a32b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 2 May 2016 21:26:35 -0400 Subject: [PATCH 155/273] core: Start local server as soon as possible (#535) --- src/core/application.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index 54c43af78..f2a0c16fa 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -65,23 +65,12 @@ Application::Application(const SearchQuery &query, QObject *parent) : Q_ASSERT(!m_instance); m_instance = this; - m_settings = new Settings(this); + // A server for receiving messages from other application instances. m_localServer = new QLocalServer(this); - m_networkManager = new QNetworkAccessManager(this); - m_extractorThread = new QThread(this); - m_extractor = new Extractor(); - - m_docsetRegistry = new DocsetRegistry(); - m_docsetRegistry->init(m_settings->docsetPath); - - m_mainWindow = new MainWindow(this); - - // Server for detecting already running instances connect(m_localServer, &QLocalServer::newConnection, [this]() { QLocalSocket *connection = m_localServer->nextPendingConnection(); - // Wait a little while the other side writes the bytes - connection->waitForReadyRead(); - if (connection->bytesAvailable()) { + // Wait a little while the other side writes the bytes. + if (connection->waitForReadyRead()) { QDataStream in(connection); Zeal::SearchQuery query; bool preventActivation; @@ -102,7 +91,12 @@ Application::Application(const SearchQuery &query, QObject *parent) : QLocalServer::removeServer(LocalServerName); m_localServer->listen(LocalServerName); + m_settings = new Settings(this); + m_networkManager = new QNetworkAccessManager(this); + // Extractor setup + m_extractorThread = new QThread(this); + m_extractor = new Extractor(); m_extractor->moveToThread(m_extractorThread); m_extractorThread->start(); connect(m_extractor, &Extractor::completed, this, &Application::extractionCompleted); @@ -112,6 +106,11 @@ Application::Application(const SearchQuery &query, QObject *parent) : connect(m_settings, &Settings::updated, this, &Application::applySettings); applySettings(); + m_docsetRegistry = new DocsetRegistry(); + m_docsetRegistry->init(m_settings->docsetPath); + + m_mainWindow = new MainWindow(this); + if (!query.isEmpty()) { m_mainWindow->search(query); m_mainWindow->show(); From 0f5400db413fecfaeb31f33bd13f25253683a3e0 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 3 May 2016 22:46:08 -0400 Subject: [PATCH 156/273] core: Fix leaking QLocalSocket --- src/core/application.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index f2a0c16fa..d2cd84a8d 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -68,10 +69,10 @@ Application::Application(const SearchQuery &query, QObject *parent) : // A server for receiving messages from other application instances. m_localServer = new QLocalServer(this); connect(m_localServer, &QLocalServer::newConnection, [this]() { - QLocalSocket *connection = m_localServer->nextPendingConnection(); - // Wait a little while the other side writes the bytes. + QScopedPointer connection(m_localServer->nextPendingConnection()); + // Wait a little, while the other side writes the data. if (connection->waitForReadyRead()) { - QDataStream in(connection); + QDataStream in(connection.data()); Zeal::SearchQuery query; bool preventActivation; in >> query; From d63f5109caf6d60ce02aa8fff75ab15571bceee5 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 11 May 2016 23:58:27 -0400 Subject: [PATCH 157/273] registry: Remove duplicate keywords during docset loading --- src/registry/docset.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 671e443eb..e0ddaca02 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -148,6 +148,8 @@ Docset::Docset(const QString &path) : // TODO: Use 'unknown' instead of CFBundleName? (See #383) m_keywords << plist.value(InfoPlist::CFBundleName, m_name).toString().toLower(); + m_keywords.removeDuplicates(); + // Try to find index path if metadata is missing one if (m_indexFilePath.isEmpty()) { if (plist.contains(InfoPlist::DashIndexFilePath)) From b6aa27bc924b8d6b3dcd0283c50820fad8883cf4 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 14 May 2016 13:43:37 -0400 Subject: [PATCH 158/273] core: Application::docsetRegistry() doesn't need to be static --- src/core/application.cpp | 2 +- src/core/application.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index d2cd84a8d..cf9df46bf 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -181,7 +181,7 @@ Settings *Application::settings() const DocsetRegistry *Application::docsetRegistry() { - return m_instance->m_docsetRegistry; + return m_docsetRegistry; } void Application::extract(const QString &filePath, const QString &destination, const QString &root) diff --git a/src/core/application.h b/src/core/application.h index 63b495d1d..11f06602b 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -57,7 +57,7 @@ class Application : public QObject QNetworkAccessManager *networkManager() const; Settings *settings() const; - static DocsetRegistry *docsetRegistry(); + DocsetRegistry *docsetRegistry(); public slots: void extract(const QString &filePath, const QString &destination, const QString &root = QString()); From cb35be1dcd01d7c6cb455f024ef770511c43cdda Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 14 May 2016 14:01:52 -0400 Subject: [PATCH 159/273] core: Improve documentation comments in Application --- src/core/application.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index cf9df46bf..ff4f0ed6c 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -140,7 +140,7 @@ Application::~Application() /*! * \internal * \brief Returns a pointer to the Core::Application instance. - * If no instance has been created, then \c nullptr is returned. + * \return A pointer or \c nullptr, if no instance has been created. */ Application *Application::instance() { @@ -149,10 +149,10 @@ Application *Application::instance() /*! * \internal - * \brief Hands over \a query to already running application instance, if it exists. + * \brief Sends \a query to an already running application instance, if it exists. * \param query A query to execute search with. * \param preventActivation If \c true, application window will not activated. - * \return \c true if communication with another instance was successful. + * \return \c true if communication with another instance has been successful. */ bool Application::send(const SearchQuery &query, bool preventActivation) { From b7dce47fad2516b913a01624df3a7406e1f41960 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 14 May 2016 14:10:19 -0400 Subject: [PATCH 160/273] app,core: Use IPC for startup query too This simplifies the code related to the starting the app with a query. --- src/core/application.cpp | 11 ----------- src/core/application.h | 1 - src/main.cpp | 5 ++++- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/core/application.cpp b/src/core/application.cpp index ff4f0ed6c..8661d4247 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -55,11 +55,6 @@ const char ReleasesApiUrl[] = "http://api.zealdocs.org/v1/releases"; Application *Application::m_instance = nullptr; Application::Application(QObject *parent) : - Application(SearchQuery(), parent) -{ -} - -Application::Application(const SearchQuery &query, QObject *parent) : QObject(parent) { // Ensure only one instance of Application @@ -112,12 +107,6 @@ Application::Application(const SearchQuery &query, QObject *parent) : m_mainWindow = new MainWindow(this); - if (!query.isEmpty()) { - m_mainWindow->search(query); - m_mainWindow->show(); - return; - } - if (m_settings->startMinimized) { if (m_settings->showSystrayIcon && m_settings->minimizeToSystray) return; diff --git a/src/core/application.h b/src/core/application.h index 11f06602b..01ad0b7af 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -47,7 +47,6 @@ class Application : public QObject Q_OBJECT public: explicit Application(QObject *parent = nullptr); - explicit Application(const SearchQuery &query, QObject *parent = nullptr); ~Application() override; static Application *instance(); diff --git a/src/main.cpp b/src/main.cpp index 45f164cff..1fbb8543d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -208,7 +208,10 @@ int main(int argc, char *argv[]) QDir::setSearchPaths(QStringLiteral("typeIcon"), {QStringLiteral(":/icons/type")}); - QScopedPointer app(new Core::Application(clParams.query)); + QScopedPointer app(new Core::Application()); + + if (!clParams.query.isEmpty()) + Core::Application::send(clParams.query, clParams.preventActivation); return qapp->exec(); } From a32f7d92090a28df972a7e0693171802f03e0dbf Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 4 Jun 2016 21:27:13 -0400 Subject: [PATCH 161/273] app,core: Move the local server code into a dedicated class Core::LocalServer is now responsible for communications between running instances. --- src/core/application.cpp | 62 +++++-------------------- src/core/application.h | 5 +-- src/core/localserver.cpp | 97 ++++++++++++++++++++++++++++++++++++++++ src/core/localserver.h | 56 +++++++++++++++++++++++ src/main.cpp | 12 +++-- 5 files changed, 173 insertions(+), 59 deletions(-) create mode 100644 src/core/localserver.cpp create mode 100644 src/core/localserver.h diff --git a/src/core/application.cpp b/src/core/application.cpp index 8661d4247..a5f0fdfc0 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include #include @@ -47,8 +45,6 @@ using namespace Zeal; using namespace Zeal::Core; namespace { -const char LocalServerName[] = "ZealLocalServer"; - const char ReleasesApiUrl[] = "http://api.zealdocs.org/v1/releases"; } @@ -61,32 +57,6 @@ Application::Application(QObject *parent) : Q_ASSERT(!m_instance); m_instance = this; - // A server for receiving messages from other application instances. - m_localServer = new QLocalServer(this); - connect(m_localServer, &QLocalServer::newConnection, [this]() { - QScopedPointer connection(m_localServer->nextPendingConnection()); - // Wait a little, while the other side writes the data. - if (connection->waitForReadyRead()) { - QDataStream in(connection.data()); - Zeal::SearchQuery query; - bool preventActivation; - in >> query; - in >> preventActivation; - - m_mainWindow->search(query); - - if (preventActivation) - return; - } - - m_mainWindow->bringToFront(); - }); - - // Remove in case previous instance crashed - // TODO: Verify if removeServer() is needed - QLocalServer::removeServer(LocalServerName); - m_localServer->listen(LocalServerName); - m_settings = new Settings(this); m_networkManager = new QNetworkAccessManager(this); @@ -136,28 +106,6 @@ Application *Application::instance() return m_instance; } -/*! - * \internal - * \brief Sends \a query to an already running application instance, if it exists. - * \param query A query to execute search with. - * \param preventActivation If \c true, application window will not activated. - * \return \c true if communication with another instance has been successful. - */ -bool Application::send(const SearchQuery &query, bool preventActivation) -{ - QScopedPointer socket(new QLocalSocket()); - socket->connectToServer(LocalServerName); - - if (!socket->waitForConnected(500)) - return false; - - QDataStream out(socket.data()); - out << query; - out << preventActivation; - socket->flush(); - return true; -} - QNetworkAccessManager *Application::networkManager() const { return m_networkManager; @@ -173,6 +121,16 @@ DocsetRegistry *Application::docsetRegistry() return m_docsetRegistry; } +void Application::executeQuery(const SearchQuery &query, bool preventActivation) +{ + m_mainWindow->search(query); + + if (preventActivation) + return; + + m_mainWindow->bringToFront(); +} + void Application::extract(const QString &filePath, const QString &destination, const QString &root) { QMetaObject::invokeMethod(m_extractor, "extract", Qt::QueuedConnection, diff --git a/src/core/application.h b/src/core/application.h index 01ad0b7af..06078c91e 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -25,7 +25,6 @@ #include -class QLocalServer; class QNetworkAccessManager; class QNetworkReply; class QThread; @@ -51,14 +50,13 @@ class Application : public QObject static Application *instance(); - static bool send(const SearchQuery &query, bool preventActivation); - QNetworkAccessManager *networkManager() const; Settings *settings() const; DocsetRegistry *docsetRegistry(); public slots: + void executeQuery(const SearchQuery &query, bool preventActivation); void extract(const QString &filePath, const QString &destination, const QString &root = QString()); QNetworkReply *download(const QUrl &url); void checkForUpdates(bool quiet = false); @@ -81,7 +79,6 @@ private slots: Settings *m_settings = nullptr; - QLocalServer *m_localServer = nullptr; QNetworkAccessManager *m_networkManager = nullptr; QThread *m_extractorThread = nullptr; diff --git a/src/core/localserver.cpp b/src/core/localserver.cpp new file mode 100644 index 000000000..07c703056 --- /dev/null +++ b/src/core/localserver.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2015-2016 Oleg Shparber +** Contact: https://go.zealdocs.org/l/contact +** +** This file is part of Zeal. +** +** Zeal 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. +** +** Zeal 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 Zeal. If not, see . +** +****************************************************************************/ + +#include "localserver.h" + +#include "registry/searchquery.h" + +#include +#include +#include +#include + +using namespace Zeal::Core; + +namespace { +const char LocalServerName[] = "ZealLocalServer"; +} + +LocalServer::LocalServer(QObject *parent) + : QObject(parent) + , m_localServer(new QLocalServer(this)) +{ + connect(m_localServer, &QLocalServer::newConnection, [this]() { + QScopedPointer connection(m_localServer->nextPendingConnection()); + // Wait while the other side writes the data. + if (!connection->waitForReadyRead(500)) + return; + + QDataStream in(connection.data()); + Zeal::SearchQuery query; + bool preventActivation; + in >> query; + in >> preventActivation; + + emit newQuery(query, preventActivation); + }); +} + +/*! + * \internal + * \brief Instructs server to listen for incoming connections. + * \param force If \c true, an attempt to remove socket file will be made. No effect on Windows. + * \return \c true if successful, \c false otherwise. + */ +bool LocalServer::start(bool force) +{ +#ifndef Q_OS_WIN32 + if (force && !QLocalServer::removeServer(LocalServerName)) { + return false; + } +#else + Q_UNUSED(force) +#endif + + return m_localServer->listen(LocalServerName); +} + +/*! + * \internal + * \brief Sends \a query to an already running application instance, if it exists. + * \param query A query to execute search with. + * \param preventActivation If \c true, application window will not activated. + * \return \c true if communication with another instance has been successful. + */ +bool LocalServer::sendQuery(const SearchQuery &query, bool preventActivation) +{ + QScopedPointer socket(new QLocalSocket()); + socket->connectToServer(LocalServerName); + + if (!socket->waitForConnected(500)) + return false; + + QDataStream out(socket.data()); + out << query; + out << preventActivation; + socket->flush(); + return true; +} diff --git a/src/core/localserver.h b/src/core/localserver.h new file mode 100644 index 000000000..62d04fa0c --- /dev/null +++ b/src/core/localserver.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015-2016 Oleg Shparber +** Contact: https://go.zealdocs.org/l/contact +** +** This file is part of Zeal. +** +** Zeal 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. +** +** Zeal 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 Zeal. If not, see . +** +****************************************************************************/ + +#ifndef ZEAL_CORE_LOCALSERVER_H +#define ZEAL_CORE_LOCALSERVER_H + +#include + +class QLocalServer; + +namespace Zeal { + +class SearchQuery; + +namespace Core { + +class LocalServer : public QObject +{ + Q_OBJECT +public: + explicit LocalServer(QObject *parent = 0); + + bool start(bool force = false); + + static bool sendQuery(const SearchQuery &query, bool preventActivation); + +signals: + void newQuery(const SearchQuery &query, bool preventActivation); + +private: + QLocalServer *m_localServer = nullptr; +}; + +} // namespace Core +} // namespace Zeal + +#endif // ZEAL_CORE_LOCALSERVER_H diff --git a/src/main.cpp b/src/main.cpp index 1fbb8543d..c7f0e2f68 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ ****************************************************************************/ #include "core/application.h" +#include "core/localserver.h" #include "registry/searchquery.h" #include @@ -191,10 +192,13 @@ int main(int argc, char *argv[]) } #endif - // Detect already running instance and optionally pass a search query to it. - if (!clParams.force && Core::Application::send(clParams.query, clParams.preventActivation)) + // Detect already running instance and optionally send the search query to it. + if (!clParams.force && Core::LocalServer::sendQuery(clParams.query, clParams.preventActivation)) return 0; + QScopedPointer localServer(new Core::LocalServer()); + localServer->start(); + // Check for SQLite plugin // TODO: Specific to docset format and should be handled accordingly in the future if (!QSqlDatabase::isDriverAvailable(QStringLiteral("QSQLITE"))) { @@ -209,9 +213,11 @@ int main(int argc, char *argv[]) QDir::setSearchPaths(QStringLiteral("typeIcon"), {QStringLiteral(":/icons/type")}); QScopedPointer app(new Core::Application()); + QObject::connect(localServer.data(), &Core::LocalServer::newQuery, + app.data(), &Core::Application::executeQuery); if (!clParams.query.isEmpty()) - Core::Application::send(clParams.query, clParams.preventActivation); + Core::LocalServer::sendQuery(clParams.query, clParams.preventActivation); return qapp->exec(); } From 222b3646787153030ce8716e6015633b98c1efaa Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 4 Jun 2016 22:24:21 -0400 Subject: [PATCH 162/273] core: Implement LocalServer::errorMessage() --- src/core/localserver.cpp | 10 ++++++++++ src/core/localserver.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/core/localserver.cpp b/src/core/localserver.cpp index 07c703056..5fb02243e 100644 --- a/src/core/localserver.cpp +++ b/src/core/localserver.cpp @@ -55,6 +55,16 @@ LocalServer::LocalServer(QObject *parent) }); } +/*! + * \internal + * \brief Returns the error message about the last occured error. + * \return Human-readable error message, or an empty string. + */ +QString LocalServer::errorString() const +{ + return m_localServer->errorString(); +} + /*! * \internal * \brief Instructs server to listen for incoming connections. diff --git a/src/core/localserver.h b/src/core/localserver.h index 62d04fa0c..c774cbc10 100644 --- a/src/core/localserver.h +++ b/src/core/localserver.h @@ -39,6 +39,8 @@ class LocalServer : public QObject public: explicit LocalServer(QObject *parent = 0); + QString errorString() const; + bool start(bool force = false); static bool sendQuery(const SearchQuery &query, bool preventActivation); From 1678282e637eb1c1e67fee9e420961e16b046c1b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 4 Jun 2016 22:26:39 -0400 Subject: [PATCH 163/273] app: Handle LocalServer errors (fixes #535) --- src/main.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index c7f0e2f68..0047f38b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,8 +38,14 @@ #include #endif +#include + using namespace Zeal; +namespace { +const char contactUrl[] = "https://go.zealdocs.org/l/contact"; +} + struct CommandLineParameters { bool force; @@ -197,7 +203,40 @@ int main(int argc, char *argv[]) return 0; QScopedPointer localServer(new Core::LocalServer()); - localServer->start(); + if (!localServer->start()) { + QScopedPointer msgBox(new QMessageBox()); + msgBox->setWindowTitle(QStringLiteral("Zeal")); + + msgBox->setIcon(QMessageBox::Warning); + msgBox->setText(QObject::tr("Another application instance can be still running, " + "or has crashed.
Make sure to start Zeal only once.")); + msgBox->addButton(QMessageBox::Help); + msgBox->addButton(QMessageBox::Retry); + QPushButton *quitButton = msgBox->addButton(QObject::tr("&Quit"), + QMessageBox::DestructiveRole); + msgBox->setDefaultButton(quitButton); + + switch (msgBox->exec()) { + case QMessageBox::Rejected: + return EXIT_SUCCESS; + case QMessageBox::Help: + QDesktopServices::openUrl(QUrl(contactUrl)); + } + + msgBox->removeButton(msgBox->button(QMessageBox::Retry)); + + if (!localServer->start(true)) { + msgBox->setIcon(QMessageBox::Critical); + msgBox->setText(QObject::tr("Zeal is unable to start. Please report the issue " + "providing the details below.")); + msgBox->setDetailedText(localServer->errorString()); + + if (msgBox->exec() == QMessageBox::Help) + QDesktopServices::openUrl(QUrl(contactUrl)); + + return EXIT_SUCCESS; + } + } // Check for SQLite plugin // TODO: Specific to docset format and should be handled accordingly in the future From 831720529d2dc49228ee5e82f6328b2cb2429ffd Mon Sep 17 00:00:00 2001 From: Vlad Date: Sun, 5 Jun 2016 18:52:10 +0300 Subject: [PATCH 164/273] ui: Implement tab duplication (fixes #524) (#538) --- src/ui/mainwindow.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++ src/ui/mainwindow.h | 1 + 2 files changed, 64 insertions(+) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 361c88bac..3b55f0df5 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -85,6 +85,41 @@ struct TabState #endif } + TabState(const TabState &rhs) + : searchQuery(rhs.searchQuery) + , selections(rhs.selections) + , expansions(rhs.expansions) + , searchScrollPosition(rhs.searchScrollPosition) + , tocScrollPosition(rhs.tocScrollPosition) + , webViewZoomFactor(rhs.webViewZoomFactor) + { + searchModel = new Zeal::SearchModel(); + tocModel = new Zeal::SearchModel(); + + webPage = new QWebPage(); +#ifndef USE_WEBENGINE + webPage->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); + webPage->setNetworkAccessManager(Core::Application::instance()->networkManager()); +#endif + + QByteArray historyArray = rhs.saveHistory(); + restoreHistory(historyArray); + } + + void restoreHistory(const QByteArray &array) const + { + QDataStream stream(array); + stream >> *webPage->history(); + } + + QByteArray saveHistory() const + { + QByteArray array; + QDataStream stream(&array, QIODevice::WriteOnly); + stream << *webPage->history(); + return array; + } + ~TabState() { delete searchModel; @@ -109,6 +144,15 @@ struct TabState #endif } + QString title() const + { +#ifdef USE_WEBENGINE + return webPage->title(); +#else + return webPage->mainFrame()->title(); +#endif + } + QString searchQuery; // Content/Search results tree view state @@ -155,6 +199,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(focusSearch, &QShortcut::activated, ui->lineEdit, static_cast(&SearchEdit::setFocus)); + QShortcut *duplicate = new QShortcut(QStringLiteral("Ctrl+Alt+T"), this); + connect(duplicate, &QShortcut::activated, this, [this]() { duplicateTab(m_tabBar->currentIndex()); }); + restoreGeometry(m_settings->windowGeometry); ui->splitter->restoreState(m_settings->verticalSplitterGeometry); @@ -470,6 +517,22 @@ void MainWindow::createTab(int index) m_tabBar->setCurrentIndex(index); } +void MainWindow::duplicateTab(int index) +{ + if (index < 0 || index >= m_tabStates.size()) + return; + + TabState *previous = m_tabStates.at(index++); + TabState *newTab = new TabState(*previous); + + connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); + connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); + + m_tabStates.insert(index, newTab); + m_tabBar->insertTab(index, newTab->title()); + m_tabBar->setCurrentIndex(index); +} + void MainWindow::displayTreeView() { TabState *tabState = currentTabState(); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index ecb56820c..d7971090e 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -93,6 +93,7 @@ private slots: void openDocset(const QModelIndex &index); void queryCompleted(); void closeTab(int index = -1); + void duplicateTab(int index); private: void displayViewActions(); From 8f7de119e9ec3ec7e5c576d47be538605a0975c6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 4 Jun 2016 23:44:26 -0400 Subject: [PATCH 165/273] app: Improve no SQLite error message box --- src/main.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0047f38b7..f2dea64c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -241,12 +241,17 @@ int main(int argc, char *argv[]) // Check for SQLite plugin // TODO: Specific to docset format and should be handled accordingly in the future if (!QSqlDatabase::isDriverAvailable(QStringLiteral("QSQLITE"))) { - const int ret = QMessageBox::critical(nullptr, QStringLiteral("Zeal"), - QObject::tr("Qt SQLite driver is not available."), - QMessageBox::Close | QMessageBox::Help); - if (ret == QMessageBox::Help) - QDesktopServices::openUrl(QUrl(QStringLiteral("https://go.zealdocs.org/l/contact"))); - return 0; + QScopedPointer msgBox(new QMessageBox()); + msgBox->setWindowTitle(QStringLiteral("Zeal")); + msgBox->setIcon(QMessageBox::Critical); + msgBox->setText(QObject::tr("Qt SQLite driver is not available.")); + msgBox->addButton(QMessageBox::Help); + QPushButton *quitButton = msgBox->addButton(QObject::tr("&Quit"), + QMessageBox::DestructiveRole); + msgBox->setDefaultButton(quitButton); + if (msgBox->exec() == QMessageBox::Help) + QDesktopServices::openUrl(QUrl(contactUrl)); + return EXIT_SUCCESS; } QDir::setSearchPaths(QStringLiteral("typeIcon"), {QStringLiteral(":/icons/type")}); From 218c3db16c7ce083db7e88a1dfc92f60833ede0f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 12:22:05 -0400 Subject: [PATCH 166/273] core: Do not define global shortcut by default (fixes #418) --- src/core/settings.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index e9b2446d2..3164be27e 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -83,11 +83,7 @@ void Settings::load() hideOnClose = m_settings->value(QStringLiteral("hide_on_close"), false).toBool(); m_settings->beginGroup(GroupGlobalShortcuts); -#ifndef Q_OS_OSX - showShortcut = m_settings->value(QStringLiteral("show"), QStringLiteral("Meta+Z")).value(); -#else - showShortcut = m_settings->value(QStringLiteral("show"), QStringLiteral("Alt+Space")).value(); -#endif + showShortcut = m_settings->value(QStringLiteral("show")).value(); m_settings->endGroup(); m_settings->beginGroup(GroupTabs); From f25d7e607772fd23d0e58399885efe02969af4b6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 13:42:55 -0400 Subject: [PATCH 167/273] 3rdparty,ui: Remove semicolons after Q_UNUSED --- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp | 4 ++-- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp | 4 ++-- src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp | 2 +- src/ui/mainwindow.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp index cc74c79e6..573a51231 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp @@ -66,8 +66,8 @@ static bool qxt_mac_handler_installed = false; OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void *data) { - Q_UNUSED(nextHandler); - Q_UNUSED(data); + Q_UNUSED(nextHandler) + Q_UNUSED(data) if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) { EventHotKeyID keyID; GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID); diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp index 849d18413..6f3d4a01b 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp @@ -57,8 +57,8 @@ bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { - Q_UNUSED(eventType); - Q_UNUSED(result); + Q_UNUSED(eventType) + Q_UNUSED(result) MSG *msg = static_cast(message); if (msg->message == WM_HOTKEY) { diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp index b4f343098..228ff1e37 100644 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp +++ b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp @@ -70,7 +70,7 @@ const QVector maskModifiers = { bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { - Q_UNUSED(result); + Q_UNUSED(result) if (eventType != "xcb_generic_event_t") return false; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 3b55f0df5..95e6b3063 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -720,7 +720,7 @@ void MainWindow::detectAppIndicatorSupport() #ifdef USE_APPINDICATOR void appIndicatorToggleWindow(GtkMenu *menu, gpointer data) { - Q_UNUSED(menu); + Q_UNUSED(menu) static_cast(data)->toggleWindow(); } #endif From 8c7c1001c0cb500dbef1b20efb57137cd7204373 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 13:44:34 -0400 Subject: [PATCH 168/273] ui: Do not show menu indicators for back/forward buttons --- src/ui/forms/mainwindow.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 9906b1fd6..9597a6aa4 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -136,6 +136,9 @@ Go back one page + + QToolButton::menu-indicator { image: none; } + @@ -149,6 +152,9 @@ Go forward one page + + QToolButton::menu-indicator { image: none; } + From baac06f75cdb86851f0bcaadb771e328b5b79048 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 16:49:41 -0400 Subject: [PATCH 169/273] registry: Add a copy constructor to SearchModel --- src/registry/searchmodel.cpp | 6 ++++++ src/registry/searchmodel.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/registry/searchmodel.cpp b/src/registry/searchmodel.cpp index 25be61958..ae98b5531 100644 --- a/src/registry/searchmodel.cpp +++ b/src/registry/searchmodel.cpp @@ -34,6 +34,12 @@ SearchModel::SearchModel(QObject *parent) : { } +SearchModel::SearchModel(const SearchModel &other) : + QAbstractItemModel(other.d_ptr->parent), + m_dataList(other.m_dataList) +{ +} + bool SearchModel::isEmpty() const { return m_dataList.isEmpty(); diff --git a/src/registry/searchmodel.h b/src/registry/searchmodel.h index 941741cdd..51ec39ced 100644 --- a/src/registry/searchmodel.h +++ b/src/registry/searchmodel.h @@ -40,6 +40,7 @@ class SearchModel : public QAbstractItemModel }; explicit SearchModel(QObject *parent = nullptr); + SearchModel(const SearchModel &other); bool isEmpty() const; From cea52c6a21ee7bb3802c4e76014d79821981c9dd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 16:50:33 -0400 Subject: [PATCH 170/273] ui: Fix missing search results in duplicated tabs --- src/ui/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 95e6b3063..60c523b9c 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -93,8 +93,8 @@ struct TabState , tocScrollPosition(rhs.tocScrollPosition) , webViewZoomFactor(rhs.webViewZoomFactor) { - searchModel = new Zeal::SearchModel(); - tocModel = new Zeal::SearchModel(); + searchModel = new Zeal::SearchModel(*rhs.searchModel); + tocModel = new Zeal::SearchModel(*rhs.tocModel); webPage = new QWebPage(); #ifndef USE_WEBENGINE From a26e12c456d74b7e65d07bb4a866a71a6170df82 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 17:21:29 -0400 Subject: [PATCH 171/273] ui: Slightly refactor the tab duplication code --- src/ui/mainwindow.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 60c523b9c..118b2d4de 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -85,16 +85,16 @@ struct TabState #endif } - TabState(const TabState &rhs) - : searchQuery(rhs.searchQuery) - , selections(rhs.selections) - , expansions(rhs.expansions) - , searchScrollPosition(rhs.searchScrollPosition) - , tocScrollPosition(rhs.tocScrollPosition) - , webViewZoomFactor(rhs.webViewZoomFactor) + TabState(const TabState &other) + : searchQuery(other.searchQuery) + , selections(other.selections) + , expansions(other.expansions) + , searchScrollPosition(other.searchScrollPosition) + , tocScrollPosition(other.tocScrollPosition) + , webViewZoomFactor(other.webViewZoomFactor) { - searchModel = new Zeal::SearchModel(*rhs.searchModel); - tocModel = new Zeal::SearchModel(*rhs.tocModel); + searchModel = new Zeal::SearchModel(*other.searchModel); + tocModel = new Zeal::SearchModel(*other.tocModel); webPage = new QWebPage(); #ifndef USE_WEBENGINE @@ -102,8 +102,7 @@ struct TabState webPage->setNetworkAccessManager(Core::Application::instance()->networkManager()); #endif - QByteArray historyArray = rhs.saveHistory(); - restoreHistory(historyArray); + restoreHistory(other.saveHistory()); } void restoreHistory(const QByteArray &array) const @@ -522,12 +521,11 @@ void MainWindow::duplicateTab(int index) if (index < 0 || index >= m_tabStates.size()) return; - TabState *previous = m_tabStates.at(index++); - TabState *newTab = new TabState(*previous); - + TabState *newTab = new TabState(*m_tabStates.at(index)); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); + ++index; m_tabStates.insert(index, newTab); m_tabBar->insertTab(index, newTab->title()); m_tabBar->setCurrentIndex(index); From 7778f5187bd06ae3f37fba8b2984514bfd202981 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 17:26:00 -0400 Subject: [PATCH 172/273] ui: Set icons for back and forward actions --- src/ui/forms/mainwindow.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 9597a6aa4..3cfa00565 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -273,11 +273,17 @@
+ + + &Back + + + &Forward From d8b90efc2ef75862c7006f7c57bb30f751bbfd97 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 17:32:07 -0400 Subject: [PATCH 173/273] ui: Disable back and forward actions by default --- src/ui/forms/mainwindow.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 3cfa00565..391decffd 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -273,6 +273,9 @@ + + false + @@ -281,6 +284,9 @@ + + false + From 0f0cec1f8eac9215e9a4b932961337c5e8c6a684 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 19:34:42 -0400 Subject: [PATCH 174/273] ui: Remove history items from the View menu This changes makes the back and forward menus to be rebuilt on the fly, only when requested. Also fixes the order of items in the backward menu. --- src/ui/mainwindow.cpp | 54 ++++++++++++++++--------------------------- src/ui/mainwindow.h | 1 - 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 118b2d4de..ea7bfe8a9 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -266,13 +266,31 @@ 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(); + QList items = history->backItems(10); + for (auto it = items.rbegin(); it != items.rend(); ++it) { + const QIcon icon = docsetIcon(docsetName(it->url())); + const QWebHistoryItem item = *it; + m_backMenu->addAction(icon, it->title(), [=](bool) { history->goToItem(item); }); + } + }); + ui->backButton->setDefaultAction(ui->actionBack); ui->backButton->setMenu(m_backMenu); m_forwardMenu = new QMenu(ui->forwardButton); + connect(m_forwardMenu, &QMenu::aboutToShow, this, [this]() { + m_forwardMenu->clear(); + QWebHistory *history = currentTabState()->webPage->history(); + for (const QWebHistoryItem &item: history->forwardItems(10)) { + const QIcon icon = docsetIcon(docsetName(item.url())); + m_forwardMenu->addAction(icon, item.title(), [=](bool) { history->goToItem(item); }); + } + }); + ui->forwardButton->setDefaultAction(ui->actionForward); ui->forwardButton->setMenu(m_forwardMenu); - displayViewActions(); - // treeView and lineEdit ui->lineEdit->setTreeView(ui->treeView); ui->lineEdit->setFocus(); @@ -296,8 +314,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->tocListView, &QListView::clicked, this, &MainWindow::openDocset); connect(ui->treeView, &QTreeView::activated, this, &MainWindow::openDocset); connect(ui->tocListView, &QListView::activated, this, &MainWindow::openDocset); - connect(ui->forwardButton, &QPushButton::clicked, ui->webView, &SearchableWebView::forward); - connect(ui->backButton, &QPushButton::clicked, ui->webView, &SearchableWebView::back); connect(ui->webView, &SearchableWebView::urlChanged, [this](const QUrl &url) { const QString name = docsetName(url); @@ -662,37 +678,7 @@ void MainWindow::setupTabBar() void MainWindow::displayViewActions() { ui->actionBack->setEnabled(ui->webView->canGoBack()); - ui->backButton->setEnabled(ui->webView->canGoBack()); ui->actionForward->setEnabled(ui->webView->canGoForward()); - ui->forwardButton->setEnabled(ui->webView->canGoForward()); - - ui->menuView->clear(); - ui->menuView->addAction(ui->actionBack); - ui->menuView->addAction(ui->actionForward); - ui->menuView->addSeparator(); - - m_backMenu->clear(); - m_forwardMenu->clear(); - - QWebHistory *history = ui->webView->page()->history(); - for (const QWebHistoryItem &item: history->backItems(10)) - m_backMenu->addAction(addHistoryAction(history, item)); - if (history->count() > 0) - addHistoryAction(history, history->currentItem())->setEnabled(false); - for (const QWebHistoryItem &item: history->forwardItems(10)) - m_forwardMenu->addAction(addHistoryAction(history, item)); -} - -QAction *MainWindow::addHistoryAction(QWebHistory *history, const QWebHistoryItem &item) -{ - const QIcon icon = docsetIcon(docsetName(item.url())); - QAction *backAction = new QAction(icon, item.title(), ui->menuView); - ui->menuView->addAction(backAction); - connect(backAction, &QAction::triggered, [=](bool) { - history->goToItem(item); - }); - - return backAction; } #ifdef USE_APPINDICATOR diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index d7971090e..0ee02867e 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -106,7 +106,6 @@ private slots: QString docsetName(const QUrl &url) const; QIcon docsetIcon(const QString &docsetName) const; - QAction *addHistoryAction(QWebHistory *history, const QWebHistoryItem &item); #ifdef USE_APPINDICATOR void detectAppIndicatorSupport(); From eb77035dea7aa0360b8742bffecdc90f27fda9ce Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 19:44:08 -0400 Subject: [PATCH 175/273] ui: Rename view synchronization methods in MainWindow --- src/ui/mainwindow.cpp | 17 +++++++++-------- src/ui/mainwindow.h | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ea7bfe8a9..1e948a600 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -382,7 +382,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_application->docsetRegistry()->search(text); if (text.isEmpty()) { currentTabState()->tocModel->setResults(); - displayTreeView(); + syncTreeView(); } }); @@ -489,7 +489,7 @@ QIcon MainWindow::docsetIcon(const QString &docsetName) const void MainWindow::queryCompleted() { - displayTreeView(); + syncTreeView(); ui->treeView->setCurrentIndex(currentTabState()->searchModel->index(0, 0, QModelIndex())); openDocset(ui->treeView->currentIndex()); @@ -523,7 +523,7 @@ void MainWindow::createTab(int index) TabState *newTab = new TabState(); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); - connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); + connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::syncToc); newTab->loadUrl(QUrl(startPageUrl)); @@ -539,7 +539,7 @@ void MainWindow::duplicateTab(int index) TabState *newTab = new TabState(*m_tabStates.at(index)); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); - connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::toggleToc); + connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::syncToc); ++index; m_tabStates.insert(index, newTab); @@ -547,7 +547,7 @@ void MainWindow::duplicateTab(int index) m_tabBar->setCurrentIndex(index); } -void MainWindow::displayTreeView() +void MainWindow::syncTreeView() { TabState *tabState = currentTabState(); @@ -559,10 +559,11 @@ void MainWindow::displayTreeView() ui->treeView->setColumnHidden(1, true); ui->treeView->setRootIsDecorated(true); } + ui->treeView->reset(); } -void MainWindow::toggleToc() +void MainWindow::syncToc() { if (!currentTabState()->tocModel->isEmpty()) { ui->tocListView->show(); @@ -630,8 +631,8 @@ void MainWindow::setupTabBar() ui->lineEdit->setText(tabState->searchQuery); ui->tocListView->setModel(tabState->tocModel); - toggleToc(); - displayTreeView(); + syncTreeView(); + syncToc(); // Bring back the selections and expansions ui->treeView->blockSignals(true); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 0ee02867e..5e98d4c02 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -97,8 +97,8 @@ private slots: private: void displayViewActions(); - void displayTreeView(); - void toggleToc(); + void syncTreeView(); + void syncToc(); void setupSearchBoxCompletions(); void setupTabBar(); From d21402cd767f603202d70111ee778bcae5388969 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 19:44:55 -0400 Subject: [PATCH 176/273] ui: Remove MainWindow::displayViewActions() --- src/ui/mainwindow.cpp | 14 +++++--------- src/ui/mainwindow.h | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 1e948a600..7199c24b8 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -323,7 +323,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : if (docset) currentTabState()->tocModel->setResults(docset->relatedLinks(url)); - displayViewActions(); + ui->actionBack->setEnabled(ui->webView->canGoBack()); + ui->actionForward->setEnabled(ui->webView->canGoForward()); }); connect(ui->webView, &SearchableWebView::titleChanged, [this](const QString &title) { @@ -645,10 +646,11 @@ void MainWindow::setupTabBar() ui->webView->setPage(tabState->webPage); ui->webView->setZoomFactor(tabState->webViewZoomFactor); + ui->actionBack->setEnabled(ui->webView->canGoBack()); + ui->actionForward->setEnabled(ui->webView->canGoForward()); + ui->treeView->verticalScrollBar()->setValue(tabState->searchScrollPosition); ui->tocListView->verticalScrollBar()->setValue(tabState->tocScrollPosition); - - displayViewActions(); }); connect(m_tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::closeTab); @@ -676,12 +678,6 @@ void MainWindow::setupTabBar() layout->insertWidget(2, m_tabBar, 0, Qt::AlignBottom); } -void MainWindow::displayViewActions() -{ - ui->actionBack->setEnabled(ui->webView->canGoBack()); - ui->actionForward->setEnabled(ui->webView->canGoForward()); -} - #ifdef USE_APPINDICATOR void MainWindow::detectAppIndicatorSupport() { diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 5e98d4c02..21d210376 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -96,7 +96,6 @@ private slots: void duplicateTab(int index); private: - void displayViewActions(); void syncTreeView(); void syncToc(); void setupSearchBoxCompletions(); From 5534c662b667e5cb3e8559ef16b27d8dc344b9af Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 19:46:35 -0400 Subject: [PATCH 177/273] ui: Remove the View menu --- src/ui/forms/mainwindow.ui | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ui/forms/mainwindow.ui b/src/ui/forms/mainwindow.ui index 391decffd..daebae94d 100644 --- a/src/ui/forms/mainwindow.ui +++ b/src/ui/forms/mainwindow.ui @@ -223,13 +223,6 @@ - - - &View - - - - &Edit @@ -240,7 +233,6 @@ - From 7ddee54aad13b1af030d637b4d7c35c8913a077f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 20:52:47 -0400 Subject: [PATCH 178/273] ui: Fix building with Qt 5.2 --- src/ui/mainwindow.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 7199c24b8..6db4aa2d0 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -273,7 +273,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : for (auto it = items.rbegin(); it != items.rend(); ++it) { const QIcon icon = docsetIcon(docsetName(it->url())); const QWebHistoryItem item = *it; - m_backMenu->addAction(icon, it->title(), [=](bool) { history->goToItem(item); }); + // TODO: [Qt 5.6] + // m_backMenu->addAction(icon, it->title(), [=](bool) { history->goToItem(item); }); + QAction *action = m_backMenu->addAction(icon, it->title()); + connect(action, &QAction::triggered, [=](bool) { history->goToItem(item); }); } }); ui->backButton->setDefaultAction(ui->actionBack); @@ -285,7 +288,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QWebHistory *history = currentTabState()->webPage->history(); for (const QWebHistoryItem &item: history->forwardItems(10)) { const QIcon icon = docsetIcon(docsetName(item.url())); - m_forwardMenu->addAction(icon, item.title(), [=](bool) { history->goToItem(item); }); + // TODO: [Qt 5.6] + //m_forwardMenu->addAction(icon, item.title(), [=](bool) { history->goToItem(item); }); + QAction *action = m_forwardMenu->addAction(icon, item.title()); + connect(action, &QAction::triggered, [=](bool) { history->goToItem(item); }); } }); ui->forwardButton->setDefaultAction(ui->actionForward); From 134e62214d86a84dbe1af15bc1dda03c612c6eac Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 21:19:43 -0400 Subject: [PATCH 179/273] ui: Fix building with Qt 5.2 one more time --- src/ui/mainwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 6db4aa2d0..8e2c3a4f7 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -270,7 +270,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_backMenu->clear(); QWebHistory *history = currentTabState()->webPage->history(); QList items = history->backItems(10); - for (auto it = items.rbegin(); it != items.rend(); ++it) { + // TODO: [Qt 5.6] + //for (auto it = items.crbegin(); it != items.crend(); ++it) { + for (auto it = items.cend() - 1; it != items.cbegin(); --it) { const QIcon icon = docsetIcon(docsetName(it->url())); const QWebHistoryItem item = *it; // TODO: [Qt 5.6] From 26fd6c802dd912cd4afa6e05d7d8eeb3d144d430 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 21:30:51 -0400 Subject: [PATCH 180/273] ui: Use the current docset storage path in the directory chooser --- src/ui/settingsdialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 0b6722bad..aec39b8f0 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -519,7 +519,8 @@ void SettingsDialog::on_downloadDocsetButton_clicked() void SettingsDialog::on_storageButton_clicked() { - const QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory")); + const QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), + ui->storageEdit->text()); if (!dir.isEmpty()) ui->storageEdit->setText(QDir::toNativeSeparators(dir)); From aa42fcc3e13aa3be4c1d95be07012d5f4b6ff039 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 21:49:31 -0400 Subject: [PATCH 181/273] ui: Update available docset list if storage changes (fixes #475) --- src/ui/settingsdialog.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index aec39b8f0..a2d6f5f65 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -117,6 +117,20 @@ SettingsDialog::SettingsDialog(Core::Application *app, QWidget *parent) : this, &SettingsDialog::updateDocsetFilter); ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); + connect(m_docsetRegistry, &DocsetRegistry::docsetRemoved, this, [this](const QString name) { + QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); + if (!item) + return; + + item->setHidden(false); + }); + connect(m_docsetRegistry, &DocsetRegistry::docsetAdded, this, [this](const QString name) { + QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); + if (!item) + return; + + item->setHidden(true); + }); // Setup signals & slots connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::saveSettings); From 2f546ee93abf3911a4e956ec437a67932d819f4e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 23:31:02 -0400 Subject: [PATCH 182/273] ci: Fix indentation in .shippable.yml --- .shippable.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index 3568b6336..76c1c2a3c 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -1,6 +1,6 @@ build: - ci: - - shippable_retry sudo apt-get -y -qq update - - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev - - qmake - - make + ci: + - shippable_retry sudo apt-get -y -qq update + - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev + - qmake + - make From 129aed9b4ac95314b07c6b73bc843753275a8e43 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 23:32:27 -0400 Subject: [PATCH 183/273] ci: Make Shippable use Ubuntu 12.04 based C image --- .shippable.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.shippable.yml b/.shippable.yml index 76c1c2a3c..b958f0279 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -1,4 +1,11 @@ +language: c +compiler: + - gcc build: + pre_ci_boot: + image_name: drydock/u12cpp + image_tag: tip + pull: false ci: - shippable_retry sudo apt-get -y -qq update - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev From 2d697e52029f1e49e10d1103ca3397d205b2e7df Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 23:35:19 -0400 Subject: [PATCH 184/273] ci: Pull Shippable image from the Docker registry --- .shippable.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.shippable.yml b/.shippable.yml index b958f0279..1f69ae6e7 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -5,7 +5,7 @@ build: pre_ci_boot: image_name: drydock/u12cpp image_tag: tip - pull: false + pull: true ci: - shippable_retry sudo apt-get -y -qq update - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev From 9ce18bfee070f4e60208b23bdc8348b2e2ab989c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 5 Jun 2016 23:41:40 -0400 Subject: [PATCH 185/273] ci[shippable]: Use Ubuntu 14.04 image --- .shippable.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.shippable.yml b/.shippable.yml index 1f69ae6e7..1a1ff3619 100644 --- a/.shippable.yml +++ b/.shippable.yml @@ -2,10 +2,6 @@ language: c compiler: - gcc build: - pre_ci_boot: - image_name: drydock/u12cpp - image_tag: tip - pull: true ci: - shippable_retry sudo apt-get -y -qq update - shippable_retry sudo apt-get -y -qq install --no-install-recommends qt5-default libqt5webkit5-dev libqt5x11extras5-dev libarchive-dev libxcb-keysyms1-dev From 58bed936e2c94bccf7ff5ec5a630c1eb59d99628 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 13 Jun 2016 05:30:19 -0400 Subject: [PATCH 186/273] ui: Fix backward navigation menu --- src/ui/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 8e2c3a4f7..f4373af68 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -272,7 +272,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QList items = history->backItems(10); // TODO: [Qt 5.6] //for (auto it = items.crbegin(); it != items.crend(); ++it) { - for (auto it = items.cend() - 1; it != items.cbegin(); --it) { + for (auto it = items.cend() - 1; it >= items.cbegin(); --it) { const QIcon icon = docsetIcon(docsetName(it->url())); const QWebHistoryItem item = *it; // TODO: [Qt 5.6] From 2c6fa6161773db618b510080cc22905c574a1f49 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 13 Jun 2016 20:24:19 -0400 Subject: [PATCH 187/273] ui: Fix redundant QString copying --- src/ui/aboutdialog.cpp | 4 ++-- src/ui/mainwindow.cpp | 7 ++++--- src/ui/settingsdialog.cpp | 9 ++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index 27ae9bbb9..32ebdfe40 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -32,8 +32,8 @@ AboutDialog::AboutDialog(QWidget *parent) : ui->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - const QString buildInfo = QString(tr("Version: %1
")) - .arg(QCoreApplication::applicationVersion()); + const QString buildInfo + = tr("Version: %1
").arg(QCoreApplication::applicationVersion()); ui->buildInfoLabel->setText(buildInfo); ui->buttonBox->setFocus(Qt::OtherFocusReason); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index f4373af68..ffb5807c5 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -258,9 +258,10 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : return; } - const int ret = QMessageBox::information(this, QStringLiteral("Zeal"), - QString(tr("Zeal %1 is available. Open download page?")).arg(version), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + const int ret + = QMessageBox::information(this, QStringLiteral("Zeal"), + tr("Zeal %1 is available. Open download page?").arg(version), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (ret == QMessageBox::Yes) QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/download.html"))); }); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index a2d6f5f65..4dffeb406 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -214,11 +214,10 @@ void SettingsDialog::removeSelectedDocsets() if (selectonModel->selectedIndexes().count() == 1) { const QString docsetTitle = selectonModel->selectedIndexes().first().data().toString(); ret = QMessageBox::question(this, QStringLiteral("Zeal"), - QString(tr("Remove %1 docset?")) - .arg(docsetTitle)); + tr("Remove %1 docset?").arg(docsetTitle)); } else { ret = QMessageBox::question(this, QStringLiteral("Zeal"), - QString(tr("Remove %1 docsets?")) + tr("Remove %1 docsets?") .arg(selectonModel->selectedIndexes().count())); } @@ -484,7 +483,7 @@ void SettingsDialog::extractionError(const QString &filePath, const QString &err { const QString docsetName = QFileInfo(filePath).baseName() + QLatin1String(".docset"); QMessageBox::warning(this, QStringLiteral("Zeal"), - QString(tr("Cannot extract docset %1: %2")).arg(docsetName, errorString)); + tr("Cannot extract docset %1: %2").arg(docsetName, errorString)); // TODO: Update list item state (hide progress bar) delete m_tmpFiles.take(docsetName); } @@ -714,7 +713,7 @@ void SettingsDialog::removeDocsets(const QStringList &names) connect(watcher, &QFutureWatcher::finished, [=] { if (!watcher->result()) { QMessageBox::warning(this, QStringLiteral("Zeal"), - QString(tr("Cannot delete docset %1!")).arg(title)); + tr("Cannot delete docset %1!").arg(title)); } resetProgress(); From af11f38f2ca6460dafcfaa926ab94db3f7154dfe Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 13 Jun 2016 20:30:35 -0400 Subject: [PATCH 188/273] ui: Do not use obsolete QMessageBox methods --- src/ui/mainwindow.cpp | 4 +++- src/ui/settingsdialog.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ffb5807c5..ec75166a3 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -261,7 +261,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : const int ret = QMessageBox::information(this, QStringLiteral("Zeal"), tr("Zeal %1 is available. Open download page?").arg(version), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape, + QMessageBox::NoButton); if (ret == QMessageBox::Yes) QDesktopServices::openUrl(QUrl(QStringLiteral("https://zealdocs.org/download.html"))); }); diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 4dffeb406..b6ab534b9 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -260,7 +260,9 @@ void SettingsDialog::downloadCompleted() if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::OperationCanceledError) { const int ret = QMessageBox::warning(this, QStringLiteral("Zeal"), reply->errorString(), - QMessageBox::Ok | QMessageBox::Retry); + QMessageBox::Retry | QMessageBox::Default, + QMessageBox::Cancel | QMessageBox::Escape, + QMessageBox::NoButton); if (ret == QMessageBox::Retry) { QNetworkReply *newReply = download(reply->request().url()); From 6f9339833b2babb5f7525ad387577da77877a536 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 19 Jun 2016 03:52:07 -0400 Subject: [PATCH 189/273] ui: Remove unnecessary condition when saving TOC splitter state --- src/ui/mainwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index ec75166a3..a6e86f863 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -315,8 +315,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->tocListView->setItemDelegate(new SearchItemDelegate(ui->tocListView)); connect(ui->tocSplitter, &QSplitter::splitterMoved, this, [this]() { - if (ui->tocListView->isVisible()) - m_settings->tocSplitterState = ui->tocSplitter->saveState(); + m_settings->tocSplitterState = ui->tocSplitter->saveState(); }); createTab(); From fd11923a3c7638ea0932a0479db34ac94b5b1a70 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 18 Jul 2016 23:58:52 -0400 Subject: [PATCH 190/273] ui: Delay loading a page until user stops typing a query Based on work by Artur Spychaj submitted in #460. Related #265, #523. Closes #564. --- src/ui/mainwindow.cpp | 25 +++++++++++++++++++++---- src/ui/mainwindow.h | 3 +++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a6e86f863..b4eba7c2f 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef USE_WEBENGINE #include @@ -174,7 +175,8 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : m_application(app), m_settings(app->settings()), m_zealListModel(new ListModel(app->docsetRegistry(), this)), - m_globalShortcut(new QxtGlobalShortcut(m_settings->showShortcut, this)) + m_globalShortcut(new QxtGlobalShortcut(m_settings->showShortcut, this)), + m_openDocsetTimer(new QTimer(this)) { ui->setupUi(this); @@ -397,6 +399,20 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } }); + // Setup delayed navigation to a page until user makes a pause in typing a search query. + m_openDocsetTimer->setInterval(400); + m_openDocsetTimer->setSingleShot(true); + connect(m_openDocsetTimer, &QTimer::timeout, this, [this]() { + QModelIndex index = m_openDocsetTimer->property("index").toModelIndex(); + if (!index.isValid()) + return; + + openDocset(index); + + // Get focus back. QWebPageEngine::load() always steals focus. + ui->lineEdit->setFocus(Qt::MouseFocusReason); + }); + ui->actionNewTab->setShortcut(QKeySequence::AddTab); connect(ui->actionNewTab, &QAction::triggered, this, [this]() { createTab(); }); addAction(ui->actionNewTab); @@ -500,13 +516,14 @@ QIcon MainWindow::docsetIcon(const QString &docsetName) const void MainWindow::queryCompleted() { + m_openDocsetTimer->stop(); + syncTreeView(); ui->treeView->setCurrentIndex(currentTabState()->searchModel->index(0, 0, QModelIndex())); - openDocset(ui->treeView->currentIndex()); - // Get focus back. QWebPageEngine::load() always steals focus. - ui->lineEdit->setFocus(Qt::MouseFocusReason); + m_openDocsetTimer->setProperty("index", ui->treeView->currentIndex()); + m_openDocsetTimer->start(); } void MainWindow::closeTab(int index) diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 21d210376..f4ee21365 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -51,6 +51,7 @@ class QxtGlobalShortcut; class QModelIndex; class QSystemTrayIcon; class QTabBar; +class QTimer; namespace Ui { class MainWindow; @@ -128,6 +129,8 @@ private slots: QSystemTrayIcon *m_trayIcon = nullptr; + QTimer *m_openDocsetTimer = nullptr; + #ifdef USE_APPINDICATOR bool m_useAppIndicator = false; _AppIndicator *m_appIndicator = nullptr; From c8464b6928ce27413dec7db8c2745b77af91f47d Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Fri, 4 Dec 2015 21:30:08 -0800 Subject: [PATCH 191/273] registry: Allow to cancel current searches When user types into the search box the previous search is canceled. This improves the speed with which the results can be obtained. Based on #460 plus cosmetic changes. Related to #265, #523. --- src/registry/cancellationtoken.cpp | 40 +++++++++++++++++++++++++ src/registry/cancellationtoken.h | 47 ++++++++++++++++++++++++++++++ src/registry/docsetregistry.cpp | 18 +++++++----- src/registry/docsetregistry.h | 6 ++-- src/ui/mainwindow.cpp | 4 ++- src/ui/mainwindow.h | 3 ++ 6 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 src/registry/cancellationtoken.cpp create mode 100644 src/registry/cancellationtoken.h diff --git a/src/registry/cancellationtoken.cpp b/src/registry/cancellationtoken.cpp new file mode 100644 index 000000000..e8e2b8785 --- /dev/null +++ b/src/registry/cancellationtoken.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Artur Spychaj +** Contact: http://zealdocs.org/contact.html +** +** This file is part of Zeal. +** +** Zeal 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. +** +** Zeal 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 Zeal. If not, see . +** +****************************************************************************/ + +#include "cancellationtoken.h" + +using namespace Zeal; + +CancellationToken::CancellationToken() +{ + m_cancelled = QSharedPointer(new bool(false)); +} + +void CancellationToken::cancel() +{ + *m_cancelled = true; +} + +bool CancellationToken::isCanceled() const +{ + return *m_cancelled; +} diff --git a/src/registry/cancellationtoken.h b/src/registry/cancellationtoken.h new file mode 100644 index 000000000..75222d554 --- /dev/null +++ b/src/registry/cancellationtoken.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Artur Spychaj +** Contact: http://zealdocs.org/contact.html +** +** This file is part of Zeal. +** +** Zeal 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. +** +** Zeal 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 Zeal. If not, see . +** +****************************************************************************/ + +#ifndef CANCELLATIONTOKEN_H +#define CANCELLATIONTOKEN_H + +#include + +namespace Zeal { + +/// Token that stores whether cancel was called on it. +/// In async code can be used to check if another thread called cancel. +struct CancellationToken +{ +public: + CancellationToken(); + bool isCanceled() const; + void cancel(); + +private: + QSharedPointer m_cancelled; +}; + +} + +Q_DECLARE_METATYPE(Zeal::CancellationToken) + +#endif // CANCELLATIONTOKEN_H diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index ef0ea5d55..81ccb6c08 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -23,6 +23,7 @@ #include "docsetregistry.h" +#include "cancellationtoken.h" #include "searchresult.h" #include @@ -35,6 +36,7 @@ DocsetRegistry::DocsetRegistry(QObject *parent) : m_thread(new QThread(this)) { // Register for use in signal connections. + qRegisterMetaType("CancellationToken"); qRegisterMetaType>("QList"); // FIXME: Only search should be performed in a separate thread @@ -122,21 +124,21 @@ void DocsetRegistry::_addDocset(const QString &path) emit docsetAdded(name); } -void DocsetRegistry::search(const QString &query) +void DocsetRegistry::search(const QString &query, const CancellationToken &token) { - // Only invalidate queries - if (query.isEmpty()) - return; - - QMetaObject::invokeMethod(this, "_runQuery", Qt::QueuedConnection, Q_ARG(QString, query)); + QMetaObject::invokeMethod(this, "_runQuery", Qt::QueuedConnection, + Q_ARG(QString, query), Q_ARG(CancellationToken, token)); } -void DocsetRegistry::_runQuery(const QString &query) +void DocsetRegistry::_runQuery(const QString &query, const CancellationToken &token) { QList results; - for (Docset *docset : docsets()) + for (Docset *docset : docsets()) { + if (token.isCanceled()) + return; results << docset->search(query); + } std::sort(results.begin(), results.end()); diff --git a/src/registry/docsetregistry.h b/src/registry/docsetregistry.h index bac4c3cc6..936b89a47 100644 --- a/src/registry/docsetregistry.h +++ b/src/registry/docsetregistry.h @@ -32,6 +32,7 @@ class QThread; namespace Zeal { +struct CancellationToken; struct SearchResult; class DocsetRegistry : public QObject @@ -52,7 +53,8 @@ class DocsetRegistry : public QObject Docset *docset(int index) const; QList docsets() const; - void search(const QString &query); + void search(const QString &query, const CancellationToken &token); + const QList &queryResults(); public slots: void addDocset(const QString &path); @@ -65,7 +67,7 @@ public slots: private slots: void _addDocset(const QString &path); - void _runQuery(const QString &query); + void _runQuery(const QString &query, const CancellationToken &token); private: void addDocsetsFromFolder(const QString &path); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index b4eba7c2f..fe92ad5ec 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -392,7 +392,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : return; currentTabState()->searchQuery = text; - m_application->docsetRegistry()->search(text); + m_cancelSearch.cancel(); + m_cancelSearch = CancellationToken(); + m_application->docsetRegistry()->search(text, m_cancelSearch); if (text.isEmpty()) { currentTabState()->tocModel->setResults(); syncTreeView(); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index f4ee21365..1ded8e4ce 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -25,6 +25,7 @@ #define MAINWINDOW_H #include "registry/searchquery.h" +#include "registry/cancellationtoken.h" #include @@ -123,6 +124,8 @@ private slots: QMenu *m_backMenu = nullptr; QMenu *m_forwardMenu = nullptr; + Zeal::CancellationToken m_cancelSearch; + QxtGlobalShortcut *m_globalShortcut = nullptr; QTabBar *m_tabBar = nullptr; From cb99a89fe07b08625f55dc563da3774057ac50bd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 20 Jul 2016 01:58:33 -0400 Subject: [PATCH 192/273] Add support for search cancellation within Docset::search() Based on #460. --- src/registry/docset.cpp | 5 +++-- src/registry/docset.h | 3 ++- src/registry/docsetregistry.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index e0ddaca02..66149ffd5 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -23,6 +23,7 @@ #include "docset.h" +#include "cancellationtoken.h" #include "searchquery.h" #include "searchresult.h" #include "util/plist.h" @@ -243,7 +244,7 @@ const QMap &Docset::symbols(const QString &symbolType) const return m_symbols[symbolType]; } -QList Docset::search(const QString &query) const +QList Docset::search(const QString &query, const CancellationToken &token) const { QList results; @@ -262,7 +263,7 @@ QList Docset::search(const QString &query) const QString subNames = QStringLiteral(" OR %1 LIKE '%.%2%' ESCAPE '\\'"); subNames += QLatin1String(" OR %1 LIKE '%::%2%' ESCAPE '\\'"); subNames += QLatin1String(" OR %1 LIKE '%/%2%' ESCAPE '\\'"); - while (results.size() < 100) { + while (!token.isCanceled() && results.size() < 100) { QString curQuery = sanitizedQuery; QString notQuery; // don't return the same result twice if (withSubStrings) { diff --git a/src/registry/docset.h b/src/registry/docset.h index a3b4d8f95..f67941fd6 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -31,6 +31,7 @@ namespace Zeal { +struct CancellationToken; struct SearchResult; class Docset @@ -59,7 +60,7 @@ class Docset const QMap &symbols(const QString &symbolType) const; - QList search(const QString &query) const; + QList search(const QString &query, const CancellationToken &token) const; QList relatedLinks(const QUrl &url) const; // FIXME: This is an ugly workaround before we have a proper docset sources implementation diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index 81ccb6c08..4aad30b2b 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -137,7 +137,7 @@ void DocsetRegistry::_runQuery(const QString &query, const CancellationToken &to for (Docset *docset : docsets()) { if (token.isCanceled()) return; - results << docset->search(query); + results << docset->search(query, token); } std::sort(results.begin(), results.end()); From 40b8d4ac0a1377100fabde89e72e60d183df4882 Mon Sep 17 00:00:00 2001 From: Artur Spychaj Date: Wed, 9 Dec 2015 23:59:08 -0800 Subject: [PATCH 193/273] registry: Search docsets in parallel Related to #264, #523. --- src/registry/docsetregistry.cpp | 28 +++++++++++++++++++--------- src/src.pro | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index 4aad30b2b..3fc784816 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -26,11 +26,21 @@ #include "cancellationtoken.h" #include "searchresult.h" +#include #include #include +#include + +#include + using namespace Zeal; +void MergeQueryResults(QList &finalResult, const QList &partial) +{ + finalResult << partial; +} + DocsetRegistry::DocsetRegistry(QObject *parent) : QObject(parent), m_thread(new QThread(this)) @@ -132,17 +142,17 @@ void DocsetRegistry::search(const QString &query, const CancellationToken &token void DocsetRegistry::_runQuery(const QString &query, const CancellationToken &token) { - QList results; - - for (Docset *docset : docsets()) { - if (token.isCanceled()) - return; - results << docset->search(query, token); - } - + QFuture> queryResultsFuture + = QtConcurrent::mappedReduced(docsets(), + std::bind(&Docset::search, + std::placeholders::_1, + query, token), + &MergeQueryResults); + QList results = queryResultsFuture.result(); std::sort(results.begin(), results.end()); - emit queryCompleted(results); + if (!token.isCanceled()) + emit queryCompleted(results); } // Recursively finds and adds all docsets in a given directory. diff --git a/src/src.pro b/src/src.pro index 767f6c162..3c6484c92 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,6 +1,6 @@ TEMPLATE = app -QT += gui widgets sql +QT += gui widgets sql concurrent CONFIG += c++11 silent ## Build options From 4b3e1df51de2ff1b3e57dd4093f1b610afd60612 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 20 Jul 2016 02:10:27 -0400 Subject: [PATCH 194/273] registry: Check for canceled search prior to sorting results This gives a slightly noticeable performance improvement. --- src/registry/docsetregistry.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index 3fc784816..33de7eaad 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -149,10 +149,16 @@ void DocsetRegistry::_runQuery(const QString &query, const CancellationToken &to query, token), &MergeQueryResults); QList results = queryResultsFuture.result(); + + if (token.isCanceled()) + return; + std::sort(results.begin(), results.end()); - if (!token.isCanceled()) - emit queryCompleted(results); + if (token.isCanceled()) + return; + + emit queryCompleted(results); } // Recursively finds and adds all docsets in a given directory. From cb28be436c9fb699ed3c855b916eca9bf1694066 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 23 Jul 2016 11:49:42 -0400 Subject: [PATCH 195/273] registry: Fix contact link in CancellationToken headers --- src/registry/cancellationtoken.cpp | 2 +- src/registry/cancellationtoken.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registry/cancellationtoken.cpp b/src/registry/cancellationtoken.cpp index e8e2b8785..64fa457e5 100644 --- a/src/registry/cancellationtoken.cpp +++ b/src/registry/cancellationtoken.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 Artur Spychaj -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** diff --git a/src/registry/cancellationtoken.h b/src/registry/cancellationtoken.h index 75222d554..ff00b1b7b 100644 --- a/src/registry/cancellationtoken.h +++ b/src/registry/cancellationtoken.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 Artur Spychaj -** Contact: http://zealdocs.org/contact.html +** Contact: https://go.zealdocs.org/l/contact ** ** This file is part of Zeal. ** From 1a06b22f0411124fbe21cbe52b1339dfd3cf81d5 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 2 Aug 2016 23:24:26 -0400 Subject: [PATCH 196/273] ui: Set QStyleOptionViewItem::HasDisplay in SearchItemDelegate This fixes the bug with item's text not rendered, when certain styles were in use, e.g. KDE's Breeze. Fixes #540. --- src/ui/searchitemdelegate.cpp | 12 ++++++++---- src/ui/searchitemdelegate.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index fa33974f1..b73a78ed1 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -108,13 +108,17 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op } } + // This should not happen unless a docset is corrupted. + if (index.data().isNull()) + return; + // Match QCommonStyle behaviour. - const QString text = index.data().toString(); + opt.features |= QStyleOptionViewItem::HasDisplay; + opt.text = index.data().toString(); const QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, opt.widget) .adjusted(margin, 0, -margin, 0); - const QFontMetrics &fm = opt.fontMetrics; - const QString elidedText = fm.elidedText(text, opt.textElideMode, textRect.width()); + const QString elidedText = fm.elidedText(opt.text, opt.textElideMode, textRect.width()); if (!m_highlight.isEmpty()) { painter->save(); @@ -125,7 +129,7 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op ? QColor::fromRgb(255, 255, 100, 20) : QColor::fromRgb(255, 255, 100, 120); for (int i = 0;;) { - const int matchIndex = text.indexOf(m_highlight, i, Qt::CaseInsensitive); + const int matchIndex = opt.text.indexOf(m_highlight, i, Qt::CaseInsensitive); if (matchIndex == -1 || matchIndex >= elidedText.length() - 1) break; diff --git a/src/ui/searchitemdelegate.h b/src/ui/searchitemdelegate.h index bc6505717..cf454b4a2 100644 --- a/src/ui/searchitemdelegate.h +++ b/src/ui/searchitemdelegate.h @@ -39,7 +39,7 @@ class SearchItemDelegate : public QStyledItemDelegate const QModelIndex &index) override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; public slots: void setHighlight(const QString &text); From ef83da0c6122c74484ac1907e0823d7d78dcd4e3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 2 Aug 2016 23:55:51 -0400 Subject: [PATCH 197/273] registry, ui: Use QLatin1String in conditions --- src/registry/docset.cpp | 2 +- src/registry/docsetregistry.cpp | 2 +- src/ui/searchitemdelegate.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 66149ffd5..16ad5c2b0 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -142,7 +142,7 @@ Docset::Docset(const QString &path) : if (plist.contains(InfoPlist::DashDocSetFamily)) { const QString kw = plist[InfoPlist::DashDocSetFamily].toString(); - if (kw != QStringLiteral("dashtoc")) + if (kw != QLatin1String("dashtoc")) m_keywords << kw; } diff --git a/src/registry/docsetregistry.cpp b/src/registry/docsetregistry.cpp index 33de7eaad..6d316d265 100644 --- a/src/registry/docsetregistry.cpp +++ b/src/registry/docsetregistry.cpp @@ -166,7 +166,7 @@ void DocsetRegistry::addDocsetsFromFolder(const QString &path) { const QDir dir(path); for (const QFileInfo &subdir : dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllDirs)) { - if (subdir.suffix() == QStringLiteral("docset")) + if (subdir.suffix() == QLatin1String("docset")) addDocset(subdir.absoluteFilePath()); else addDocsetsFromFolder(subdir.absoluteFilePath()); diff --git a/src/ui/searchitemdelegate.cpp b/src/ui/searchitemdelegate.cpp index b73a78ed1..10752e066 100644 --- a/src/ui/searchitemdelegate.cpp +++ b/src/ui/searchitemdelegate.cpp @@ -153,7 +153,7 @@ void SearchItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op #ifdef Q_OS_WIN32 // QWindowsVistaStyle overrides highlight colour. - if (style->objectName() == QStringLiteral("windowsvista")) { + if (style->objectName() == QLatin1String("windowsvista")) { opt.palette.setColor(QPalette::All, QPalette::HighlightedText, opt.palette.color(QPalette::Active, QPalette::Text)); } From 4c7b3621c850415bfc958a0a7a70dec0f58c5d3b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 3 Aug 2016 00:16:39 -0400 Subject: [PATCH 198/273] registry: Mark docset as invalid when Documents directory is missing Fixes #573. --- src/registry/docset.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index 16ad5c2b0..c7f6b5ec8 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -127,8 +127,10 @@ Docset::Docset(const QString &path) : createIndex(); - if (!dir.cd(QStringLiteral("Documents"))) + if (!dir.cd(QStringLiteral("Documents"))) { + m_type = Type::Invalid; return; + } // Setup keywords if (plist.contains(InfoPlist::DocSetPlatformFamily)) From 26cdb7b39943955dea4905d3b4d585d88b6cd477 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 7 Aug 2016 17:34:17 -0400 Subject: [PATCH 199/273] qmake: Add period after AppIndicator detection message --- src/ui/ui.pri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/ui.pri b/src/ui/ui.pri index d6f23ac33..1a2a104a5 100644 --- a/src/ui/ui.pri +++ b/src/ui/ui.pri @@ -14,8 +14,8 @@ unix:!macx { CONFIG += link_pkgconfig PKGCONFIG += appindicator-0.1 gtk+-2.0 DEFINES += USE_APPINDICATOR - message("AppIndicator support: Yes") + message("AppIndicator support: Yes.") } else { - message("AppIndicator support: No") + message("AppIndicator support: No.") } } From bfdeae77331c1cc8d576afd70ca8c146951893b7 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 7 Aug 2016 21:26:47 -0400 Subject: [PATCH 200/273] core: Do not keep QSettings object between loading/saving settings This allows to keep the settings clean, without any complex checking if options are valid and supported. --- src/core/settings.cpp | 183 +++++++++++++++++++++++------------------- src/core/settings.h | 2 +- 2 files changed, 101 insertions(+), 84 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3164be27e..5d9c7d7a9 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -50,13 +50,7 @@ const char GroupProxy[] = "proxy"; using namespace Zeal::Core; Settings::Settings(QObject *parent) : - QObject(parent), - #ifndef PORTABLE_BUILD - m_settings(new QSettings(this)) - #else - m_settings(new QSettings(QCoreApplication::applicationDirPath() + QLatin1String("/zeal.ini"), - QSettings::IniFormat, this)) - #endif + QObject(parent) { // TODO: Move to user style sheet (related to #268) #ifndef USE_WEBENGINE @@ -74,41 +68,43 @@ Settings::~Settings() void Settings::load() { + QScopedPointer settings(qsettings()); + // TODO: Put everything in groups - startMinimized = m_settings->value(QStringLiteral("start_minimized"), false).toBool(); - checkForUpdate = m_settings->value(QStringLiteral("check_for_update"), true).toBool(); + startMinimized = settings->value(QStringLiteral("start_minimized"), false).toBool(); + checkForUpdate = settings->value(QStringLiteral("check_for_update"), true).toBool(); - showSystrayIcon = m_settings->value(QStringLiteral("show_systray_icon"), true).toBool(); - minimizeToSystray = m_settings->value(QStringLiteral("minimize_to_systray"), false).toBool(); - hideOnClose = m_settings->value(QStringLiteral("hide_on_close"), false).toBool(); + showSystrayIcon = settings->value(QStringLiteral("show_systray_icon"), true).toBool(); + minimizeToSystray = settings->value(QStringLiteral("minimize_to_systray"), false).toBool(); + hideOnClose = settings->value(QStringLiteral("hide_on_close"), false).toBool(); - m_settings->beginGroup(GroupGlobalShortcuts); - showShortcut = m_settings->value(QStringLiteral("show")).value(); - m_settings->endGroup(); + settings->beginGroup(GroupGlobalShortcuts); + showShortcut = settings->value(QStringLiteral("show")).value(); + settings->endGroup(); - m_settings->beginGroup(GroupTabs); - openNewTabAfterActive = m_settings->value(QStringLiteral("open_new_tab_after_active"), false).toBool(); - m_settings->endGroup(); + settings->beginGroup(GroupTabs); + openNewTabAfterActive = settings->value(QStringLiteral("open_new_tab_after_active"), false).toBool(); + settings->endGroup(); - m_settings->beginGroup(GroupBrowser); - minimumFontSize = m_settings->value(QStringLiteral("minimum_font_size"), + settings->beginGroup(GroupBrowser); + minimumFontSize = settings->value(QStringLiteral("minimum_font_size"), QWebSettings::globalSettings()->fontSize(QWebSettings::MinimumFontSize)).toInt(); QWebSettings::globalSettings()->setFontSize(QWebSettings::MinimumFontSize, minimumFontSize); - m_settings->endGroup(); + settings->endGroup(); - m_settings->beginGroup(GroupProxy); - proxyType = static_cast(m_settings->value(QStringLiteral("type"), + settings->beginGroup(GroupProxy); + proxyType = static_cast(settings->value(QStringLiteral("type"), ProxyType::System).toUInt()); - proxyHost = m_settings->value(QStringLiteral("host")).toString(); - proxyPort = m_settings->value(QStringLiteral("port"), 0).toInt(); - proxyAuthenticate = m_settings->value(QStringLiteral("authenticate"), false).toBool(); - proxyUserName = m_settings->value(QStringLiteral("username")).toString(); - proxyPassword = m_settings->value(QStringLiteral("password")).toString(); - m_settings->endGroup(); - - m_settings->beginGroup(GroupDocsets); - if (m_settings->contains(QStringLiteral("path"))) { - docsetPath = m_settings->value(QStringLiteral("path")).toString(); + proxyHost = settings->value(QStringLiteral("host")).toString(); + proxyPort = settings->value(QStringLiteral("port"), 0).toInt(); + proxyAuthenticate = settings->value(QStringLiteral("authenticate"), false).toBool(); + proxyUserName = settings->value(QStringLiteral("username")).toString(); + proxyPassword = settings->value(QStringLiteral("password")).toString(); + settings->endGroup(); + + settings->beginGroup(GroupDocsets); + if (settings->contains(QStringLiteral("path"))) { + docsetPath = settings->value(QStringLiteral("path")).toString(); } else { #ifndef PORTABLE_BUILD docsetPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) @@ -118,72 +114,93 @@ void Settings::load() #endif QDir().mkpath(docsetPath); } - m_settings->endGroup(); + settings->endGroup(); - m_settings->beginGroup(GroupState); - windowGeometry = m_settings->value(QStringLiteral("window_geometry")).toByteArray(); - verticalSplitterGeometry = m_settings->value(QStringLiteral("splitter_geometry")).toByteArray(); - tocSplitterState = m_settings->value(QStringLiteral("toc_splitter_state")).toByteArray(); - m_settings->endGroup(); + settings->beginGroup(GroupState); + windowGeometry = settings->value(QStringLiteral("window_geometry")).toByteArray(); + verticalSplitterGeometry = settings->value(QStringLiteral("splitter_geometry")).toByteArray(); + tocSplitterState = settings->value(QStringLiteral("toc_splitter_state")).toByteArray(); + settings->endGroup(); - m_settings->beginGroup(GroupInternal); - installId = m_settings->value(QStringLiteral("install_id"), + settings->beginGroup(GroupInternal); + installId = settings->value(QStringLiteral("install_id"), // Avoid curly braces (QTBUG-885) QUuid::createUuid().toString().mid(1, 36)).toString(); - version = m_settings->value(QStringLiteral("version"), + version = settings->value(QStringLiteral("version"), QCoreApplication::applicationVersion()).toString(); - m_settings->endGroup(); + settings->endGroup(); } void Settings::save() { + QScopedPointer settings(qsettings()); + // TODO: Put everything in groups - m_settings->setValue(QStringLiteral("start_minimized"), startMinimized); - m_settings->setValue(QStringLiteral("check_for_update"), checkForUpdate); - - m_settings->setValue(QStringLiteral("show_systray_icon"), showSystrayIcon); - m_settings->setValue(QStringLiteral("minimize_to_systray"), minimizeToSystray); - m_settings->setValue(QStringLiteral("hide_on_close"), hideOnClose); - - m_settings->beginGroup(GroupGlobalShortcuts); - m_settings->setValue(QStringLiteral("show"), showShortcut); - m_settings->endGroup(); - - m_settings->beginGroup(GroupTabs); - m_settings->setValue(QStringLiteral("open_new_tab_after_active"), openNewTabAfterActive); - m_settings->endGroup(); - - m_settings->beginGroup(GroupBrowser); - m_settings->setValue(QStringLiteral("minimum_font_size"), minimumFontSize); - m_settings->endGroup(); - - m_settings->beginGroup(GroupProxy); - m_settings->setValue(QStringLiteral("type"), proxyType); - m_settings->setValue(QStringLiteral("host"), proxyHost); - m_settings->setValue(QStringLiteral("port"), proxyPort); - m_settings->setValue(QStringLiteral("authenticate"), proxyAuthenticate); - m_settings->setValue(QStringLiteral("username"), proxyUserName); - m_settings->setValue(QStringLiteral("password"), proxyPassword); - m_settings->endGroup(); + settings->setValue(QStringLiteral("start_minimized"), startMinimized); + settings->setValue(QStringLiteral("check_for_update"), checkForUpdate); + + settings->setValue(QStringLiteral("show_systray_icon"), showSystrayIcon); + settings->setValue(QStringLiteral("minimize_to_systray"), minimizeToSystray); + settings->setValue(QStringLiteral("hide_on_close"), hideOnClose); + + settings->beginGroup(GroupGlobalShortcuts); + settings->setValue(QStringLiteral("show"), showShortcut); + settings->endGroup(); + + settings->beginGroup(GroupTabs); + settings->setValue(QStringLiteral("open_new_tab_after_active"), openNewTabAfterActive); + settings->endGroup(); + + settings->beginGroup(GroupBrowser); + settings->setValue(QStringLiteral("minimum_font_size"), minimumFontSize); + settings->endGroup(); + + settings->beginGroup(GroupProxy); + settings->setValue(QStringLiteral("type"), proxyType); + settings->setValue(QStringLiteral("host"), proxyHost); + settings->setValue(QStringLiteral("port"), proxyPort); + settings->setValue(QStringLiteral("authenticate"), proxyAuthenticate); + settings->setValue(QStringLiteral("username"), proxyUserName); + settings->setValue(QStringLiteral("password"), proxyPassword); + settings->endGroup(); #ifndef PORTABLE_BUILD - m_settings->beginGroup(GroupDocsets); - m_settings->setValue(QStringLiteral("path"), docsetPath); - m_settings->endGroup(); + settings->beginGroup(GroupDocsets); + settings->setValue(QStringLiteral("path"), docsetPath); + settings->endGroup(); #endif - m_settings->beginGroup(GroupState); - m_settings->setValue(QStringLiteral("window_geometry"), windowGeometry); - m_settings->setValue(QStringLiteral("splitter_geometry"), verticalSplitterGeometry); - m_settings->setValue(QStringLiteral("toc_splitter_state"), tocSplitterState); - m_settings->endGroup(); + settings->beginGroup(GroupState); + settings->setValue(QStringLiteral("window_geometry"), windowGeometry); + settings->setValue(QStringLiteral("splitter_geometry"), verticalSplitterGeometry); + settings->setValue(QStringLiteral("toc_splitter_state"), tocSplitterState); + settings->endGroup(); - m_settings->beginGroup(GroupInternal); - m_settings->setValue(QStringLiteral("install_id"), installId); - m_settings->setValue(QStringLiteral("version"), QCoreApplication::applicationVersion()); - m_settings->endGroup(); + settings->beginGroup(GroupInternal); + settings->setValue(QStringLiteral("install_id"), installId); + settings->setValue(QStringLiteral("version"), QCoreApplication::applicationVersion()); + settings->endGroup(); - m_settings->sync(); + settings->sync(); emit updated(); } + +/*! + * \internal + * \brief Returns an initialized QSettings object. + * \param parent Optional parent object. + * \return QSettings object. + * + * QSettings is initialized according to build options, e.g. standard vs portable. + * Caller is responsible for deleting the returned object. + */ +QSettings *Settings::qsettings(QObject *parent) +{ +#ifndef PORTABLE_BUILD + return new QSettings(parent); +#else + return new QSettings(QCoreApplication::applicationDirPath() + QLatin1String("/zeal.ini"), + QSettings::IniFormat, parent); +#endif +} diff --git a/src/core/settings.h b/src/core/settings.h index eee115960..135a1048b 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -106,7 +106,7 @@ public slots: void updated(); private: - QSettings *m_settings = nullptr; + static QSettings *qsettings(QObject *parent = nullptr); }; } // namespace Core From 76e0cd48d4aa9fc6a5d8cf3a2964adfb41503038 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 7 Aug 2016 21:29:17 -0400 Subject: [PATCH 201/273] core: Do not load settings version It should be used only for migration. --- src/core/settings.cpp | 3 +-- src/core/settings.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 5d9c7d7a9..b8f1c95e7 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -126,8 +126,6 @@ void Settings::load() installId = settings->value(QStringLiteral("install_id"), // Avoid curly braces (QTBUG-885) QUuid::createUuid().toString().mid(1, 36)).toString(); - version = settings->value(QStringLiteral("version"), - QCoreApplication::applicationVersion()).toString(); settings->endGroup(); } @@ -178,6 +176,7 @@ void Settings::save() settings->beginGroup(GroupInternal); settings->setValue(QStringLiteral("install_id"), installId); + // Version of configuration file format, should match Zeal version. Used for migration rules. settings->setValue(QStringLiteral("version"), QCoreApplication::applicationVersion()); settings->endGroup(); diff --git a/src/core/settings.h b/src/core/settings.h index 135a1048b..7d4a84e6f 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -77,8 +77,6 @@ class Settings : public QObject // a settings wipe. It is not attached to user hardware or software, and is sent exclusevely // to *.zealdocs.org hosts. QString installId; - // Version of configuration file format, should match Zeal version. Useful for migration rules. - QString version; ProxyType proxyType = ProxyType::System; QString proxyHost; From ebd3ab8b5727febd61a15d7fa6a469405debd2a7 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 7 Aug 2016 21:34:29 -0400 Subject: [PATCH 202/273] core: Reset 'state/splitter_geometry' option for <0.3 versions This settings options has to be reset due to removal of custom styles for the main splitter. --- src/core/settings.cpp | 27 +++++++++++++++++++++++++++ src/core/settings.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index b8f1c95e7..2c5bd5947 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -69,6 +69,7 @@ Settings::~Settings() void Settings::load() { QScopedPointer settings(qsettings()); + migrate(settings.data()); // TODO: Put everything in groups startMinimized = settings->value(QStringLiteral("start_minimized"), false).toBool(); @@ -185,6 +186,32 @@ void Settings::save() emit updated(); } +/*! + * \internal + * \brief Migrates settings from older application versions. + * \param settings QSettings object to update. + * + * The settings migration process relies on 'internal/version' option, that was introduced in the + * release 0.2.0, so a missing option indicates pre-0.2 release. + */ +void Settings::migrate(QSettings *settings) const +{ + settings->beginGroup(GroupInternal); + const QString version = settings->value(QStringLiteral("version")).toString(); + settings->endGroup(); + + // + // Pre 0.3 + // + + // Unset 'state/splitter_geometry', because custom styles were removed. + if (version.isEmpty() || version.startsWith(QLatin1String("0.2"))) { + settings->beginGroup(GroupState); + settings->remove(QStringLiteral("splitter_geometry")); + settings->endGroup(); + } +} + /*! * \internal * \brief Returns an initialized QSettings object. diff --git a/src/core/settings.h b/src/core/settings.h index 7d4a84e6f..50fc37ae5 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -104,6 +104,8 @@ public slots: void updated(); private: + void migrate(QSettings *settings) const; + static QSettings *qsettings(QObject *parent = nullptr); }; From 5c3b84725bc3d502993584e92a6b75a050ea2fad Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 9 Aug 2016 23:35:17 -0400 Subject: [PATCH 203/273] ui: Fix crash on application quit (WebEngine only) (fixes #577) --- src/ui/mainwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fe92ad5ec..e41b4a8bc 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -124,7 +124,8 @@ struct TabState { delete searchModel; delete tocModel; - delete webPage; + // deleteLater() prevents crashing on quit (#577) + webPage->deleteLater(); } QUrl url() const { @@ -470,6 +471,7 @@ MainWindow::~MainWindow() m_settings->verticalSplitterGeometry = ui->splitter->saveState(); m_settings->windowGeometry = saveGeometry(); + // Delete the UI first, because it depends on tab states. delete ui; qDeleteAll(m_tabStates); } From 6ff29e3da3b1c0803445655d1532479c371f8bad Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 9 Aug 2016 23:37:28 -0400 Subject: [PATCH 204/273] ui: Improve coding style a bit --- src/ui/mainwindow.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index e41b4a8bc..dd730f69a 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -106,6 +106,14 @@ struct TabState restoreHistory(other.saveHistory()); } + ~TabState() + { + delete searchModel; + delete tocModel; + // deleteLater() prevents crashing on quit (#577) + webPage->deleteLater(); + } + void restoreHistory(const QByteArray &array) const { QDataStream stream(array); @@ -120,14 +128,6 @@ struct TabState return array; } - ~TabState() - { - delete searchModel; - delete tocModel; - // deleteLater() prevents crashing on quit (#577) - webPage->deleteLater(); - } - QUrl url() const { #ifdef USE_WEBENGINE return webPage->url(); @@ -542,7 +542,7 @@ void MainWindow::closeTab(int index) m_tabBar->removeTab(index); - if (m_tabStates.count() == 0) + if (m_tabStates.isEmpty()) createTab(); } From a18790ffd4489783b73cb2a1eb50144e7ebe5fc9 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Aug 2016 22:22:24 -0400 Subject: [PATCH 205/273] ui: Move tabs settings into a separate tab --- src/ui/forms/settingsdialog.ui | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/ui/forms/settingsdialog.ui b/src/ui/forms/settingsdialog.ui index e1a8c11d2..d01631368 100644 --- a/src/ui/forms/settingsdialog.ui +++ b/src/ui/forms/settingsdialog.ui @@ -141,10 +141,30 @@
+ + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Tabs + + - Tabs behavior + Behavior @@ -157,19 +177,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - From a657d0e70af14e6039ff5533850dc9bce99da4b1 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Aug 2016 22:30:36 -0400 Subject: [PATCH 206/273] core: Fix precision warning --- src/core/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2c5bd5947..cffdc9549 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -97,7 +97,7 @@ void Settings::load() proxyType = static_cast(settings->value(QStringLiteral("type"), ProxyType::System).toUInt()); proxyHost = settings->value(QStringLiteral("host")).toString(); - proxyPort = settings->value(QStringLiteral("port"), 0).toInt(); + proxyPort = static_cast(settings->value(QStringLiteral("port"), 0).toUInt()); proxyAuthenticate = settings->value(QStringLiteral("authenticate"), false).toBool(); proxyUserName = settings->value(QStringLiteral("username")).toString(); proxyPassword = settings->value(QStringLiteral("password")).toString(); From d244ca33da3bf614f092e991e179243f0c43a1b0 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Aug 2016 22:34:02 -0400 Subject: [PATCH 207/273] ui: Store manual proxy settings even when disabled --- src/ui/settingsdialog.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index b6ab534b9..260fde7f7 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -794,13 +794,14 @@ void SettingsDialog::loadSettings() break; case Core::Settings::ProxyType::UserDefined: ui->manualProxySettings->setChecked(true); - ui->httpProxy->setText(settings->proxyHost); - ui->httpProxyPort->setValue(settings->proxyPort); - ui->httpProxyNeedsAuth->setChecked(settings->proxyAuthenticate); - ui->httpProxyUser->setText(settings->proxyUserName); - ui->httpProxyPass->setText(settings->proxyPassword); break; } + + ui->httpProxy->setText(settings->proxyHost); + ui->httpProxyPort->setValue(settings->proxyPort); + ui->httpProxyNeedsAuth->setChecked(settings->proxyAuthenticate); + ui->httpProxyUser->setText(settings->proxyUserName); + ui->httpProxyPass->setText(settings->proxyPassword); } void SettingsDialog::saveSettings() From e31fa22449a264d9ee131c4203a6960fb1d1712d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 14 Aug 2016 23:14:18 -0400 Subject: [PATCH 208/273] ui: Cleanup web view includes in MainWindow --- src/ui/mainwindow.cpp | 4 +++- src/ui/mainwindow.h | 13 ------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index dd730f69a..9674929c3 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -46,10 +46,12 @@ #ifdef USE_WEBENGINE #include +#include #include -#include typedef QWebEngineHistory QWebHistory; +typedef QWebEngineHistoryItem QWebHistoryItem; +typedef QWebEnginePage QWebPage; #else #include #include diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 1ded8e4ce..5ade8c5c3 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -29,19 +29,6 @@ #include -#ifdef USE_WEBENGINE -class QWebEngineHistory; -class QWebEngineHistoryItem; -class QWebEnginePage; -typedef QWebEngineHistory QWebHistory; -typedef QWebEngineHistoryItem QWebHistoryItem; -typedef QWebEnginePage QWebPage; -#else -class QWebHistory; -class QWebHistoryItem; -class QWebPage; -#endif - #ifdef USE_APPINDICATOR struct _AppIndicator; struct _GtkWidget; From feee0ec6edb43be392fe0bb560ba5af20e50b71a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 16 Aug 2016 20:17:03 -0400 Subject: [PATCH 209/273] qmake: Move shared options to common.pri --- common.pri | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/src.pro | 54 ++------------------------------------------ 2 files changed, 67 insertions(+), 52 deletions(-) create mode 100644 common.pri diff --git a/common.pri b/common.pri new file mode 100644 index 000000000..87e3486ad --- /dev/null +++ b/common.pri @@ -0,0 +1,65 @@ +# Shared build options +# +# This file must be included at the top of every non-subdirs .pro file. +# Use: +# include($$SRC_ROOT/common.pri) + +# Compilation settings +CONFIG += c++11 silent + +# QString options +DEFINES *= QT_USE_QSTRINGBUILDER +DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII +DEFINES *= QT_NO_CAST_TO_ASCII +DEFINES *= QT_NO_URL_CAST_FROM_STRING + +# Keep build directory clean +MOC_DIR = $$BUILD_ROOT/.moc +OBJECTS_DIR = $$BUILD_ROOT/.obj +RCC_DIR = $$BUILD_ROOT/.rcc +UI_DIR = $$BUILD_ROOT/.ui + +# Application version +VERSION = 0.2.1 +DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" + +# Browser engine +CONFIG(zeal_qtwebkit) { + qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit + else: error("Qt WebKit is not available.") +} else:CONFIG(zeal_qtwebengine) { + qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine + else: error("Qt WebEngine is not available.") +} else { + qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine + else: qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit + else: error("Zeal requires Qt WebEngine or Qt WebKit.") +} + +equals(BROWSER_ENGINE, qtwebengine) { + message("Browser engine: Qt WebEngine.") + QT += webenginewidgets + DEFINES += USE_WEBENGINE +} else { + message("Browser engine: Qt WebKit.") + QT += webkitwidgets + DEFINES += USE_WEBKIT +} + +# Portable build +CONFIG(zeal_portable) { + message("Portable build: Yes.") + DEFINES += PORTABLE_BUILD +} else { + message("Portable build: No.") +} + +# Unix installation prefix +unix:!macx { + isEmpty(PREFIX): PREFIX = /usr + message("Install prefix: $$PREFIX") + target.path = $$PREFIX/bin + + # Always install target + INSTALLS += target +} diff --git a/src/src.pro b/src/src.pro index 3c6484c92..556c56d13 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,48 +1,8 @@ +include($$SRC_ROOT/common.pri) + TEMPLATE = app QT += gui widgets sql concurrent -CONFIG += c++11 silent - -## Build options -# Browser engine -CONFIG(zeal_qtwebkit) { - qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit - else: error("Qt WebKit is not available.") -} else:CONFIG(zeal_qtwebengine) { - qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine - else: error("Qt WebEngine is not available.") -} else { - qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine - else: qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit - else: error("Zeal requires Qt WebEngine or Qt WebKit.") -} - -equals(BROWSER_ENGINE, qtwebengine) { - message("Browser engine: Qt WebEngine.") - QT += webenginewidgets - DEFINES += USE_WEBENGINE -} else { - message("Browser engine: Qt WebKit.") - QT += webkitwidgets - DEFINES += USE_WEBKIT -} - -# Portable build -CONFIG(zeal_portable) { - message("Portable build: Yes.") - DEFINES += PORTABLE_BUILD -} else { - message("Portable build: No.") -} - -VERSION = 0.2.1 -DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" - -# QString options -DEFINES *= QT_USE_QSTRINGBUILDER -DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII -DEFINES *= QT_NO_CAST_TO_ASCII -DEFINES *= QT_NO_URL_CAST_FROM_STRING HEADERS += \ util/version.h \ @@ -65,10 +25,6 @@ DESTDIR = $$BUILD_ROOT/bin unix:!macx { TARGET = zeal - isEmpty(PREFIX): PREFIX = /usr - target.path = $$PREFIX/bin - INSTALLS = target - appicons16.files=appicons/16/* appicons24.files=appicons/24/* appicons32.files=appicons/32/* @@ -96,9 +52,3 @@ macx { TARGET = Zeal ICON = resources/zeal.icns } - -# Keep build directory organised -MOC_DIR = $$BUILD_ROOT/.moc -OBJECTS_DIR = $$BUILD_ROOT/.obj -RCC_DIR = $$BUILD_ROOT/.rcc -UI_DIR = $$BUILD_ROOT/.ui From e8a3bf912032e6252b30643bc5b015cd22d6ab10 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 16 Aug 2016 20:52:33 -0400 Subject: [PATCH 210/273] app, ui: Set application-wide window icon --- src/main.cpp | 5 +++++ src/ui/mainwindow.cpp | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f2dea64c8..feaca9465 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -202,6 +203,10 @@ int main(int argc, char *argv[]) if (!clParams.force && Core::LocalServer::sendQuery(clParams.query, clParams.preventActivation)) return 0; + // Set application-wide window icon. All message boxes and other windows will use it by default. + qapp->setWindowIcon(QIcon::fromTheme(QStringLiteral("zeal"), + QIcon(QStringLiteral(":/zeal.ico")))); + QScopedPointer localServer(new Core::LocalServer()); if (!localServer->start()) { QScopedPointer msgBox(new QMessageBox()); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 9674929c3..466e8f45e 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -185,8 +185,6 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(m_settings, &Core::Settings::updated, this, &MainWindow::applySettings); - setWindowIcon(QIcon::fromTheme(QStringLiteral("zeal"), QIcon(QStringLiteral(":/zeal.ico")))); - #ifdef USE_APPINDICATOR detectAppIndicatorSupport(); #endif From 49ef260805aa59fc4d32bba097a3cb6f52e5356f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 16 Aug 2016 21:00:13 -0400 Subject: [PATCH 211/273] resources: Optimize logo icons --- src/resources/icons/logo/128x128.png | Bin 23373 -> 23241 bytes src/resources/icons/logo/64x64.png | Bin 6051 -> 6006 bytes src/resources/icons/logo/icon.png | Bin 1164 -> 923 bytes src/resources/icons/logo/icon@2x.png | Bin 1878 -> 1817 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/resources/icons/logo/128x128.png b/src/resources/icons/logo/128x128.png index 0d391992eb2f9336a16860a4a53dcf581f50d5b2..a7d7dd556a4977c067a6031333bc64b3d2d67b69 100644 GIT binary patch literal 23241 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 M07*qoM6N<$f=U(;KL7v# literal 23373 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 o5qwe>`=#ThPbXFRCwC$n|qLDS9RWh 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 E0FiE9SpWb4 delta 520 zcmbQu-oqKu8Q|y6%O%Cdz`(%k>ERLtqy<5kgBeKjY~FqXNGT+H1o<*BRH-pAG_)`< z`~nI!ykKA`HDF+PmB7GYHG_dcykO3*KpO@Irs)AbA+A6L8#N~~)&KwhpGWGI2#~8% z666=mAkugF90+XU(7$)Tto|P(BMX<9H1m&#+B?2Kdie0cF(IxWGo4og)iWk}ySs2@ zT=)_OvL>4nJa0`PlBg3pY5k@V5>u1eox=FU{Pft^^5jHA zO-p%wb#?1`b4_JqH$2On!Yu?Pcv*%CKp+%1- zUD{Nn*w(e;)T&prZteQjc5Ky?y^Uh3nOQ=NXmG;y7GlJ5|y+ z{p>vB@_T}+(L$;b-~ww|J}cgNmdK II;Vst02Hv%ZU6uP diff --git a/src/resources/icons/logo/icon@2x.png b/src/resources/icons/logo/icon@2x.png index 078173c1d5dd3b9b6717dc8b29b3fd37ce73cb3b..28b878550946cd8d99d61d4750ca69711cc31c11 100644 GIT binary patch delta 1795 zcmV+e2mJWf4w(*+7YZN<1^@s6b9#F8kzW^o00(qQO+^Rb2OR?nCy{D4^00yQ>L_t(o!=0B+j9f<%$A8t`Z)SF9cXsivZI+b{vK7a{mQ2vv z;=lm~I3R}$C_Vs=6c8jtNS4TvQve~s0gyO=09gnLMMA&@E|3Tbj1VE1KpYW5;xBA} z@5Jl1z22RfotZb?#o_h)7_V(PJgN2i^{ZD^{jaKj^%KAX!q!XfGUqPx)l2X3thXz2 z_b~o;4d1UL#rhWGCr|!(*jZnb`73X*^xl0S(WWXQ1|)hRcko3u`l!XD#<_?vx%5bH z@xYuZZSZ8>bjCgok9aTkrRICap8tE0@mrwr<>oSN{qpsG$OXJ&0zz z*O1+Vf-zt({`(U-P7Yx2-o5YEVK399ngvKhwmTG22xdH$0$Mb@l+hAI zcm0YPOTx2f&;EDMt_6%3re@~p+`7qzRR})&PynARRpyVK$dqk%@VyRpVhRMz#1u0h zK1SH=aP!wES$qEHS^O(`5r8m%?C1HXMF@f#(iE<*uCm$d(oRy;Pi7zaJZ&>gYrlPt z^m@BM0D=0heJp(GTMRC}!OF?6F}V021R?kg_9E{U)R)OzIAE;9NJ_mXOgCqFfDRf0 z8cGOrCF#m?mYgxeTOWLs?VtKG>!*Ih>T};IVv@@QEvr@(LeQ-aq-jcjqhX3nRt@MV zWbg;Jl%JxQ$!T_e<{74zKE(2OpP~2KX+))Tn1Emi0gNq6RD-9QgaTkhBiU4I-RG6J zh0Z4SFR}2{v!vISIeX$Lp}SEeq(syRpf)q6qbfg`tq53C!X_dRl;C|C=L!mQkA0E( zPd>%!FMh!4FTcN)aI05;sE}2@fna4T6-!p!Vk8PFAq`_)pz)slEIj>nYC9IW`0Qut zzWP$hh*fr$k~~|7A7TBkzb|BrjD-MK5@~iNNdp68`VOvrTKd!GXpg6I2+iTxPIx83j6L%CgKMpE`Ji#-4|;&1r121wjA&Yh3-=_bQDn zoBC+m7-Ln{I}tH|B2rfkOg8HUm4=*(s{x9vm~SBO2e)2+k@bJRSYljBT2tu{xx=nC ziHOvJz7r8EBF&&4)MQlv5G0G8&6u!g-o8X2#5HR&8S>`i%Le76Lsm*Xo3@UKG*xw& z^FYJdxTWF%63`Gb1x5Lk`C_6ICMIGb6BFFWE@|TTdEQTd%*}Ad&MT0JNWs!lXpB6t zsX_=!NHr#6WXRa}z0Vjb#CZr&F3L#Ue$eclxP;o=Ea%roqz@j_=u>c2dUGyevNcCK z3fy`}gZ1RbeINRyTF+8KEJ`M`;M?Q-BO^ds=j1G=a`z^&efGwcI?>6PUm=K zYA@DW#2Ac!7{mx766sp*cq}aYMTS`Lfzc>sxP5`n%r@7MYoyWooKPtzIW_35jzUYq8cK#vo$G`o_5NkTIzSMrq2RKV-Atqt@-Q zwssTy)+HZ8@T#gV7R<2Q?XtMI$nM>{nQhH7-D=T)Y&NMk>LkwLT!M2hA|m&6KqQO1 z_ntHzG90ATx^*-t-R=g%fBoHOXGg@TY5=<4d-grJpH^#zX0yq}M1v&Bj3zF@CAkCl zkAN{*7YaV$oW)wp#Ka_t2}QaXRShA8KEQ?Z=c(0dIOhrj5=&ExVKBy2p2vqV@%@-g z=7C`FO?e^I2%EV*K+U?^`G62>(TDPttFFjBD z+N~c|3&sKV(4qI8==V3jIoWI?2nSkq_RLIVN^)g)`y;y3KV5dT#u_0JgS+__+U;3Zd-|L6_B z{fG6zwRm7J95C@-1L{B{j(Qxmik!KNKUz5hg~)U%Fa!p1^y58W_wKeo*8Ia!9JX?x l@|EYeb0k002ovPDHLkV1nY4bg=*c delta 1856 zcmV-G2fz544%QBk7f2xp1^@s6xF)Gl0000WV@Og>004R>004l5008;`004mK004C` z008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r<0K(7k>uINkl5Px5iuYk3b{ipsv$-#erk9Z5ylrE>CPWMI$c#NGVsdz^Jky_+!OEH>a?lFmSahe zCy&gcUdw%}jQRpF!BietJ}+cz0Wnzs0OrG=)rTJYOn;J_iGm4MT35e+@#32#wHlE% zyhDaOyemOfQ5OuW0*Zzws;E=cXM&D?%adJv_n>c{larr(;?R$N^ZQ?nl;Guae<8A2 zidBQMbBIWhS%qvquYiF1@UEby%#H%0+3wY6Pp@DMM3?{hu{=)};J|?c@6$Zu;CP2W9O)&MrllZMRw|;qs_2++@)xUxZ5BNbZ$DbA@ z@M=g?xUsgzR<}bdPEj|WEpj<*GfV5gevb4;tAEG<0?EQb=DzR^`d8jy<;+*;U;Y<@ z;9ZvX0{05)N-!4zn8;!zC8-IMjcFdBje3vzGKIO3bY(dMXFz!K{g1Ny6JKQG?5|jR z?psAoaviT_*NTGox-)<@O{v#Sfn-&W4tzpd3nHq7`Wdq4FI6N?{U`P9EQVC8CQAL`4gQAiUz8E9+dz!pvizXZGVyvG%j?vG()t?j+pm@RVegZ@@>g zBY+G{f*1)(icc$E1?ulQ#N5+grM73D%YV;)n$D{)m5fM*ouwqt=CMcE`15ZI9U~(p zz*6oJfHr%+~Nu@k7t%pI%`7k1vqCeV&;Ur$(~eU%5tl{eK$9 zgn*1Ne&iU9BgeV)rN=Yk3c!pEcr7xkR$h4oC+i%p_cKL>{>oMQD_2pV zeVzj4dCDh_9H+kjA)>}4QKJb!Z|OCz|KvNBgDiV>!M8CcQdMU~#E3|u>KSh&1(o`o zimL?*te9^gKM!ud{308Ff3eJQ1%I@raz5k%+vYeTk^ns`B9VwRygE>mbpe2vtaeex zgvH_Q$_)507nw|l{P1z*0p&tKk(73}q686XsOli+fx3;tmWm6AN4?Js6zx;u#e^VC z0AisN0PeymX~Oy(_hU0toR4M|h()AeX(=oQ9@tXBd&Q?3fEXAuocqpY41eXryZ1pa z=t$VU*X*0vnA*%VOY1|@2ajrq$(KB!U~SBJbB1*2x&5{}8}Uv4+o&9LWj_l$$jN!f z)ul~dJ$RhO$)*AwRdpp3TFb=rZmzGav1iX-_FBs;699F^u({dhy^D*?&&@M6JI`l;8T{j~ zF1tG-R#iRFan5n@!9z5gQ#2Y4#>VQzapp9(F*eQvxc>|olbu4|d900yqKL7vabn{O zxENLS-uoWFrKKfmwHnsi!hwX=ltK)~n9A=_F(!N;(a8c4ftigJh7zq4ZsR7qe5fW# zomOj^Kb$>FtJNCWU4IEYcFb*;JLv#Kk)?Ti6?y4-TC2BzP;D3sL`RRl=X9^P_4V;a z13@_4OxQm)mKn*70e6Ldr5y`3RU#wAVz9T~LOX44wr*bh@}-*(14FOqnq zwThnE=A*!0c={kNI2i!_AieO+=bf!A)XKtPko>P(PMy*J5x}q_t|ChKUywUC73bBP uyx+Easg`Wi&VK+^(2o;HIR3K$0000 Date: Sat, 10 Sep 2016 23:19:09 -0400 Subject: [PATCH 212/273] registry: Small optimization in Docset --- src/registry/docset.cpp | 7 ++----- src/registry/docset.h | 3 ++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/registry/docset.cpp b/src/registry/docset.cpp index c7f6b5ec8..5b1059734 100644 --- a/src/registry/docset.cpp +++ b/src/registry/docset.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -437,10 +438,6 @@ void Docset::loadSymbols(const QString &symbolType) const void Docset::loadSymbols(const QString &symbolType, const QString &symbolString) const { - QSqlDatabase db = database(); - if (!db.isOpen()) - return; - QString queryStr; if (m_type == Docset::Type::Dash) { queryStr = QStringLiteral("SELECT name, path FROM searchIndex WHERE type='%1' ORDER BY name ASC"); @@ -496,7 +493,7 @@ void Docset::createIndex() } // Drop old indexes - for (const QString oldIndexName : oldIndexes) + for (const QString &oldIndexName : oldIndexes) query.exec(indexDropQuery.arg(oldIndexName)); query.exec(indexCreateQuery.arg(IndexNamePrefix, IndexNameVersion, tableName, columnName)); diff --git a/src/registry/docset.h b/src/registry/docset.h index f67941fd6..acd92d48c 100644 --- a/src/registry/docset.h +++ b/src/registry/docset.h @@ -27,7 +27,8 @@ #include #include #include -#include + +class QSqlDatabase; namespace Zeal { From 7ce8cd92a60a0d9593cbcff11cb9a752c395fbd1 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 10 Sep 2016 23:40:12 -0400 Subject: [PATCH 213/273] ui: Fix a few Clang warnings in SettingsDialog --- src/ui/settingsdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/settingsdialog.cpp b/src/ui/settingsdialog.cpp index 260fde7f7..ac590b6a4 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/ui/settingsdialog.cpp @@ -837,7 +837,7 @@ void SettingsDialog::saveSettings() settings->proxyType = Core::Settings::ProxyType::UserDefined; settings->proxyHost = ui->httpProxy->text(); - settings->proxyPort = ui->httpProxyPort->text().toUInt(); + settings->proxyPort = ui->httpProxyPort->text().toUShort(); settings->proxyAuthenticate = ui->httpProxyNeedsAuth->isChecked(); settings->proxyUserName = ui->httpProxyUser->text(); settings->proxyPassword = ui->httpProxyPass->text(); @@ -850,7 +850,7 @@ int SettingsDialog::percent(qint64 fraction, qint64 total) if (!total) return 0; - return fraction / static_cast(total) * 100; + return static_cast(fraction / static_cast(total) * 100); } QString SettingsDialog::cacheLocation(const QString &fileName) From ff2b2db8e399a5d22ee5f424d28b077975cad268 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 10 Sep 2016 23:43:00 -0400 Subject: [PATCH 214/273] qmake: Move FreeDesktop assets to a separate subproject --- assets/assets.pro | 23 ++++++++++++++++++ .../freedesktop}/appicons/128/zeal.png | Bin .../freedesktop}/appicons/16/zeal.png | Bin .../freedesktop}/appicons/24/zeal.png | Bin .../freedesktop}/appicons/32/zeal.png | Bin .../freedesktop}/appicons/64/zeal.png | Bin {src => assets/freedesktop}/zeal.desktop | 0 src/src.pro | 16 ------------ zeal.pro | 2 +- 9 files changed, 24 insertions(+), 17 deletions(-) create mode 100644 assets/assets.pro rename {src => assets/freedesktop}/appicons/128/zeal.png (100%) rename {src => assets/freedesktop}/appicons/16/zeal.png (100%) rename {src => assets/freedesktop}/appicons/24/zeal.png (100%) rename {src => assets/freedesktop}/appicons/32/zeal.png (100%) rename {src => assets/freedesktop}/appicons/64/zeal.png (100%) rename {src => assets/freedesktop}/zeal.desktop (100%) diff --git a/assets/assets.pro b/assets/assets.pro new file mode 100644 index 000000000..2f1136b01 --- /dev/null +++ b/assets/assets.pro @@ -0,0 +1,23 @@ +TEMPLATE = aux + +include($$SRC_ROOT/common.pri) + +unix:!macx { + TARGET = zeal + appicons16.files=freedesktop/appicons/16/* + appicons24.files=freedesktop/appicons/24/* + appicons32.files=freedesktop/appicons/32/* + appicons64.files=freedesktop/appicons/64/* + appicons128.files=freedesktop/appicons/128/* + + appicons16.path=$$PREFIX/share/icons/hicolor/16x16/apps + appicons24.path=$$PREFIX/share/icons/hicolor/24x24/apps + appicons32.path=$$PREFIX/share/icons/hicolor/32x32/apps + appicons64.path=$$PREFIX/share/icons/hicolor/64x64/apps + appicons128.path=$$PREFIX/share/icons/hicolor/128x128/apps + + desktop.files=freedesktop/zeal.desktop + desktop.path=$$PREFIX/share/applications + + INSTALLS += appicons16 appicons24 appicons32 appicons64 appicons128 desktop +} diff --git a/src/appicons/128/zeal.png b/assets/freedesktop/appicons/128/zeal.png similarity index 100% rename from src/appicons/128/zeal.png rename to assets/freedesktop/appicons/128/zeal.png diff --git a/src/appicons/16/zeal.png b/assets/freedesktop/appicons/16/zeal.png similarity index 100% rename from src/appicons/16/zeal.png rename to assets/freedesktop/appicons/16/zeal.png diff --git a/src/appicons/24/zeal.png b/assets/freedesktop/appicons/24/zeal.png similarity index 100% rename from src/appicons/24/zeal.png rename to assets/freedesktop/appicons/24/zeal.png diff --git a/src/appicons/32/zeal.png b/assets/freedesktop/appicons/32/zeal.png similarity index 100% rename from src/appicons/32/zeal.png rename to assets/freedesktop/appicons/32/zeal.png diff --git a/src/appicons/64/zeal.png b/assets/freedesktop/appicons/64/zeal.png similarity index 100% rename from src/appicons/64/zeal.png rename to assets/freedesktop/appicons/64/zeal.png diff --git a/src/zeal.desktop b/assets/freedesktop/zeal.desktop similarity index 100% rename from src/zeal.desktop rename to assets/freedesktop/zeal.desktop diff --git a/src/src.pro b/src/src.pro index 556c56d13..34f1936af 100644 --- a/src/src.pro +++ b/src/src.pro @@ -25,22 +25,6 @@ DESTDIR = $$BUILD_ROOT/bin unix:!macx { TARGET = zeal - appicons16.files=appicons/16/* - appicons24.files=appicons/24/* - appicons32.files=appicons/32/* - appicons64.files=appicons/64/* - appicons128.files=appicons/128/* - - appicons16.path=$$PREFIX/share/icons/hicolor/16x16/apps - appicons24.path=$$PREFIX/share/icons/hicolor/24x24/apps - appicons32.path=$$PREFIX/share/icons/hicolor/32x32/apps - appicons64.path=$$PREFIX/share/icons/hicolor/64x64/apps - appicons128.path=$$PREFIX/share/icons/hicolor/128x128/apps - - desktop.files=zeal.desktop - desktop.path=$$PREFIX/share/applications - - INSTALLS += appicons16 appicons24 appicons32 appicons64 appicons128 desktop } win32 { diff --git a/zeal.pro b/zeal.pro index dc7a87b65..2ba5ff08a 100644 --- a/zeal.pro +++ b/zeal.pro @@ -9,9 +9,9 @@ lessThan(QT_VERSION, "5.2.0") { } TEMPLATE = subdirs -CONFIG += ordered SUBDIRS += \ + assets \ src # Ease access to these files from Qt Creator From 140785099c12c9d8cb81646b5450b2a5b2996eb2 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 10 Sep 2016 23:44:59 -0400 Subject: [PATCH 215/273] registry: Remove forgotten shell script --- src/registry/rename.sh | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/registry/rename.sh diff --git a/src/registry/rename.sh b/src/registry/rename.sh deleted file mode 100644 index 5220b2a06..000000000 --- a/src/registry/rename.sh +++ /dev/null @@ -1,5 +0,0 @@ -for file in zeal*; -do - mv "$file" "${file#XY zeal}" -done - From 1c068d42f72ce16d7dea0f863ad903640d5a0492 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 02:14:48 -0400 Subject: [PATCH 216/273] qmake: Reorganize the whole project This is an attempt to provide a better structure to the project. All modules are now individual subprojects called libraries. QxtGlobalShortcut was moved to the Ui library, and resources are part of the application (app) subproject. --- .qmake.conf | 3 ++ assets/assets.pro | 4 +- common.pri => qmake/common.pri | 8 +++- qmake/library.pri | 8 ++++ .../qxtglobalshortcut/qxtglobalshortcut.pri | 20 --------- src/app/app.pro | 38 ++++++++++++++++ src/{ => app}/main.cpp | 6 +-- src/{ => app}/resources/browser/highlight.css | 0 src/{ => app}/resources/browser/main.css | 0 src/{ => app}/resources/browser/start.html | 0 .../resources/icons/logo/128x128.png | Bin src/{ => app}/resources/icons/logo/64x64.png | Bin src/{ => app}/resources/icons/logo/icon.png | Bin .../resources/icons/logo/icon@2x.png | Bin .../resources/icons/type/Abbreviation.png | Bin .../resources/icons/type/Abbreviation@2x.png | Bin src/{ => app}/resources/icons/type/Alias.png | Bin .../resources/icons/type/Alias@2x.png | Bin .../resources/icons/type/Annotation.png | Bin .../resources/icons/type/Annotation@2x.png | Bin .../resources/icons/type/Attribute.png | Bin .../resources/icons/type/Attribute@2x.png | Bin src/{ => app}/resources/icons/type/Axiom.png | Bin .../resources/icons/type/Axiom@2x.png | Bin .../resources/icons/type/Binding.png | Bin .../resources/icons/type/Binding@2x.png | Bin .../resources/icons/type/Bookmark.png | Bin .../resources/icons/type/Bookmark@2x.png | Bin .../resources/icons/type/Builtin.png | Bin .../resources/icons/type/Builtin@2x.png | Bin .../resources/icons/type/Callback.png | Bin .../resources/icons/type/Callback@2x.png | Bin .../resources/icons/type/Category.png | Bin .../resources/icons/type/Category@2x.png | Bin src/{ => app}/resources/icons/type/Class.png | Bin .../resources/icons/type/Class@2x.png | Bin .../resources/icons/type/Collection.png | Bin .../resources/icons/type/Collection@2x.png | Bin src/{ => app}/resources/icons/type/Column.png | Bin .../resources/icons/type/Column@2x.png | Bin .../resources/icons/type/Command.png | Bin .../resources/icons/type/Command@2x.png | Bin .../resources/icons/type/Component.png | Bin .../resources/icons/type/Component@2x.png | Bin .../resources/icons/type/Constant.png | Bin .../resources/icons/type/Constant@2x.png | Bin .../resources/icons/type/Constructor.png | Bin .../resources/icons/type/Constructor@2x.png | Bin .../resources/icons/type/Conversion.png | Bin .../resources/icons/type/Conversion@2x.png | Bin .../resources/icons/type/Database.png | Bin .../resources/icons/type/Database@2x.png | Bin .../resources/icons/type/Decorator.png | Bin .../resources/icons/type/Decorator@2x.png | Bin src/{ => app}/resources/icons/type/Define.png | Bin .../resources/icons/type/Define@2x.png | Bin .../resources/icons/type/Delegate.png | Bin .../resources/icons/type/Delegate@2x.png | Bin .../resources/icons/type/DeletedSnippet.png | Bin .../icons/type/DeletedSnippet@2x.png | Bin .../resources/icons/type/Diagram.png | Bin .../resources/icons/type/Diagram@2x.png | Bin .../resources/icons/type/Directive.png | Bin .../resources/icons/type/Directive@2x.png | Bin .../resources/icons/type/Element.png | Bin .../resources/icons/type/Element@2x.png | Bin src/{ => app}/resources/icons/type/Entry.png | Bin .../resources/icons/type/Entry@2x.png | Bin .../resources/icons/type/Enumeration.png | Bin .../resources/icons/type/Enumeration@2x.png | Bin .../resources/icons/type/Environment.png | Bin .../resources/icons/type/Environment@2x.png | Bin src/{ => app}/resources/icons/type/Error.png | Bin .../resources/icons/type/Error@2x.png | Bin src/{ => app}/resources/icons/type/Event.png | Bin .../resources/icons/type/Event@2x.png | Bin .../resources/icons/type/Exception.png | Bin .../resources/icons/type/Exception@2x.png | Bin .../resources/icons/type/Extension.png | Bin .../resources/icons/type/Extension@2x.png | Bin src/{ => app}/resources/icons/type/Field.png | Bin .../resources/icons/type/Field@2x.png | Bin src/{ => app}/resources/icons/type/File.png | Bin .../resources/icons/type/File@2x.png | Bin src/{ => app}/resources/icons/type/Filter.png | Bin .../resources/icons/type/Filter@2x.png | Bin .../resources/icons/type/Foreign Key.png | Bin .../resources/icons/type/Foreign Key@2x.png | Bin .../resources/icons/type/Framework.png | Bin .../resources/icons/type/Framework@2x.png | Bin .../resources/icons/type/Function.png | Bin .../resources/icons/type/Function@2x.png | Bin src/{ => app}/resources/icons/type/Global.png | Bin .../resources/icons/type/Global@2x.png | Bin src/{ => app}/resources/icons/type/Guide.png | Bin .../resources/icons/type/Guide@2x.png | Bin src/{ => app}/resources/icons/type/Helper.png | Bin .../resources/icons/type/Helper@2x.png | Bin src/{ => app}/resources/icons/type/Hook.png | Bin .../resources/icons/type/Hook@2x.png | Bin src/{ => app}/resources/icons/type/Index.png | Bin .../resources/icons/type/Index@2x.png | Bin .../resources/icons/type/Indirection.png | Bin .../resources/icons/type/Indirection@2x.png | Bin .../resources/icons/type/Inductive.png | Bin .../resources/icons/type/Inductive@2x.png | Bin .../resources/icons/type/Instance.png | Bin .../resources/icons/type/Instance@2x.png | Bin .../resources/icons/type/Instruction.png | Bin .../resources/icons/type/Instruction@2x.png | Bin .../resources/icons/type/Interface.png | Bin .../resources/icons/type/Interface@2x.png | Bin .../resources/icons/type/Keyword.png | Bin .../resources/icons/type/Keyword@2x.png | Bin src/{ => app}/resources/icons/type/Lemma.png | Bin .../resources/icons/type/Lemma@2x.png | Bin .../resources/icons/type/Library.png | Bin .../resources/icons/type/Library@2x.png | Bin .../resources/icons/type/Literal.png | Bin .../resources/icons/type/Literal@2x.png | Bin src/{ => app}/resources/icons/type/Macro.png | Bin .../resources/icons/type/Macro@2x.png | Bin src/{ => app}/resources/icons/type/Method.png | Bin .../resources/icons/type/Method@2x.png | Bin src/{ => app}/resources/icons/type/Mixin.png | Bin .../resources/icons/type/Mixin@2x.png | Bin .../resources/icons/type/Modifier.png | Bin .../resources/icons/type/Modifier@2x.png | Bin src/{ => app}/resources/icons/type/Module.png | Bin .../resources/icons/type/Module@2x.png | Bin .../resources/icons/type/Namespace.png | Bin .../resources/icons/type/Namespace@2x.png | Bin .../resources/icons/type/NewSnippet.png | Bin .../resources/icons/type/NewSnippet@2x.png | Bin .../resources/icons/type/Notation.png | Bin .../resources/icons/type/Notation@2x.png | Bin src/{ => app}/resources/icons/type/Object.png | Bin .../resources/icons/type/Object@2x.png | Bin .../resources/icons/type/Operator.png | Bin .../resources/icons/type/Operator@2x.png | Bin src/{ => app}/resources/icons/type/Option.png | Bin .../resources/icons/type/Option@2x.png | Bin .../resources/icons/type/Package.png | Bin .../resources/icons/type/Package@2x.png | Bin .../resources/icons/type/Parameter.png | Bin .../resources/icons/type/Parameter@2x.png | Bin .../resources/icons/type/Pattern.png | Bin .../resources/icons/type/Pattern@2x.png | Bin src/{ => app}/resources/icons/type/Plugin.png | Bin .../resources/icons/type/Plugin@2x.png | Bin .../resources/icons/type/Procedure.png | Bin .../resources/icons/type/Procedure@2x.png | Bin .../resources/icons/type/Projection.png | Bin .../resources/icons/type/Projection@2x.png | Bin .../resources/icons/type/Property.png | Bin .../resources/icons/type/Property@2x.png | Bin .../resources/icons/type/Protocol.png | Bin .../resources/icons/type/Protocol@2x.png | Bin .../resources/icons/type/Provider.png | Bin .../resources/icons/type/Provider@2x.png | Bin .../resources/icons/type/Provisioner.png | Bin .../resources/icons/type/Provisioner@2x.png | Bin src/{ => app}/resources/icons/type/Query.png | Bin .../resources/icons/type/Query@2x.png | Bin src/{ => app}/resources/icons/type/Record.png | Bin .../resources/icons/type/Record@2x.png | Bin .../resources/icons/type/Relationship.png | Bin .../resources/icons/type/Relationship@2x.png | Bin src/{ => app}/resources/icons/type/Report.png | Bin .../resources/icons/type/Report@2x.png | Bin .../resources/icons/type/Request.png | Bin .../resources/icons/type/Request@2x.png | Bin .../resources/icons/type/Resource.png | Bin .../resources/icons/type/Resource@2x.png | Bin src/{ => app}/resources/icons/type/Sample.png | Bin .../resources/icons/type/Sample@2x.png | Bin src/{ => app}/resources/icons/type/Schema.png | Bin .../resources/icons/type/Schema@2x.png | Bin src/{ => app}/resources/icons/type/Script.png | Bin .../resources/icons/type/Script@2x.png | Bin .../resources/icons/type/Section.png | Bin .../resources/icons/type/Section@2x.png | Bin .../resources/icons/type/Service.png | Bin .../resources/icons/type/Service@2x.png | Bin .../resources/icons/type/Setting.png | Bin .../resources/icons/type/Setting@2x.png | Bin .../resources/icons/type/Shortcut.png | Bin .../resources/icons/type/Shortcut@2x.png | Bin .../resources/icons/type/Signature.png | Bin .../resources/icons/type/Signature@2x.png | Bin .../resources/icons/type/Snippet.png | Bin .../resources/icons/type/Snippet@2x.png | Bin .../resources/icons/type/Special Form.png | Bin .../resources/icons/type/Special Form@2x.png | Bin .../resources/icons/type/Statement.png | Bin .../resources/icons/type/Statement@2x.png | Bin .../resources/icons/type/Structure.png | Bin .../resources/icons/type/Structure@2x.png | Bin src/{ => app}/resources/icons/type/Style.png | Bin .../resources/icons/type/Style@2x.png | Bin .../resources/icons/type/Subroutine.png | Bin .../resources/icons/type/Subroutine@2x.png | Bin src/{ => app}/resources/icons/type/Syntax.png | Bin .../resources/icons/type/Syntax@2x.png | Bin src/{ => app}/resources/icons/type/Table.png | Bin .../resources/icons/type/Table@2x.png | Bin src/{ => app}/resources/icons/type/Tactic.png | Bin .../resources/icons/type/Tactic@2x.png | Bin src/{ => app}/resources/icons/type/Tag.png | Bin src/{ => app}/resources/icons/type/Tag@2x.png | Bin src/{ => app}/resources/icons/type/Test.png | Bin .../resources/icons/type/Test@2x.png | Bin src/{ => app}/resources/icons/type/Trait.png | Bin .../resources/icons/type/Trait@2x.png | Bin .../resources/icons/type/Trigger.png | Bin .../resources/icons/type/Trigger@2x.png | Bin src/{ => app}/resources/icons/type/Type.png | Bin .../resources/icons/type/Type@2x.png | Bin src/{ => app}/resources/icons/type/Union.png | Bin .../resources/icons/type/Union@2x.png | Bin .../resources/icons/type/Unknown.png | Bin .../resources/icons/type/Unknown@2x.png | Bin src/{ => app}/resources/icons/type/Value.png | Bin .../resources/icons/type/Value@2x.png | Bin .../resources/icons/type/Variable.png | Bin .../resources/icons/type/Variable@2x.png | Bin .../resources/icons/type/Variant.png | Bin .../resources/icons/type/Variant@2x.png | Bin src/{ => app}/resources/icons/type/View.png | Bin .../resources/icons/type/View@2x.png | Bin src/{ => app}/resources/icons/type/Web.png | Bin src/{ => app}/resources/icons/type/Web@2x.png | Bin src/{ => app}/resources/icons/type/Word.png | Bin .../resources/icons/type/Word@2x.png | Bin .../resources/icons/type/_DashAnnotations.png | Bin .../icons/type/_DashAnnotations@2x.png | Bin .../resources/icons/type/_Struct.png | Bin .../resources/icons/type/_Struct@2x.png | Bin src/{ => app}/resources/zeal.icns | Bin src/{ => app}/resources/zeal.ico | Bin src/{ => app}/resources/zeal.qrc | 0 src/{ => libs}/core/application.cpp | 9 ++-- src/{ => libs}/core/application.h | 0 src/{ => libs}/core/core.pri | 3 +- src/libs/core/core.pro | 4 ++ src/{ => libs}/core/extractor.cpp | 0 src/{ => libs}/core/extractor.h | 0 src/{ => libs}/core/localserver.cpp | 2 +- src/{ => libs}/core/localserver.h | 0 src/{ => libs}/core/settings.cpp | 0 src/{ => libs}/core/settings.h | 0 src/libs/libs.pro | 7 +++ src/{ => libs}/registry/cancellationtoken.cpp | 0 src/{ => libs}/registry/cancellationtoken.h | 0 src/{ => libs}/registry/docset.cpp | 3 +- src/{ => libs}/registry/docset.h | 0 src/{ => libs}/registry/docsetmetadata.cpp | 0 src/{ => libs}/registry/docsetmetadata.h | 0 src/{ => libs}/registry/docsetregistry.cpp | 0 src/{ => libs}/registry/docsetregistry.h | 0 src/{ => libs}/registry/listmodel.cpp | 0 src/{ => libs}/registry/listmodel.h | 0 src/libs/registry/registry.pri | 1 + src/libs/registry/registry.pro | 6 +++ src/{ => libs}/registry/searchmodel.cpp | 2 +- src/{ => libs}/registry/searchmodel.h | 0 src/{ => libs}/registry/searchquery.cpp | 0 src/{ => libs}/registry/searchquery.h | 0 src/{ => libs}/registry/searchresult.cpp | 0 src/{ => libs}/registry/searchresult.h | 0 src/{ => libs}/ui/aboutdialog.cpp | 0 src/{ => libs}/ui/aboutdialog.h | 0 src/{ => libs}/ui/docsetlistitemdelegate.cpp | 2 +- src/{ => libs}/ui/docsetlistitemdelegate.h | 0 src/{ => libs}/ui/forms/aboutdialog.ui | 0 src/{ => libs}/ui/forms/mainwindow.ui | 0 src/{ => libs}/ui/forms/settingsdialog.ui | 0 src/{ => libs}/ui/mainwindow.cpp | 14 +++--- src/{ => libs}/ui/mainwindow.h | 4 +- src/{ => libs}/ui/progressitemdelegate.cpp | 0 src/{ => libs}/ui/progressitemdelegate.h | 0 .../qxtglobalshortcut/qxtglobalshortcut.cpp | 0 .../ui}/qxtglobalshortcut/qxtglobalshortcut.h | 0 .../qxtglobalshortcut/qxtglobalshortcut.pri | 6 +++ .../qxtglobalshortcut_mac.cpp | 0 .../qxtglobalshortcut/qxtglobalshortcut_p.h | 0 .../qxtglobalshortcut_win.cpp | 0 .../qxtglobalshortcut_x11.cpp | 0 src/{ => libs}/ui/searchitemdelegate.cpp | 0 src/{ => libs}/ui/searchitemdelegate.h | 0 src/{ => libs}/ui/settingsdialog.cpp | 9 ++-- src/{ => libs}/ui/settingsdialog.h | 2 +- src/{ => libs}/ui/ui.pri | 23 ++++++---- src/libs/ui/ui.pro | 14 ++++++ .../ui/widgets/searchablewebview.cpp | 0 src/{ => libs}/ui/widgets/searchablewebview.h | 0 src/{ => libs}/ui/widgets/searchedit.cpp | 2 +- src/{ => libs}/ui/widgets/searchedit.h | 0 src/{ => libs}/ui/widgets/shortcutedit.cpp | 0 src/{ => libs}/ui/widgets/shortcutedit.h | 0 src/{ => libs}/ui/widgets/toolbarframe.cpp | 0 src/{ => libs}/ui/widgets/toolbarframe.h | 0 src/{ => libs}/ui/widgets/webview.cpp | 0 src/{ => libs}/ui/widgets/webview.h | 0 src/{ => libs}/util/plist.cpp | 0 src/{ => libs}/util/plist.h | 0 src/libs/util/util.pri | 1 + src/libs/util/util.pro | 4 ++ src/{ => libs}/util/version.cpp | 0 src/{ => libs}/util/version.h | 0 src/registry/registry.pri | 5 --- src/src.pro | 42 +++--------------- 312 files changed, 151 insertions(+), 101 deletions(-) rename common.pri => qmake/common.pri (92%) create mode 100644 qmake/library.pri delete mode 100644 src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.pri create mode 100644 src/app/app.pro rename src/{ => app}/main.cpp (99%) rename src/{ => app}/resources/browser/highlight.css (100%) rename src/{ => app}/resources/browser/main.css (100%) rename src/{ => app}/resources/browser/start.html (100%) rename src/{ => app}/resources/icons/logo/128x128.png (100%) rename src/{ => app}/resources/icons/logo/64x64.png (100%) rename src/{ => app}/resources/icons/logo/icon.png (100%) rename src/{ => app}/resources/icons/logo/icon@2x.png (100%) rename src/{ => app}/resources/icons/type/Abbreviation.png (100%) rename src/{ => app}/resources/icons/type/Abbreviation@2x.png (100%) rename src/{ => app}/resources/icons/type/Alias.png (100%) rename src/{ => app}/resources/icons/type/Alias@2x.png (100%) rename src/{ => app}/resources/icons/type/Annotation.png (100%) rename src/{ => app}/resources/icons/type/Annotation@2x.png (100%) rename src/{ => app}/resources/icons/type/Attribute.png (100%) rename src/{ => app}/resources/icons/type/Attribute@2x.png (100%) rename src/{ => app}/resources/icons/type/Axiom.png (100%) rename src/{ => app}/resources/icons/type/Axiom@2x.png (100%) rename src/{ => app}/resources/icons/type/Binding.png (100%) rename src/{ => app}/resources/icons/type/Binding@2x.png (100%) rename src/{ => app}/resources/icons/type/Bookmark.png (100%) rename src/{ => app}/resources/icons/type/Bookmark@2x.png (100%) rename src/{ => app}/resources/icons/type/Builtin.png (100%) rename src/{ => app}/resources/icons/type/Builtin@2x.png (100%) rename src/{ => app}/resources/icons/type/Callback.png (100%) rename src/{ => app}/resources/icons/type/Callback@2x.png (100%) rename src/{ => app}/resources/icons/type/Category.png (100%) rename src/{ => app}/resources/icons/type/Category@2x.png (100%) rename src/{ => app}/resources/icons/type/Class.png (100%) rename src/{ => app}/resources/icons/type/Class@2x.png (100%) rename src/{ => app}/resources/icons/type/Collection.png (100%) rename src/{ => app}/resources/icons/type/Collection@2x.png (100%) rename src/{ => app}/resources/icons/type/Column.png (100%) rename src/{ => app}/resources/icons/type/Column@2x.png (100%) rename src/{ => app}/resources/icons/type/Command.png (100%) rename src/{ => app}/resources/icons/type/Command@2x.png (100%) rename src/{ => app}/resources/icons/type/Component.png (100%) rename src/{ => app}/resources/icons/type/Component@2x.png (100%) rename src/{ => app}/resources/icons/type/Constant.png (100%) rename src/{ => app}/resources/icons/type/Constant@2x.png (100%) rename src/{ => app}/resources/icons/type/Constructor.png (100%) rename src/{ => app}/resources/icons/type/Constructor@2x.png (100%) rename src/{ => app}/resources/icons/type/Conversion.png (100%) rename src/{ => app}/resources/icons/type/Conversion@2x.png (100%) rename src/{ => app}/resources/icons/type/Database.png (100%) rename src/{ => app}/resources/icons/type/Database@2x.png (100%) rename src/{ => app}/resources/icons/type/Decorator.png (100%) rename src/{ => app}/resources/icons/type/Decorator@2x.png (100%) rename src/{ => app}/resources/icons/type/Define.png (100%) rename src/{ => app}/resources/icons/type/Define@2x.png (100%) rename src/{ => app}/resources/icons/type/Delegate.png (100%) rename src/{ => app}/resources/icons/type/Delegate@2x.png (100%) rename src/{ => app}/resources/icons/type/DeletedSnippet.png (100%) rename src/{ => app}/resources/icons/type/DeletedSnippet@2x.png (100%) rename src/{ => app}/resources/icons/type/Diagram.png (100%) rename src/{ => app}/resources/icons/type/Diagram@2x.png (100%) rename src/{ => app}/resources/icons/type/Directive.png (100%) rename src/{ => app}/resources/icons/type/Directive@2x.png (100%) rename src/{ => app}/resources/icons/type/Element.png (100%) rename src/{ => app}/resources/icons/type/Element@2x.png (100%) rename src/{ => app}/resources/icons/type/Entry.png (100%) rename src/{ => app}/resources/icons/type/Entry@2x.png (100%) rename src/{ => app}/resources/icons/type/Enumeration.png (100%) rename src/{ => app}/resources/icons/type/Enumeration@2x.png (100%) rename src/{ => app}/resources/icons/type/Environment.png (100%) rename src/{ => app}/resources/icons/type/Environment@2x.png (100%) rename src/{ => app}/resources/icons/type/Error.png (100%) rename src/{ => app}/resources/icons/type/Error@2x.png (100%) rename src/{ => app}/resources/icons/type/Event.png (100%) rename src/{ => app}/resources/icons/type/Event@2x.png (100%) rename src/{ => app}/resources/icons/type/Exception.png (100%) rename src/{ => app}/resources/icons/type/Exception@2x.png (100%) rename src/{ => app}/resources/icons/type/Extension.png (100%) rename src/{ => app}/resources/icons/type/Extension@2x.png (100%) rename src/{ => app}/resources/icons/type/Field.png (100%) rename src/{ => app}/resources/icons/type/Field@2x.png (100%) rename src/{ => app}/resources/icons/type/File.png (100%) rename src/{ => app}/resources/icons/type/File@2x.png (100%) rename src/{ => app}/resources/icons/type/Filter.png (100%) rename src/{ => app}/resources/icons/type/Filter@2x.png (100%) rename src/{ => app}/resources/icons/type/Foreign Key.png (100%) rename src/{ => app}/resources/icons/type/Foreign Key@2x.png (100%) rename src/{ => app}/resources/icons/type/Framework.png (100%) rename src/{ => app}/resources/icons/type/Framework@2x.png (100%) rename src/{ => app}/resources/icons/type/Function.png (100%) rename src/{ => app}/resources/icons/type/Function@2x.png (100%) rename src/{ => app}/resources/icons/type/Global.png (100%) rename src/{ => app}/resources/icons/type/Global@2x.png (100%) rename src/{ => app}/resources/icons/type/Guide.png (100%) rename src/{ => app}/resources/icons/type/Guide@2x.png (100%) rename src/{ => app}/resources/icons/type/Helper.png (100%) rename src/{ => app}/resources/icons/type/Helper@2x.png (100%) rename src/{ => app}/resources/icons/type/Hook.png (100%) rename src/{ => app}/resources/icons/type/Hook@2x.png (100%) rename src/{ => app}/resources/icons/type/Index.png (100%) rename src/{ => app}/resources/icons/type/Index@2x.png (100%) rename src/{ => app}/resources/icons/type/Indirection.png (100%) rename src/{ => app}/resources/icons/type/Indirection@2x.png (100%) rename src/{ => app}/resources/icons/type/Inductive.png (100%) rename src/{ => app}/resources/icons/type/Inductive@2x.png (100%) rename src/{ => app}/resources/icons/type/Instance.png (100%) rename src/{ => app}/resources/icons/type/Instance@2x.png (100%) rename src/{ => app}/resources/icons/type/Instruction.png (100%) rename src/{ => app}/resources/icons/type/Instruction@2x.png (100%) rename src/{ => app}/resources/icons/type/Interface.png (100%) rename src/{ => app}/resources/icons/type/Interface@2x.png (100%) rename src/{ => app}/resources/icons/type/Keyword.png (100%) rename src/{ => app}/resources/icons/type/Keyword@2x.png (100%) rename src/{ => app}/resources/icons/type/Lemma.png (100%) rename src/{ => app}/resources/icons/type/Lemma@2x.png (100%) rename src/{ => app}/resources/icons/type/Library.png (100%) rename src/{ => app}/resources/icons/type/Library@2x.png (100%) rename src/{ => app}/resources/icons/type/Literal.png (100%) rename src/{ => app}/resources/icons/type/Literal@2x.png (100%) rename src/{ => app}/resources/icons/type/Macro.png (100%) rename src/{ => app}/resources/icons/type/Macro@2x.png (100%) rename src/{ => app}/resources/icons/type/Method.png (100%) rename src/{ => app}/resources/icons/type/Method@2x.png (100%) rename src/{ => app}/resources/icons/type/Mixin.png (100%) rename src/{ => app}/resources/icons/type/Mixin@2x.png (100%) rename src/{ => app}/resources/icons/type/Modifier.png (100%) rename src/{ => app}/resources/icons/type/Modifier@2x.png (100%) rename src/{ => app}/resources/icons/type/Module.png (100%) rename src/{ => app}/resources/icons/type/Module@2x.png (100%) rename src/{ => app}/resources/icons/type/Namespace.png (100%) rename src/{ => app}/resources/icons/type/Namespace@2x.png (100%) rename src/{ => app}/resources/icons/type/NewSnippet.png (100%) rename src/{ => app}/resources/icons/type/NewSnippet@2x.png (100%) rename src/{ => app}/resources/icons/type/Notation.png (100%) rename src/{ => app}/resources/icons/type/Notation@2x.png (100%) rename src/{ => app}/resources/icons/type/Object.png (100%) rename src/{ => app}/resources/icons/type/Object@2x.png (100%) rename src/{ => app}/resources/icons/type/Operator.png (100%) rename src/{ => app}/resources/icons/type/Operator@2x.png (100%) rename src/{ => app}/resources/icons/type/Option.png (100%) rename src/{ => app}/resources/icons/type/Option@2x.png (100%) rename src/{ => app}/resources/icons/type/Package.png (100%) rename src/{ => app}/resources/icons/type/Package@2x.png (100%) rename src/{ => app}/resources/icons/type/Parameter.png (100%) rename src/{ => app}/resources/icons/type/Parameter@2x.png (100%) rename src/{ => app}/resources/icons/type/Pattern.png (100%) rename src/{ => app}/resources/icons/type/Pattern@2x.png (100%) rename src/{ => app}/resources/icons/type/Plugin.png (100%) rename src/{ => app}/resources/icons/type/Plugin@2x.png (100%) rename src/{ => app}/resources/icons/type/Procedure.png (100%) rename src/{ => app}/resources/icons/type/Procedure@2x.png (100%) rename src/{ => app}/resources/icons/type/Projection.png (100%) rename src/{ => app}/resources/icons/type/Projection@2x.png (100%) rename src/{ => app}/resources/icons/type/Property.png (100%) rename src/{ => app}/resources/icons/type/Property@2x.png (100%) rename src/{ => app}/resources/icons/type/Protocol.png (100%) rename src/{ => app}/resources/icons/type/Protocol@2x.png (100%) rename src/{ => app}/resources/icons/type/Provider.png (100%) rename src/{ => app}/resources/icons/type/Provider@2x.png (100%) rename src/{ => app}/resources/icons/type/Provisioner.png (100%) rename src/{ => app}/resources/icons/type/Provisioner@2x.png (100%) rename src/{ => app}/resources/icons/type/Query.png (100%) rename src/{ => app}/resources/icons/type/Query@2x.png (100%) rename src/{ => app}/resources/icons/type/Record.png (100%) rename src/{ => app}/resources/icons/type/Record@2x.png (100%) rename src/{ => app}/resources/icons/type/Relationship.png (100%) rename src/{ => app}/resources/icons/type/Relationship@2x.png (100%) rename src/{ => app}/resources/icons/type/Report.png (100%) rename src/{ => app}/resources/icons/type/Report@2x.png (100%) rename src/{ => app}/resources/icons/type/Request.png (100%) rename src/{ => app}/resources/icons/type/Request@2x.png (100%) rename src/{ => app}/resources/icons/type/Resource.png (100%) rename src/{ => app}/resources/icons/type/Resource@2x.png (100%) rename src/{ => app}/resources/icons/type/Sample.png (100%) rename src/{ => app}/resources/icons/type/Sample@2x.png (100%) rename src/{ => app}/resources/icons/type/Schema.png (100%) rename src/{ => app}/resources/icons/type/Schema@2x.png (100%) rename src/{ => app}/resources/icons/type/Script.png (100%) rename src/{ => app}/resources/icons/type/Script@2x.png (100%) rename src/{ => app}/resources/icons/type/Section.png (100%) rename src/{ => app}/resources/icons/type/Section@2x.png (100%) rename src/{ => app}/resources/icons/type/Service.png (100%) rename src/{ => app}/resources/icons/type/Service@2x.png (100%) rename src/{ => app}/resources/icons/type/Setting.png (100%) rename src/{ => app}/resources/icons/type/Setting@2x.png (100%) rename src/{ => app}/resources/icons/type/Shortcut.png (100%) rename src/{ => app}/resources/icons/type/Shortcut@2x.png (100%) rename src/{ => app}/resources/icons/type/Signature.png (100%) rename src/{ => app}/resources/icons/type/Signature@2x.png (100%) rename src/{ => app}/resources/icons/type/Snippet.png (100%) rename src/{ => app}/resources/icons/type/Snippet@2x.png (100%) rename src/{ => app}/resources/icons/type/Special Form.png (100%) rename src/{ => app}/resources/icons/type/Special Form@2x.png (100%) rename src/{ => app}/resources/icons/type/Statement.png (100%) rename src/{ => app}/resources/icons/type/Statement@2x.png (100%) rename src/{ => app}/resources/icons/type/Structure.png (100%) rename src/{ => app}/resources/icons/type/Structure@2x.png (100%) rename src/{ => app}/resources/icons/type/Style.png (100%) rename src/{ => app}/resources/icons/type/Style@2x.png (100%) rename src/{ => app}/resources/icons/type/Subroutine.png (100%) rename src/{ => app}/resources/icons/type/Subroutine@2x.png (100%) rename src/{ => app}/resources/icons/type/Syntax.png (100%) rename src/{ => app}/resources/icons/type/Syntax@2x.png (100%) rename src/{ => app}/resources/icons/type/Table.png (100%) rename src/{ => app}/resources/icons/type/Table@2x.png (100%) rename src/{ => app}/resources/icons/type/Tactic.png (100%) rename src/{ => app}/resources/icons/type/Tactic@2x.png (100%) rename src/{ => app}/resources/icons/type/Tag.png (100%) rename src/{ => app}/resources/icons/type/Tag@2x.png (100%) rename src/{ => app}/resources/icons/type/Test.png (100%) rename src/{ => app}/resources/icons/type/Test@2x.png (100%) rename src/{ => app}/resources/icons/type/Trait.png (100%) rename src/{ => app}/resources/icons/type/Trait@2x.png (100%) rename src/{ => app}/resources/icons/type/Trigger.png (100%) rename src/{ => app}/resources/icons/type/Trigger@2x.png (100%) rename src/{ => app}/resources/icons/type/Type.png (100%) rename src/{ => app}/resources/icons/type/Type@2x.png (100%) rename src/{ => app}/resources/icons/type/Union.png (100%) rename src/{ => app}/resources/icons/type/Union@2x.png (100%) rename src/{ => app}/resources/icons/type/Unknown.png (100%) rename src/{ => app}/resources/icons/type/Unknown@2x.png (100%) rename src/{ => app}/resources/icons/type/Value.png (100%) rename src/{ => app}/resources/icons/type/Value@2x.png (100%) rename src/{ => app}/resources/icons/type/Variable.png (100%) rename src/{ => app}/resources/icons/type/Variable@2x.png (100%) rename src/{ => app}/resources/icons/type/Variant.png (100%) rename src/{ => app}/resources/icons/type/Variant@2x.png (100%) rename src/{ => app}/resources/icons/type/View.png (100%) rename src/{ => app}/resources/icons/type/View@2x.png (100%) rename src/{ => app}/resources/icons/type/Web.png (100%) rename src/{ => app}/resources/icons/type/Web@2x.png (100%) rename src/{ => app}/resources/icons/type/Word.png (100%) rename src/{ => app}/resources/icons/type/Word@2x.png (100%) rename src/{ => app}/resources/icons/type/_DashAnnotations.png (100%) rename src/{ => app}/resources/icons/type/_DashAnnotations@2x.png (100%) rename src/{ => app}/resources/icons/type/_Struct.png (100%) rename src/{ => app}/resources/icons/type/_Struct@2x.png (100%) rename src/{ => app}/resources/zeal.icns (100%) rename src/{ => app}/resources/zeal.ico (100%) rename src/{ => app}/resources/zeal.qrc (100%) rename src/{ => libs}/core/application.cpp (98%) rename src/{ => libs}/core/application.h (100%) rename src/{ => libs}/core/core.pri (65%) create mode 100644 src/libs/core/core.pro rename src/{ => libs}/core/extractor.cpp (100%) rename src/{ => libs}/core/extractor.h (100%) rename src/{ => libs}/core/localserver.cpp (98%) rename src/{ => libs}/core/localserver.h (100%) rename src/{ => libs}/core/settings.cpp (100%) rename src/{ => libs}/core/settings.h (100%) create mode 100644 src/libs/libs.pro rename src/{ => libs}/registry/cancellationtoken.cpp (100%) rename src/{ => libs}/registry/cancellationtoken.h (100%) rename src/{ => libs}/registry/docset.cpp (99%) rename src/{ => libs}/registry/docset.h (100%) rename src/{ => libs}/registry/docsetmetadata.cpp (100%) rename src/{ => libs}/registry/docsetmetadata.h (100%) rename src/{ => libs}/registry/docsetregistry.cpp (100%) rename src/{ => libs}/registry/docsetregistry.h (100%) rename src/{ => libs}/registry/listmodel.cpp (100%) rename src/{ => libs}/registry/listmodel.h (100%) create mode 100644 src/libs/registry/registry.pri create mode 100644 src/libs/registry/registry.pro rename src/{ => libs}/registry/searchmodel.cpp (99%) rename src/{ => libs}/registry/searchmodel.h (100%) rename src/{ => libs}/registry/searchquery.cpp (100%) rename src/{ => libs}/registry/searchquery.h (100%) rename src/{ => libs}/registry/searchresult.cpp (100%) rename src/{ => libs}/registry/searchresult.h (100%) rename src/{ => libs}/ui/aboutdialog.cpp (100%) rename src/{ => libs}/ui/aboutdialog.h (100%) rename src/{ => libs}/ui/docsetlistitemdelegate.cpp (98%) rename src/{ => libs}/ui/docsetlistitemdelegate.h (100%) rename src/{ => libs}/ui/forms/aboutdialog.ui (100%) rename src/{ => libs}/ui/forms/mainwindow.ui (100%) rename src/{ => libs}/ui/forms/settingsdialog.ui (100%) rename src/{ => libs}/ui/mainwindow.cpp (99%) rename src/{ => libs}/ui/mainwindow.h (97%) rename src/{ => libs}/ui/progressitemdelegate.cpp (100%) rename src/{ => libs}/ui/progressitemdelegate.h (100%) rename src/{3rdparty => libs/ui}/qxtglobalshortcut/qxtglobalshortcut.cpp (100%) rename src/{3rdparty => libs/ui}/qxtglobalshortcut/qxtglobalshortcut.h (100%) create mode 100644 src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.pri rename src/{3rdparty => libs/ui}/qxtglobalshortcut/qxtglobalshortcut_mac.cpp (100%) rename src/{3rdparty => libs/ui}/qxtglobalshortcut/qxtglobalshortcut_p.h (100%) rename src/{3rdparty => libs/ui}/qxtglobalshortcut/qxtglobalshortcut_win.cpp (100%) rename src/{3rdparty => libs/ui}/qxtglobalshortcut/qxtglobalshortcut_x11.cpp (100%) rename src/{ => libs}/ui/searchitemdelegate.cpp (100%) rename src/{ => libs}/ui/searchitemdelegate.h (100%) rename src/{ => libs}/ui/settingsdialog.cpp (99%) rename src/{ => libs}/ui/settingsdialog.h (98%) rename src/{ => libs}/ui/ui.pri (57%) create mode 100644 src/libs/ui/ui.pro rename src/{ => libs}/ui/widgets/searchablewebview.cpp (100%) rename src/{ => libs}/ui/widgets/searchablewebview.h (100%) rename src/{ => libs}/ui/widgets/searchedit.cpp (99%) rename src/{ => libs}/ui/widgets/searchedit.h (100%) rename src/{ => libs}/ui/widgets/shortcutedit.cpp (100%) rename src/{ => libs}/ui/widgets/shortcutedit.h (100%) rename src/{ => libs}/ui/widgets/toolbarframe.cpp (100%) rename src/{ => libs}/ui/widgets/toolbarframe.h (100%) rename src/{ => libs}/ui/widgets/webview.cpp (100%) rename src/{ => libs}/ui/widgets/webview.h (100%) rename src/{ => libs}/util/plist.cpp (100%) rename src/{ => libs}/util/plist.h (100%) create mode 100644 src/libs/util/util.pri create mode 100644 src/libs/util/util.pro rename src/{ => libs}/util/version.cpp (100%) rename src/{ => libs}/util/version.h (100%) delete mode 100644 src/registry/registry.pri diff --git a/.qmake.conf b/.qmake.conf index 5fbbff49d..e96e51b13 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,2 +1,5 @@ SRC_ROOT=$$PWD BUILD_ROOT=$$shadowed($$PWD) + +ZEAL_COMMON_PRI = $$SRC_ROOT/qmake/common.pri +ZEAL_LIBRARY_PRI = $$SRC_ROOT/qmake/library.pri diff --git a/assets/assets.pro b/assets/assets.pro index 2f1136b01..bb39f61e8 100644 --- a/assets/assets.pro +++ b/assets/assets.pro @@ -1,6 +1,6 @@ -TEMPLATE = aux +include($$ZEAL_COMMON_PRI) -include($$SRC_ROOT/common.pri) +TEMPLATE = aux unix:!macx { TARGET = zeal diff --git a/common.pri b/qmake/common.pri similarity index 92% rename from common.pri rename to qmake/common.pri index 87e3486ad..06129878a 100644 --- a/common.pri +++ b/qmake/common.pri @@ -2,10 +2,14 @@ # # This file must be included at the top of every non-subdirs .pro file. # Use: -# include($$SRC_ROOT/common.pri) +# include($$ZEAL_COMMON_PRI) # Compilation settings -CONFIG += c++11 silent +CONFIG += c++11 #silent + +# Shared include path +INCLUDEPATH += $$SRC_ROOT/src/libs +LIBS = -L$$BUILD_ROOT/.lib # QString options DEFINES *= QT_USE_QSTRINGBUILDER diff --git a/qmake/library.pri b/qmake/library.pri new file mode 100644 index 000000000..7effb1c8c --- /dev/null +++ b/qmake/library.pri @@ -0,0 +1,8 @@ +include($$ZEAL_COMMON_PRI) +include($$replace(_PRO_FILE_PWD_, ([^/]+$), \\1/\\1.pri)) + +TEMPLATE = lib +CONFIG += staticlib + +DESTDIR = $$BUILD_ROOT/.lib +TARGET = $$ZEAL_LIB_NAME diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.pri b/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.pri deleted file mode 100644 index 44257cfd9..000000000 --- a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.pri +++ /dev/null @@ -1,20 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += $$files($$PWD/*.h) -SOURCES += $$PWD/qxtglobalshortcut.cpp - -unix:!macx { - QT += x11extras - - CONFIG += link_pkgconfig - PKGCONFIG += x11 xcb xcb-keysyms - - SOURCES += $$PWD/qxtglobalshortcut_x11.cpp -} - -win32:SOURCES += $$PWD/qxtglobalshortcut_win.cpp - -macx { - SOURCES += $$PWD/qxtglobalshortcut_mac.cpp - LIBS += -framework Carbon -} diff --git a/src/app/app.pro b/src/app/app.pro new file mode 100644 index 000000000..e57067898 --- /dev/null +++ b/src/app/app.pro @@ -0,0 +1,38 @@ +include($$ZEAL_COMMON_PRI) + +TEMPLATE = app + +QT += gui widgets sql concurrent + +SOURCES += \ + main.cpp + +RESOURCES += \ + resources/zeal.qrc + +DESTDIR = $$BUILD_ROOT/bin + +unix:!macx { + TARGET = zeal +} + +win32 { + TARGET = zeal + RC_ICONS = resources/zeal.ico +} + +macx { + TARGET = Zeal + ICON = resources/zeal.icns +} + +# Depend on all dependencies of libraries +for(lib_dir, $$list($$files($$SRC_ROOT/src/libs/*))) { + !equals(lib_dir, $$SRC_ROOT/src/libs/libs.pro) { + include($$lib_dir/$$basename(lib_dir).pri) +# LIBS += -l$$ZEAL_LIB_NAME + } +} + +# FIXME: Hardcoded link line & cyclic dependencies. +LIBS += -lUi -lCore -lUi -lRegistry -lUtil diff --git a/src/main.cpp b/src/app/main.cpp similarity index 99% rename from src/main.cpp rename to src/app/main.cpp index feaca9465..b726efa96 100644 --- a/src/main.cpp +++ b/src/app/main.cpp @@ -21,9 +21,9 @@ ** ****************************************************************************/ -#include "core/application.h" -#include "core/localserver.h" -#include "registry/searchquery.h" +#include +#include +#include #include #include diff --git a/src/resources/browser/highlight.css b/src/app/resources/browser/highlight.css similarity index 100% rename from src/resources/browser/highlight.css rename to src/app/resources/browser/highlight.css diff --git a/src/resources/browser/main.css b/src/app/resources/browser/main.css similarity index 100% rename from src/resources/browser/main.css rename to src/app/resources/browser/main.css diff --git a/src/resources/browser/start.html b/src/app/resources/browser/start.html similarity index 100% rename from src/resources/browser/start.html rename to src/app/resources/browser/start.html diff --git a/src/resources/icons/logo/128x128.png b/src/app/resources/icons/logo/128x128.png similarity index 100% rename from src/resources/icons/logo/128x128.png rename to src/app/resources/icons/logo/128x128.png diff --git a/src/resources/icons/logo/64x64.png b/src/app/resources/icons/logo/64x64.png similarity index 100% rename from src/resources/icons/logo/64x64.png rename to src/app/resources/icons/logo/64x64.png diff --git a/src/resources/icons/logo/icon.png b/src/app/resources/icons/logo/icon.png similarity index 100% rename from src/resources/icons/logo/icon.png rename to src/app/resources/icons/logo/icon.png diff --git a/src/resources/icons/logo/icon@2x.png b/src/app/resources/icons/logo/icon@2x.png similarity index 100% rename from src/resources/icons/logo/icon@2x.png rename to src/app/resources/icons/logo/icon@2x.png diff --git a/src/resources/icons/type/Abbreviation.png b/src/app/resources/icons/type/Abbreviation.png similarity index 100% rename from src/resources/icons/type/Abbreviation.png rename to src/app/resources/icons/type/Abbreviation.png diff --git a/src/resources/icons/type/Abbreviation@2x.png b/src/app/resources/icons/type/Abbreviation@2x.png similarity index 100% rename from src/resources/icons/type/Abbreviation@2x.png rename to src/app/resources/icons/type/Abbreviation@2x.png diff --git a/src/resources/icons/type/Alias.png b/src/app/resources/icons/type/Alias.png similarity index 100% rename from src/resources/icons/type/Alias.png rename to src/app/resources/icons/type/Alias.png diff --git a/src/resources/icons/type/Alias@2x.png b/src/app/resources/icons/type/Alias@2x.png similarity index 100% rename from src/resources/icons/type/Alias@2x.png rename to src/app/resources/icons/type/Alias@2x.png diff --git a/src/resources/icons/type/Annotation.png b/src/app/resources/icons/type/Annotation.png similarity index 100% rename from src/resources/icons/type/Annotation.png rename to src/app/resources/icons/type/Annotation.png diff --git a/src/resources/icons/type/Annotation@2x.png b/src/app/resources/icons/type/Annotation@2x.png similarity index 100% rename from src/resources/icons/type/Annotation@2x.png rename to src/app/resources/icons/type/Annotation@2x.png diff --git a/src/resources/icons/type/Attribute.png b/src/app/resources/icons/type/Attribute.png similarity index 100% rename from src/resources/icons/type/Attribute.png rename to src/app/resources/icons/type/Attribute.png diff --git a/src/resources/icons/type/Attribute@2x.png b/src/app/resources/icons/type/Attribute@2x.png similarity index 100% rename from src/resources/icons/type/Attribute@2x.png rename to src/app/resources/icons/type/Attribute@2x.png diff --git a/src/resources/icons/type/Axiom.png b/src/app/resources/icons/type/Axiom.png similarity index 100% rename from src/resources/icons/type/Axiom.png rename to src/app/resources/icons/type/Axiom.png diff --git a/src/resources/icons/type/Axiom@2x.png b/src/app/resources/icons/type/Axiom@2x.png similarity index 100% rename from src/resources/icons/type/Axiom@2x.png rename to src/app/resources/icons/type/Axiom@2x.png diff --git a/src/resources/icons/type/Binding.png b/src/app/resources/icons/type/Binding.png similarity index 100% rename from src/resources/icons/type/Binding.png rename to src/app/resources/icons/type/Binding.png diff --git a/src/resources/icons/type/Binding@2x.png b/src/app/resources/icons/type/Binding@2x.png similarity index 100% rename from src/resources/icons/type/Binding@2x.png rename to src/app/resources/icons/type/Binding@2x.png diff --git a/src/resources/icons/type/Bookmark.png b/src/app/resources/icons/type/Bookmark.png similarity index 100% rename from src/resources/icons/type/Bookmark.png rename to src/app/resources/icons/type/Bookmark.png diff --git a/src/resources/icons/type/Bookmark@2x.png b/src/app/resources/icons/type/Bookmark@2x.png similarity index 100% rename from src/resources/icons/type/Bookmark@2x.png rename to src/app/resources/icons/type/Bookmark@2x.png diff --git a/src/resources/icons/type/Builtin.png b/src/app/resources/icons/type/Builtin.png similarity index 100% rename from src/resources/icons/type/Builtin.png rename to src/app/resources/icons/type/Builtin.png diff --git a/src/resources/icons/type/Builtin@2x.png b/src/app/resources/icons/type/Builtin@2x.png similarity index 100% rename from src/resources/icons/type/Builtin@2x.png rename to src/app/resources/icons/type/Builtin@2x.png diff --git a/src/resources/icons/type/Callback.png b/src/app/resources/icons/type/Callback.png similarity index 100% rename from src/resources/icons/type/Callback.png rename to src/app/resources/icons/type/Callback.png diff --git a/src/resources/icons/type/Callback@2x.png b/src/app/resources/icons/type/Callback@2x.png similarity index 100% rename from src/resources/icons/type/Callback@2x.png rename to src/app/resources/icons/type/Callback@2x.png diff --git a/src/resources/icons/type/Category.png b/src/app/resources/icons/type/Category.png similarity index 100% rename from src/resources/icons/type/Category.png rename to src/app/resources/icons/type/Category.png diff --git a/src/resources/icons/type/Category@2x.png b/src/app/resources/icons/type/Category@2x.png similarity index 100% rename from src/resources/icons/type/Category@2x.png rename to src/app/resources/icons/type/Category@2x.png diff --git a/src/resources/icons/type/Class.png b/src/app/resources/icons/type/Class.png similarity index 100% rename from src/resources/icons/type/Class.png rename to src/app/resources/icons/type/Class.png diff --git a/src/resources/icons/type/Class@2x.png b/src/app/resources/icons/type/Class@2x.png similarity index 100% rename from src/resources/icons/type/Class@2x.png rename to src/app/resources/icons/type/Class@2x.png diff --git a/src/resources/icons/type/Collection.png b/src/app/resources/icons/type/Collection.png similarity index 100% rename from src/resources/icons/type/Collection.png rename to src/app/resources/icons/type/Collection.png diff --git a/src/resources/icons/type/Collection@2x.png b/src/app/resources/icons/type/Collection@2x.png similarity index 100% rename from src/resources/icons/type/Collection@2x.png rename to src/app/resources/icons/type/Collection@2x.png diff --git a/src/resources/icons/type/Column.png b/src/app/resources/icons/type/Column.png similarity index 100% rename from src/resources/icons/type/Column.png rename to src/app/resources/icons/type/Column.png diff --git a/src/resources/icons/type/Column@2x.png b/src/app/resources/icons/type/Column@2x.png similarity index 100% rename from src/resources/icons/type/Column@2x.png rename to src/app/resources/icons/type/Column@2x.png diff --git a/src/resources/icons/type/Command.png b/src/app/resources/icons/type/Command.png similarity index 100% rename from src/resources/icons/type/Command.png rename to src/app/resources/icons/type/Command.png diff --git a/src/resources/icons/type/Command@2x.png b/src/app/resources/icons/type/Command@2x.png similarity index 100% rename from src/resources/icons/type/Command@2x.png rename to src/app/resources/icons/type/Command@2x.png diff --git a/src/resources/icons/type/Component.png b/src/app/resources/icons/type/Component.png similarity index 100% rename from src/resources/icons/type/Component.png rename to src/app/resources/icons/type/Component.png diff --git a/src/resources/icons/type/Component@2x.png b/src/app/resources/icons/type/Component@2x.png similarity index 100% rename from src/resources/icons/type/Component@2x.png rename to src/app/resources/icons/type/Component@2x.png diff --git a/src/resources/icons/type/Constant.png b/src/app/resources/icons/type/Constant.png similarity index 100% rename from src/resources/icons/type/Constant.png rename to src/app/resources/icons/type/Constant.png diff --git a/src/resources/icons/type/Constant@2x.png b/src/app/resources/icons/type/Constant@2x.png similarity index 100% rename from src/resources/icons/type/Constant@2x.png rename to src/app/resources/icons/type/Constant@2x.png diff --git a/src/resources/icons/type/Constructor.png b/src/app/resources/icons/type/Constructor.png similarity index 100% rename from src/resources/icons/type/Constructor.png rename to src/app/resources/icons/type/Constructor.png diff --git a/src/resources/icons/type/Constructor@2x.png b/src/app/resources/icons/type/Constructor@2x.png similarity index 100% rename from src/resources/icons/type/Constructor@2x.png rename to src/app/resources/icons/type/Constructor@2x.png diff --git a/src/resources/icons/type/Conversion.png b/src/app/resources/icons/type/Conversion.png similarity index 100% rename from src/resources/icons/type/Conversion.png rename to src/app/resources/icons/type/Conversion.png diff --git a/src/resources/icons/type/Conversion@2x.png b/src/app/resources/icons/type/Conversion@2x.png similarity index 100% rename from src/resources/icons/type/Conversion@2x.png rename to src/app/resources/icons/type/Conversion@2x.png diff --git a/src/resources/icons/type/Database.png b/src/app/resources/icons/type/Database.png similarity index 100% rename from src/resources/icons/type/Database.png rename to src/app/resources/icons/type/Database.png diff --git a/src/resources/icons/type/Database@2x.png b/src/app/resources/icons/type/Database@2x.png similarity index 100% rename from src/resources/icons/type/Database@2x.png rename to src/app/resources/icons/type/Database@2x.png diff --git a/src/resources/icons/type/Decorator.png b/src/app/resources/icons/type/Decorator.png similarity index 100% rename from src/resources/icons/type/Decorator.png rename to src/app/resources/icons/type/Decorator.png diff --git a/src/resources/icons/type/Decorator@2x.png b/src/app/resources/icons/type/Decorator@2x.png similarity index 100% rename from src/resources/icons/type/Decorator@2x.png rename to src/app/resources/icons/type/Decorator@2x.png diff --git a/src/resources/icons/type/Define.png b/src/app/resources/icons/type/Define.png similarity index 100% rename from src/resources/icons/type/Define.png rename to src/app/resources/icons/type/Define.png diff --git a/src/resources/icons/type/Define@2x.png b/src/app/resources/icons/type/Define@2x.png similarity index 100% rename from src/resources/icons/type/Define@2x.png rename to src/app/resources/icons/type/Define@2x.png diff --git a/src/resources/icons/type/Delegate.png b/src/app/resources/icons/type/Delegate.png similarity index 100% rename from src/resources/icons/type/Delegate.png rename to src/app/resources/icons/type/Delegate.png diff --git a/src/resources/icons/type/Delegate@2x.png b/src/app/resources/icons/type/Delegate@2x.png similarity index 100% rename from src/resources/icons/type/Delegate@2x.png rename to src/app/resources/icons/type/Delegate@2x.png diff --git a/src/resources/icons/type/DeletedSnippet.png b/src/app/resources/icons/type/DeletedSnippet.png similarity index 100% rename from src/resources/icons/type/DeletedSnippet.png rename to src/app/resources/icons/type/DeletedSnippet.png diff --git a/src/resources/icons/type/DeletedSnippet@2x.png b/src/app/resources/icons/type/DeletedSnippet@2x.png similarity index 100% rename from src/resources/icons/type/DeletedSnippet@2x.png rename to src/app/resources/icons/type/DeletedSnippet@2x.png diff --git a/src/resources/icons/type/Diagram.png b/src/app/resources/icons/type/Diagram.png similarity index 100% rename from src/resources/icons/type/Diagram.png rename to src/app/resources/icons/type/Diagram.png diff --git a/src/resources/icons/type/Diagram@2x.png b/src/app/resources/icons/type/Diagram@2x.png similarity index 100% rename from src/resources/icons/type/Diagram@2x.png rename to src/app/resources/icons/type/Diagram@2x.png diff --git a/src/resources/icons/type/Directive.png b/src/app/resources/icons/type/Directive.png similarity index 100% rename from src/resources/icons/type/Directive.png rename to src/app/resources/icons/type/Directive.png diff --git a/src/resources/icons/type/Directive@2x.png b/src/app/resources/icons/type/Directive@2x.png similarity index 100% rename from src/resources/icons/type/Directive@2x.png rename to src/app/resources/icons/type/Directive@2x.png diff --git a/src/resources/icons/type/Element.png b/src/app/resources/icons/type/Element.png similarity index 100% rename from src/resources/icons/type/Element.png rename to src/app/resources/icons/type/Element.png diff --git a/src/resources/icons/type/Element@2x.png b/src/app/resources/icons/type/Element@2x.png similarity index 100% rename from src/resources/icons/type/Element@2x.png rename to src/app/resources/icons/type/Element@2x.png diff --git a/src/resources/icons/type/Entry.png b/src/app/resources/icons/type/Entry.png similarity index 100% rename from src/resources/icons/type/Entry.png rename to src/app/resources/icons/type/Entry.png diff --git a/src/resources/icons/type/Entry@2x.png b/src/app/resources/icons/type/Entry@2x.png similarity index 100% rename from src/resources/icons/type/Entry@2x.png rename to src/app/resources/icons/type/Entry@2x.png diff --git a/src/resources/icons/type/Enumeration.png b/src/app/resources/icons/type/Enumeration.png similarity index 100% rename from src/resources/icons/type/Enumeration.png rename to src/app/resources/icons/type/Enumeration.png diff --git a/src/resources/icons/type/Enumeration@2x.png b/src/app/resources/icons/type/Enumeration@2x.png similarity index 100% rename from src/resources/icons/type/Enumeration@2x.png rename to src/app/resources/icons/type/Enumeration@2x.png diff --git a/src/resources/icons/type/Environment.png b/src/app/resources/icons/type/Environment.png similarity index 100% rename from src/resources/icons/type/Environment.png rename to src/app/resources/icons/type/Environment.png diff --git a/src/resources/icons/type/Environment@2x.png b/src/app/resources/icons/type/Environment@2x.png similarity index 100% rename from src/resources/icons/type/Environment@2x.png rename to src/app/resources/icons/type/Environment@2x.png diff --git a/src/resources/icons/type/Error.png b/src/app/resources/icons/type/Error.png similarity index 100% rename from src/resources/icons/type/Error.png rename to src/app/resources/icons/type/Error.png diff --git a/src/resources/icons/type/Error@2x.png b/src/app/resources/icons/type/Error@2x.png similarity index 100% rename from src/resources/icons/type/Error@2x.png rename to src/app/resources/icons/type/Error@2x.png diff --git a/src/resources/icons/type/Event.png b/src/app/resources/icons/type/Event.png similarity index 100% rename from src/resources/icons/type/Event.png rename to src/app/resources/icons/type/Event.png diff --git a/src/resources/icons/type/Event@2x.png b/src/app/resources/icons/type/Event@2x.png similarity index 100% rename from src/resources/icons/type/Event@2x.png rename to src/app/resources/icons/type/Event@2x.png diff --git a/src/resources/icons/type/Exception.png b/src/app/resources/icons/type/Exception.png similarity index 100% rename from src/resources/icons/type/Exception.png rename to src/app/resources/icons/type/Exception.png diff --git a/src/resources/icons/type/Exception@2x.png b/src/app/resources/icons/type/Exception@2x.png similarity index 100% rename from src/resources/icons/type/Exception@2x.png rename to src/app/resources/icons/type/Exception@2x.png diff --git a/src/resources/icons/type/Extension.png b/src/app/resources/icons/type/Extension.png similarity index 100% rename from src/resources/icons/type/Extension.png rename to src/app/resources/icons/type/Extension.png diff --git a/src/resources/icons/type/Extension@2x.png b/src/app/resources/icons/type/Extension@2x.png similarity index 100% rename from src/resources/icons/type/Extension@2x.png rename to src/app/resources/icons/type/Extension@2x.png diff --git a/src/resources/icons/type/Field.png b/src/app/resources/icons/type/Field.png similarity index 100% rename from src/resources/icons/type/Field.png rename to src/app/resources/icons/type/Field.png diff --git a/src/resources/icons/type/Field@2x.png b/src/app/resources/icons/type/Field@2x.png similarity index 100% rename from src/resources/icons/type/Field@2x.png rename to src/app/resources/icons/type/Field@2x.png diff --git a/src/resources/icons/type/File.png b/src/app/resources/icons/type/File.png similarity index 100% rename from src/resources/icons/type/File.png rename to src/app/resources/icons/type/File.png diff --git a/src/resources/icons/type/File@2x.png b/src/app/resources/icons/type/File@2x.png similarity index 100% rename from src/resources/icons/type/File@2x.png rename to src/app/resources/icons/type/File@2x.png diff --git a/src/resources/icons/type/Filter.png b/src/app/resources/icons/type/Filter.png similarity index 100% rename from src/resources/icons/type/Filter.png rename to src/app/resources/icons/type/Filter.png diff --git a/src/resources/icons/type/Filter@2x.png b/src/app/resources/icons/type/Filter@2x.png similarity index 100% rename from src/resources/icons/type/Filter@2x.png rename to src/app/resources/icons/type/Filter@2x.png diff --git a/src/resources/icons/type/Foreign Key.png b/src/app/resources/icons/type/Foreign Key.png similarity index 100% rename from src/resources/icons/type/Foreign Key.png rename to src/app/resources/icons/type/Foreign Key.png diff --git a/src/resources/icons/type/Foreign Key@2x.png b/src/app/resources/icons/type/Foreign Key@2x.png similarity index 100% rename from src/resources/icons/type/Foreign Key@2x.png rename to src/app/resources/icons/type/Foreign Key@2x.png diff --git a/src/resources/icons/type/Framework.png b/src/app/resources/icons/type/Framework.png similarity index 100% rename from src/resources/icons/type/Framework.png rename to src/app/resources/icons/type/Framework.png diff --git a/src/resources/icons/type/Framework@2x.png b/src/app/resources/icons/type/Framework@2x.png similarity index 100% rename from src/resources/icons/type/Framework@2x.png rename to src/app/resources/icons/type/Framework@2x.png diff --git a/src/resources/icons/type/Function.png b/src/app/resources/icons/type/Function.png similarity index 100% rename from src/resources/icons/type/Function.png rename to src/app/resources/icons/type/Function.png diff --git a/src/resources/icons/type/Function@2x.png b/src/app/resources/icons/type/Function@2x.png similarity index 100% rename from src/resources/icons/type/Function@2x.png rename to src/app/resources/icons/type/Function@2x.png diff --git a/src/resources/icons/type/Global.png b/src/app/resources/icons/type/Global.png similarity index 100% rename from src/resources/icons/type/Global.png rename to src/app/resources/icons/type/Global.png diff --git a/src/resources/icons/type/Global@2x.png b/src/app/resources/icons/type/Global@2x.png similarity index 100% rename from src/resources/icons/type/Global@2x.png rename to src/app/resources/icons/type/Global@2x.png diff --git a/src/resources/icons/type/Guide.png b/src/app/resources/icons/type/Guide.png similarity index 100% rename from src/resources/icons/type/Guide.png rename to src/app/resources/icons/type/Guide.png diff --git a/src/resources/icons/type/Guide@2x.png b/src/app/resources/icons/type/Guide@2x.png similarity index 100% rename from src/resources/icons/type/Guide@2x.png rename to src/app/resources/icons/type/Guide@2x.png diff --git a/src/resources/icons/type/Helper.png b/src/app/resources/icons/type/Helper.png similarity index 100% rename from src/resources/icons/type/Helper.png rename to src/app/resources/icons/type/Helper.png diff --git a/src/resources/icons/type/Helper@2x.png b/src/app/resources/icons/type/Helper@2x.png similarity index 100% rename from src/resources/icons/type/Helper@2x.png rename to src/app/resources/icons/type/Helper@2x.png diff --git a/src/resources/icons/type/Hook.png b/src/app/resources/icons/type/Hook.png similarity index 100% rename from src/resources/icons/type/Hook.png rename to src/app/resources/icons/type/Hook.png diff --git a/src/resources/icons/type/Hook@2x.png b/src/app/resources/icons/type/Hook@2x.png similarity index 100% rename from src/resources/icons/type/Hook@2x.png rename to src/app/resources/icons/type/Hook@2x.png diff --git a/src/resources/icons/type/Index.png b/src/app/resources/icons/type/Index.png similarity index 100% rename from src/resources/icons/type/Index.png rename to src/app/resources/icons/type/Index.png diff --git a/src/resources/icons/type/Index@2x.png b/src/app/resources/icons/type/Index@2x.png similarity index 100% rename from src/resources/icons/type/Index@2x.png rename to src/app/resources/icons/type/Index@2x.png diff --git a/src/resources/icons/type/Indirection.png b/src/app/resources/icons/type/Indirection.png similarity index 100% rename from src/resources/icons/type/Indirection.png rename to src/app/resources/icons/type/Indirection.png diff --git a/src/resources/icons/type/Indirection@2x.png b/src/app/resources/icons/type/Indirection@2x.png similarity index 100% rename from src/resources/icons/type/Indirection@2x.png rename to src/app/resources/icons/type/Indirection@2x.png diff --git a/src/resources/icons/type/Inductive.png b/src/app/resources/icons/type/Inductive.png similarity index 100% rename from src/resources/icons/type/Inductive.png rename to src/app/resources/icons/type/Inductive.png diff --git a/src/resources/icons/type/Inductive@2x.png b/src/app/resources/icons/type/Inductive@2x.png similarity index 100% rename from src/resources/icons/type/Inductive@2x.png rename to src/app/resources/icons/type/Inductive@2x.png diff --git a/src/resources/icons/type/Instance.png b/src/app/resources/icons/type/Instance.png similarity index 100% rename from src/resources/icons/type/Instance.png rename to src/app/resources/icons/type/Instance.png diff --git a/src/resources/icons/type/Instance@2x.png b/src/app/resources/icons/type/Instance@2x.png similarity index 100% rename from src/resources/icons/type/Instance@2x.png rename to src/app/resources/icons/type/Instance@2x.png diff --git a/src/resources/icons/type/Instruction.png b/src/app/resources/icons/type/Instruction.png similarity index 100% rename from src/resources/icons/type/Instruction.png rename to src/app/resources/icons/type/Instruction.png diff --git a/src/resources/icons/type/Instruction@2x.png b/src/app/resources/icons/type/Instruction@2x.png similarity index 100% rename from src/resources/icons/type/Instruction@2x.png rename to src/app/resources/icons/type/Instruction@2x.png diff --git a/src/resources/icons/type/Interface.png b/src/app/resources/icons/type/Interface.png similarity index 100% rename from src/resources/icons/type/Interface.png rename to src/app/resources/icons/type/Interface.png diff --git a/src/resources/icons/type/Interface@2x.png b/src/app/resources/icons/type/Interface@2x.png similarity index 100% rename from src/resources/icons/type/Interface@2x.png rename to src/app/resources/icons/type/Interface@2x.png diff --git a/src/resources/icons/type/Keyword.png b/src/app/resources/icons/type/Keyword.png similarity index 100% rename from src/resources/icons/type/Keyword.png rename to src/app/resources/icons/type/Keyword.png diff --git a/src/resources/icons/type/Keyword@2x.png b/src/app/resources/icons/type/Keyword@2x.png similarity index 100% rename from src/resources/icons/type/Keyword@2x.png rename to src/app/resources/icons/type/Keyword@2x.png diff --git a/src/resources/icons/type/Lemma.png b/src/app/resources/icons/type/Lemma.png similarity index 100% rename from src/resources/icons/type/Lemma.png rename to src/app/resources/icons/type/Lemma.png diff --git a/src/resources/icons/type/Lemma@2x.png b/src/app/resources/icons/type/Lemma@2x.png similarity index 100% rename from src/resources/icons/type/Lemma@2x.png rename to src/app/resources/icons/type/Lemma@2x.png diff --git a/src/resources/icons/type/Library.png b/src/app/resources/icons/type/Library.png similarity index 100% rename from src/resources/icons/type/Library.png rename to src/app/resources/icons/type/Library.png diff --git a/src/resources/icons/type/Library@2x.png b/src/app/resources/icons/type/Library@2x.png similarity index 100% rename from src/resources/icons/type/Library@2x.png rename to src/app/resources/icons/type/Library@2x.png diff --git a/src/resources/icons/type/Literal.png b/src/app/resources/icons/type/Literal.png similarity index 100% rename from src/resources/icons/type/Literal.png rename to src/app/resources/icons/type/Literal.png diff --git a/src/resources/icons/type/Literal@2x.png b/src/app/resources/icons/type/Literal@2x.png similarity index 100% rename from src/resources/icons/type/Literal@2x.png rename to src/app/resources/icons/type/Literal@2x.png diff --git a/src/resources/icons/type/Macro.png b/src/app/resources/icons/type/Macro.png similarity index 100% rename from src/resources/icons/type/Macro.png rename to src/app/resources/icons/type/Macro.png diff --git a/src/resources/icons/type/Macro@2x.png b/src/app/resources/icons/type/Macro@2x.png similarity index 100% rename from src/resources/icons/type/Macro@2x.png rename to src/app/resources/icons/type/Macro@2x.png diff --git a/src/resources/icons/type/Method.png b/src/app/resources/icons/type/Method.png similarity index 100% rename from src/resources/icons/type/Method.png rename to src/app/resources/icons/type/Method.png diff --git a/src/resources/icons/type/Method@2x.png b/src/app/resources/icons/type/Method@2x.png similarity index 100% rename from src/resources/icons/type/Method@2x.png rename to src/app/resources/icons/type/Method@2x.png diff --git a/src/resources/icons/type/Mixin.png b/src/app/resources/icons/type/Mixin.png similarity index 100% rename from src/resources/icons/type/Mixin.png rename to src/app/resources/icons/type/Mixin.png diff --git a/src/resources/icons/type/Mixin@2x.png b/src/app/resources/icons/type/Mixin@2x.png similarity index 100% rename from src/resources/icons/type/Mixin@2x.png rename to src/app/resources/icons/type/Mixin@2x.png diff --git a/src/resources/icons/type/Modifier.png b/src/app/resources/icons/type/Modifier.png similarity index 100% rename from src/resources/icons/type/Modifier.png rename to src/app/resources/icons/type/Modifier.png diff --git a/src/resources/icons/type/Modifier@2x.png b/src/app/resources/icons/type/Modifier@2x.png similarity index 100% rename from src/resources/icons/type/Modifier@2x.png rename to src/app/resources/icons/type/Modifier@2x.png diff --git a/src/resources/icons/type/Module.png b/src/app/resources/icons/type/Module.png similarity index 100% rename from src/resources/icons/type/Module.png rename to src/app/resources/icons/type/Module.png diff --git a/src/resources/icons/type/Module@2x.png b/src/app/resources/icons/type/Module@2x.png similarity index 100% rename from src/resources/icons/type/Module@2x.png rename to src/app/resources/icons/type/Module@2x.png diff --git a/src/resources/icons/type/Namespace.png b/src/app/resources/icons/type/Namespace.png similarity index 100% rename from src/resources/icons/type/Namespace.png rename to src/app/resources/icons/type/Namespace.png diff --git a/src/resources/icons/type/Namespace@2x.png b/src/app/resources/icons/type/Namespace@2x.png similarity index 100% rename from src/resources/icons/type/Namespace@2x.png rename to src/app/resources/icons/type/Namespace@2x.png diff --git a/src/resources/icons/type/NewSnippet.png b/src/app/resources/icons/type/NewSnippet.png similarity index 100% rename from src/resources/icons/type/NewSnippet.png rename to src/app/resources/icons/type/NewSnippet.png diff --git a/src/resources/icons/type/NewSnippet@2x.png b/src/app/resources/icons/type/NewSnippet@2x.png similarity index 100% rename from src/resources/icons/type/NewSnippet@2x.png rename to src/app/resources/icons/type/NewSnippet@2x.png diff --git a/src/resources/icons/type/Notation.png b/src/app/resources/icons/type/Notation.png similarity index 100% rename from src/resources/icons/type/Notation.png rename to src/app/resources/icons/type/Notation.png diff --git a/src/resources/icons/type/Notation@2x.png b/src/app/resources/icons/type/Notation@2x.png similarity index 100% rename from src/resources/icons/type/Notation@2x.png rename to src/app/resources/icons/type/Notation@2x.png diff --git a/src/resources/icons/type/Object.png b/src/app/resources/icons/type/Object.png similarity index 100% rename from src/resources/icons/type/Object.png rename to src/app/resources/icons/type/Object.png diff --git a/src/resources/icons/type/Object@2x.png b/src/app/resources/icons/type/Object@2x.png similarity index 100% rename from src/resources/icons/type/Object@2x.png rename to src/app/resources/icons/type/Object@2x.png diff --git a/src/resources/icons/type/Operator.png b/src/app/resources/icons/type/Operator.png similarity index 100% rename from src/resources/icons/type/Operator.png rename to src/app/resources/icons/type/Operator.png diff --git a/src/resources/icons/type/Operator@2x.png b/src/app/resources/icons/type/Operator@2x.png similarity index 100% rename from src/resources/icons/type/Operator@2x.png rename to src/app/resources/icons/type/Operator@2x.png diff --git a/src/resources/icons/type/Option.png b/src/app/resources/icons/type/Option.png similarity index 100% rename from src/resources/icons/type/Option.png rename to src/app/resources/icons/type/Option.png diff --git a/src/resources/icons/type/Option@2x.png b/src/app/resources/icons/type/Option@2x.png similarity index 100% rename from src/resources/icons/type/Option@2x.png rename to src/app/resources/icons/type/Option@2x.png diff --git a/src/resources/icons/type/Package.png b/src/app/resources/icons/type/Package.png similarity index 100% rename from src/resources/icons/type/Package.png rename to src/app/resources/icons/type/Package.png diff --git a/src/resources/icons/type/Package@2x.png b/src/app/resources/icons/type/Package@2x.png similarity index 100% rename from src/resources/icons/type/Package@2x.png rename to src/app/resources/icons/type/Package@2x.png diff --git a/src/resources/icons/type/Parameter.png b/src/app/resources/icons/type/Parameter.png similarity index 100% rename from src/resources/icons/type/Parameter.png rename to src/app/resources/icons/type/Parameter.png diff --git a/src/resources/icons/type/Parameter@2x.png b/src/app/resources/icons/type/Parameter@2x.png similarity index 100% rename from src/resources/icons/type/Parameter@2x.png rename to src/app/resources/icons/type/Parameter@2x.png diff --git a/src/resources/icons/type/Pattern.png b/src/app/resources/icons/type/Pattern.png similarity index 100% rename from src/resources/icons/type/Pattern.png rename to src/app/resources/icons/type/Pattern.png diff --git a/src/resources/icons/type/Pattern@2x.png b/src/app/resources/icons/type/Pattern@2x.png similarity index 100% rename from src/resources/icons/type/Pattern@2x.png rename to src/app/resources/icons/type/Pattern@2x.png diff --git a/src/resources/icons/type/Plugin.png b/src/app/resources/icons/type/Plugin.png similarity index 100% rename from src/resources/icons/type/Plugin.png rename to src/app/resources/icons/type/Plugin.png diff --git a/src/resources/icons/type/Plugin@2x.png b/src/app/resources/icons/type/Plugin@2x.png similarity index 100% rename from src/resources/icons/type/Plugin@2x.png rename to src/app/resources/icons/type/Plugin@2x.png diff --git a/src/resources/icons/type/Procedure.png b/src/app/resources/icons/type/Procedure.png similarity index 100% rename from src/resources/icons/type/Procedure.png rename to src/app/resources/icons/type/Procedure.png diff --git a/src/resources/icons/type/Procedure@2x.png b/src/app/resources/icons/type/Procedure@2x.png similarity index 100% rename from src/resources/icons/type/Procedure@2x.png rename to src/app/resources/icons/type/Procedure@2x.png diff --git a/src/resources/icons/type/Projection.png b/src/app/resources/icons/type/Projection.png similarity index 100% rename from src/resources/icons/type/Projection.png rename to src/app/resources/icons/type/Projection.png diff --git a/src/resources/icons/type/Projection@2x.png b/src/app/resources/icons/type/Projection@2x.png similarity index 100% rename from src/resources/icons/type/Projection@2x.png rename to src/app/resources/icons/type/Projection@2x.png diff --git a/src/resources/icons/type/Property.png b/src/app/resources/icons/type/Property.png similarity index 100% rename from src/resources/icons/type/Property.png rename to src/app/resources/icons/type/Property.png diff --git a/src/resources/icons/type/Property@2x.png b/src/app/resources/icons/type/Property@2x.png similarity index 100% rename from src/resources/icons/type/Property@2x.png rename to src/app/resources/icons/type/Property@2x.png diff --git a/src/resources/icons/type/Protocol.png b/src/app/resources/icons/type/Protocol.png similarity index 100% rename from src/resources/icons/type/Protocol.png rename to src/app/resources/icons/type/Protocol.png diff --git a/src/resources/icons/type/Protocol@2x.png b/src/app/resources/icons/type/Protocol@2x.png similarity index 100% rename from src/resources/icons/type/Protocol@2x.png rename to src/app/resources/icons/type/Protocol@2x.png diff --git a/src/resources/icons/type/Provider.png b/src/app/resources/icons/type/Provider.png similarity index 100% rename from src/resources/icons/type/Provider.png rename to src/app/resources/icons/type/Provider.png diff --git a/src/resources/icons/type/Provider@2x.png b/src/app/resources/icons/type/Provider@2x.png similarity index 100% rename from src/resources/icons/type/Provider@2x.png rename to src/app/resources/icons/type/Provider@2x.png diff --git a/src/resources/icons/type/Provisioner.png b/src/app/resources/icons/type/Provisioner.png similarity index 100% rename from src/resources/icons/type/Provisioner.png rename to src/app/resources/icons/type/Provisioner.png diff --git a/src/resources/icons/type/Provisioner@2x.png b/src/app/resources/icons/type/Provisioner@2x.png similarity index 100% rename from src/resources/icons/type/Provisioner@2x.png rename to src/app/resources/icons/type/Provisioner@2x.png diff --git a/src/resources/icons/type/Query.png b/src/app/resources/icons/type/Query.png similarity index 100% rename from src/resources/icons/type/Query.png rename to src/app/resources/icons/type/Query.png diff --git a/src/resources/icons/type/Query@2x.png b/src/app/resources/icons/type/Query@2x.png similarity index 100% rename from src/resources/icons/type/Query@2x.png rename to src/app/resources/icons/type/Query@2x.png diff --git a/src/resources/icons/type/Record.png b/src/app/resources/icons/type/Record.png similarity index 100% rename from src/resources/icons/type/Record.png rename to src/app/resources/icons/type/Record.png diff --git a/src/resources/icons/type/Record@2x.png b/src/app/resources/icons/type/Record@2x.png similarity index 100% rename from src/resources/icons/type/Record@2x.png rename to src/app/resources/icons/type/Record@2x.png diff --git a/src/resources/icons/type/Relationship.png b/src/app/resources/icons/type/Relationship.png similarity index 100% rename from src/resources/icons/type/Relationship.png rename to src/app/resources/icons/type/Relationship.png diff --git a/src/resources/icons/type/Relationship@2x.png b/src/app/resources/icons/type/Relationship@2x.png similarity index 100% rename from src/resources/icons/type/Relationship@2x.png rename to src/app/resources/icons/type/Relationship@2x.png diff --git a/src/resources/icons/type/Report.png b/src/app/resources/icons/type/Report.png similarity index 100% rename from src/resources/icons/type/Report.png rename to src/app/resources/icons/type/Report.png diff --git a/src/resources/icons/type/Report@2x.png b/src/app/resources/icons/type/Report@2x.png similarity index 100% rename from src/resources/icons/type/Report@2x.png rename to src/app/resources/icons/type/Report@2x.png diff --git a/src/resources/icons/type/Request.png b/src/app/resources/icons/type/Request.png similarity index 100% rename from src/resources/icons/type/Request.png rename to src/app/resources/icons/type/Request.png diff --git a/src/resources/icons/type/Request@2x.png b/src/app/resources/icons/type/Request@2x.png similarity index 100% rename from src/resources/icons/type/Request@2x.png rename to src/app/resources/icons/type/Request@2x.png diff --git a/src/resources/icons/type/Resource.png b/src/app/resources/icons/type/Resource.png similarity index 100% rename from src/resources/icons/type/Resource.png rename to src/app/resources/icons/type/Resource.png diff --git a/src/resources/icons/type/Resource@2x.png b/src/app/resources/icons/type/Resource@2x.png similarity index 100% rename from src/resources/icons/type/Resource@2x.png rename to src/app/resources/icons/type/Resource@2x.png diff --git a/src/resources/icons/type/Sample.png b/src/app/resources/icons/type/Sample.png similarity index 100% rename from src/resources/icons/type/Sample.png rename to src/app/resources/icons/type/Sample.png diff --git a/src/resources/icons/type/Sample@2x.png b/src/app/resources/icons/type/Sample@2x.png similarity index 100% rename from src/resources/icons/type/Sample@2x.png rename to src/app/resources/icons/type/Sample@2x.png diff --git a/src/resources/icons/type/Schema.png b/src/app/resources/icons/type/Schema.png similarity index 100% rename from src/resources/icons/type/Schema.png rename to src/app/resources/icons/type/Schema.png diff --git a/src/resources/icons/type/Schema@2x.png b/src/app/resources/icons/type/Schema@2x.png similarity index 100% rename from src/resources/icons/type/Schema@2x.png rename to src/app/resources/icons/type/Schema@2x.png diff --git a/src/resources/icons/type/Script.png b/src/app/resources/icons/type/Script.png similarity index 100% rename from src/resources/icons/type/Script.png rename to src/app/resources/icons/type/Script.png diff --git a/src/resources/icons/type/Script@2x.png b/src/app/resources/icons/type/Script@2x.png similarity index 100% rename from src/resources/icons/type/Script@2x.png rename to src/app/resources/icons/type/Script@2x.png diff --git a/src/resources/icons/type/Section.png b/src/app/resources/icons/type/Section.png similarity index 100% rename from src/resources/icons/type/Section.png rename to src/app/resources/icons/type/Section.png diff --git a/src/resources/icons/type/Section@2x.png b/src/app/resources/icons/type/Section@2x.png similarity index 100% rename from src/resources/icons/type/Section@2x.png rename to src/app/resources/icons/type/Section@2x.png diff --git a/src/resources/icons/type/Service.png b/src/app/resources/icons/type/Service.png similarity index 100% rename from src/resources/icons/type/Service.png rename to src/app/resources/icons/type/Service.png diff --git a/src/resources/icons/type/Service@2x.png b/src/app/resources/icons/type/Service@2x.png similarity index 100% rename from src/resources/icons/type/Service@2x.png rename to src/app/resources/icons/type/Service@2x.png diff --git a/src/resources/icons/type/Setting.png b/src/app/resources/icons/type/Setting.png similarity index 100% rename from src/resources/icons/type/Setting.png rename to src/app/resources/icons/type/Setting.png diff --git a/src/resources/icons/type/Setting@2x.png b/src/app/resources/icons/type/Setting@2x.png similarity index 100% rename from src/resources/icons/type/Setting@2x.png rename to src/app/resources/icons/type/Setting@2x.png diff --git a/src/resources/icons/type/Shortcut.png b/src/app/resources/icons/type/Shortcut.png similarity index 100% rename from src/resources/icons/type/Shortcut.png rename to src/app/resources/icons/type/Shortcut.png diff --git a/src/resources/icons/type/Shortcut@2x.png b/src/app/resources/icons/type/Shortcut@2x.png similarity index 100% rename from src/resources/icons/type/Shortcut@2x.png rename to src/app/resources/icons/type/Shortcut@2x.png diff --git a/src/resources/icons/type/Signature.png b/src/app/resources/icons/type/Signature.png similarity index 100% rename from src/resources/icons/type/Signature.png rename to src/app/resources/icons/type/Signature.png diff --git a/src/resources/icons/type/Signature@2x.png b/src/app/resources/icons/type/Signature@2x.png similarity index 100% rename from src/resources/icons/type/Signature@2x.png rename to src/app/resources/icons/type/Signature@2x.png diff --git a/src/resources/icons/type/Snippet.png b/src/app/resources/icons/type/Snippet.png similarity index 100% rename from src/resources/icons/type/Snippet.png rename to src/app/resources/icons/type/Snippet.png diff --git a/src/resources/icons/type/Snippet@2x.png b/src/app/resources/icons/type/Snippet@2x.png similarity index 100% rename from src/resources/icons/type/Snippet@2x.png rename to src/app/resources/icons/type/Snippet@2x.png diff --git a/src/resources/icons/type/Special Form.png b/src/app/resources/icons/type/Special Form.png similarity index 100% rename from src/resources/icons/type/Special Form.png rename to src/app/resources/icons/type/Special Form.png diff --git a/src/resources/icons/type/Special Form@2x.png b/src/app/resources/icons/type/Special Form@2x.png similarity index 100% rename from src/resources/icons/type/Special Form@2x.png rename to src/app/resources/icons/type/Special Form@2x.png diff --git a/src/resources/icons/type/Statement.png b/src/app/resources/icons/type/Statement.png similarity index 100% rename from src/resources/icons/type/Statement.png rename to src/app/resources/icons/type/Statement.png diff --git a/src/resources/icons/type/Statement@2x.png b/src/app/resources/icons/type/Statement@2x.png similarity index 100% rename from src/resources/icons/type/Statement@2x.png rename to src/app/resources/icons/type/Statement@2x.png diff --git a/src/resources/icons/type/Structure.png b/src/app/resources/icons/type/Structure.png similarity index 100% rename from src/resources/icons/type/Structure.png rename to src/app/resources/icons/type/Structure.png diff --git a/src/resources/icons/type/Structure@2x.png b/src/app/resources/icons/type/Structure@2x.png similarity index 100% rename from src/resources/icons/type/Structure@2x.png rename to src/app/resources/icons/type/Structure@2x.png diff --git a/src/resources/icons/type/Style.png b/src/app/resources/icons/type/Style.png similarity index 100% rename from src/resources/icons/type/Style.png rename to src/app/resources/icons/type/Style.png diff --git a/src/resources/icons/type/Style@2x.png b/src/app/resources/icons/type/Style@2x.png similarity index 100% rename from src/resources/icons/type/Style@2x.png rename to src/app/resources/icons/type/Style@2x.png diff --git a/src/resources/icons/type/Subroutine.png b/src/app/resources/icons/type/Subroutine.png similarity index 100% rename from src/resources/icons/type/Subroutine.png rename to src/app/resources/icons/type/Subroutine.png diff --git a/src/resources/icons/type/Subroutine@2x.png b/src/app/resources/icons/type/Subroutine@2x.png similarity index 100% rename from src/resources/icons/type/Subroutine@2x.png rename to src/app/resources/icons/type/Subroutine@2x.png diff --git a/src/resources/icons/type/Syntax.png b/src/app/resources/icons/type/Syntax.png similarity index 100% rename from src/resources/icons/type/Syntax.png rename to src/app/resources/icons/type/Syntax.png diff --git a/src/resources/icons/type/Syntax@2x.png b/src/app/resources/icons/type/Syntax@2x.png similarity index 100% rename from src/resources/icons/type/Syntax@2x.png rename to src/app/resources/icons/type/Syntax@2x.png diff --git a/src/resources/icons/type/Table.png b/src/app/resources/icons/type/Table.png similarity index 100% rename from src/resources/icons/type/Table.png rename to src/app/resources/icons/type/Table.png diff --git a/src/resources/icons/type/Table@2x.png b/src/app/resources/icons/type/Table@2x.png similarity index 100% rename from src/resources/icons/type/Table@2x.png rename to src/app/resources/icons/type/Table@2x.png diff --git a/src/resources/icons/type/Tactic.png b/src/app/resources/icons/type/Tactic.png similarity index 100% rename from src/resources/icons/type/Tactic.png rename to src/app/resources/icons/type/Tactic.png diff --git a/src/resources/icons/type/Tactic@2x.png b/src/app/resources/icons/type/Tactic@2x.png similarity index 100% rename from src/resources/icons/type/Tactic@2x.png rename to src/app/resources/icons/type/Tactic@2x.png diff --git a/src/resources/icons/type/Tag.png b/src/app/resources/icons/type/Tag.png similarity index 100% rename from src/resources/icons/type/Tag.png rename to src/app/resources/icons/type/Tag.png diff --git a/src/resources/icons/type/Tag@2x.png b/src/app/resources/icons/type/Tag@2x.png similarity index 100% rename from src/resources/icons/type/Tag@2x.png rename to src/app/resources/icons/type/Tag@2x.png diff --git a/src/resources/icons/type/Test.png b/src/app/resources/icons/type/Test.png similarity index 100% rename from src/resources/icons/type/Test.png rename to src/app/resources/icons/type/Test.png diff --git a/src/resources/icons/type/Test@2x.png b/src/app/resources/icons/type/Test@2x.png similarity index 100% rename from src/resources/icons/type/Test@2x.png rename to src/app/resources/icons/type/Test@2x.png diff --git a/src/resources/icons/type/Trait.png b/src/app/resources/icons/type/Trait.png similarity index 100% rename from src/resources/icons/type/Trait.png rename to src/app/resources/icons/type/Trait.png diff --git a/src/resources/icons/type/Trait@2x.png b/src/app/resources/icons/type/Trait@2x.png similarity index 100% rename from src/resources/icons/type/Trait@2x.png rename to src/app/resources/icons/type/Trait@2x.png diff --git a/src/resources/icons/type/Trigger.png b/src/app/resources/icons/type/Trigger.png similarity index 100% rename from src/resources/icons/type/Trigger.png rename to src/app/resources/icons/type/Trigger.png diff --git a/src/resources/icons/type/Trigger@2x.png b/src/app/resources/icons/type/Trigger@2x.png similarity index 100% rename from src/resources/icons/type/Trigger@2x.png rename to src/app/resources/icons/type/Trigger@2x.png diff --git a/src/resources/icons/type/Type.png b/src/app/resources/icons/type/Type.png similarity index 100% rename from src/resources/icons/type/Type.png rename to src/app/resources/icons/type/Type.png diff --git a/src/resources/icons/type/Type@2x.png b/src/app/resources/icons/type/Type@2x.png similarity index 100% rename from src/resources/icons/type/Type@2x.png rename to src/app/resources/icons/type/Type@2x.png diff --git a/src/resources/icons/type/Union.png b/src/app/resources/icons/type/Union.png similarity index 100% rename from src/resources/icons/type/Union.png rename to src/app/resources/icons/type/Union.png diff --git a/src/resources/icons/type/Union@2x.png b/src/app/resources/icons/type/Union@2x.png similarity index 100% rename from src/resources/icons/type/Union@2x.png rename to src/app/resources/icons/type/Union@2x.png diff --git a/src/resources/icons/type/Unknown.png b/src/app/resources/icons/type/Unknown.png similarity index 100% rename from src/resources/icons/type/Unknown.png rename to src/app/resources/icons/type/Unknown.png diff --git a/src/resources/icons/type/Unknown@2x.png b/src/app/resources/icons/type/Unknown@2x.png similarity index 100% rename from src/resources/icons/type/Unknown@2x.png rename to src/app/resources/icons/type/Unknown@2x.png diff --git a/src/resources/icons/type/Value.png b/src/app/resources/icons/type/Value.png similarity index 100% rename from src/resources/icons/type/Value.png rename to src/app/resources/icons/type/Value.png diff --git a/src/resources/icons/type/Value@2x.png b/src/app/resources/icons/type/Value@2x.png similarity index 100% rename from src/resources/icons/type/Value@2x.png rename to src/app/resources/icons/type/Value@2x.png diff --git a/src/resources/icons/type/Variable.png b/src/app/resources/icons/type/Variable.png similarity index 100% rename from src/resources/icons/type/Variable.png rename to src/app/resources/icons/type/Variable.png diff --git a/src/resources/icons/type/Variable@2x.png b/src/app/resources/icons/type/Variable@2x.png similarity index 100% rename from src/resources/icons/type/Variable@2x.png rename to src/app/resources/icons/type/Variable@2x.png diff --git a/src/resources/icons/type/Variant.png b/src/app/resources/icons/type/Variant.png similarity index 100% rename from src/resources/icons/type/Variant.png rename to src/app/resources/icons/type/Variant.png diff --git a/src/resources/icons/type/Variant@2x.png b/src/app/resources/icons/type/Variant@2x.png similarity index 100% rename from src/resources/icons/type/Variant@2x.png rename to src/app/resources/icons/type/Variant@2x.png diff --git a/src/resources/icons/type/View.png b/src/app/resources/icons/type/View.png similarity index 100% rename from src/resources/icons/type/View.png rename to src/app/resources/icons/type/View.png diff --git a/src/resources/icons/type/View@2x.png b/src/app/resources/icons/type/View@2x.png similarity index 100% rename from src/resources/icons/type/View@2x.png rename to src/app/resources/icons/type/View@2x.png diff --git a/src/resources/icons/type/Web.png b/src/app/resources/icons/type/Web.png similarity index 100% rename from src/resources/icons/type/Web.png rename to src/app/resources/icons/type/Web.png diff --git a/src/resources/icons/type/Web@2x.png b/src/app/resources/icons/type/Web@2x.png similarity index 100% rename from src/resources/icons/type/Web@2x.png rename to src/app/resources/icons/type/Web@2x.png diff --git a/src/resources/icons/type/Word.png b/src/app/resources/icons/type/Word.png similarity index 100% rename from src/resources/icons/type/Word.png rename to src/app/resources/icons/type/Word.png diff --git a/src/resources/icons/type/Word@2x.png b/src/app/resources/icons/type/Word@2x.png similarity index 100% rename from src/resources/icons/type/Word@2x.png rename to src/app/resources/icons/type/Word@2x.png diff --git a/src/resources/icons/type/_DashAnnotations.png b/src/app/resources/icons/type/_DashAnnotations.png similarity index 100% rename from src/resources/icons/type/_DashAnnotations.png rename to src/app/resources/icons/type/_DashAnnotations.png diff --git a/src/resources/icons/type/_DashAnnotations@2x.png b/src/app/resources/icons/type/_DashAnnotations@2x.png similarity index 100% rename from src/resources/icons/type/_DashAnnotations@2x.png rename to src/app/resources/icons/type/_DashAnnotations@2x.png diff --git a/src/resources/icons/type/_Struct.png b/src/app/resources/icons/type/_Struct.png similarity index 100% rename from src/resources/icons/type/_Struct.png rename to src/app/resources/icons/type/_Struct.png diff --git a/src/resources/icons/type/_Struct@2x.png b/src/app/resources/icons/type/_Struct@2x.png similarity index 100% rename from src/resources/icons/type/_Struct@2x.png rename to src/app/resources/icons/type/_Struct@2x.png diff --git a/src/resources/zeal.icns b/src/app/resources/zeal.icns similarity index 100% rename from src/resources/zeal.icns rename to src/app/resources/zeal.icns diff --git a/src/resources/zeal.ico b/src/app/resources/zeal.ico similarity index 100% rename from src/resources/zeal.ico rename to src/app/resources/zeal.ico diff --git a/src/resources/zeal.qrc b/src/app/resources/zeal.qrc similarity index 100% rename from src/resources/zeal.qrc rename to src/app/resources/zeal.qrc diff --git a/src/core/application.cpp b/src/libs/core/application.cpp similarity index 98% rename from src/core/application.cpp rename to src/libs/core/application.cpp index a5f0fdfc0..c5fa7af20 100644 --- a/src/core/application.cpp +++ b/src/libs/core/application.cpp @@ -24,10 +24,11 @@ #include "extractor.h" #include "settings.h" -#include "registry/docsetregistry.h" -#include "registry/searchquery.h" -#include "ui/mainwindow.h" -#include "util/version.h" + +#include +#include +#include +#include #include #include diff --git a/src/core/application.h b/src/libs/core/application.h similarity index 100% rename from src/core/application.h rename to src/libs/core/application.h diff --git a/src/core/core.pri b/src/libs/core/core.pri similarity index 65% rename from src/core/core.pri rename to src/libs/core/core.pri index a9823b8e2..b9c3197c6 100644 --- a/src/core/core.pri +++ b/src/libs/core/core.pri @@ -1,5 +1,4 @@ -HEADERS += $$files($$PWD/*.h) -SOURCES += $$files($$PWD/*.cpp) +ZEAL_LIB_NAME = Core unix:!macx { CONFIG += link_pkgconfig diff --git a/src/libs/core/core.pro b/src/libs/core/core.pro new file mode 100644 index 000000000..1c61c1c65 --- /dev/null +++ b/src/libs/core/core.pro @@ -0,0 +1,4 @@ +include($$ZEAL_LIBRARY_PRI) + +HEADERS += $$files(*.h) +SOURCES += $$files(*.cpp) diff --git a/src/core/extractor.cpp b/src/libs/core/extractor.cpp similarity index 100% rename from src/core/extractor.cpp rename to src/libs/core/extractor.cpp diff --git a/src/core/extractor.h b/src/libs/core/extractor.h similarity index 100% rename from src/core/extractor.h rename to src/libs/core/extractor.h diff --git a/src/core/localserver.cpp b/src/libs/core/localserver.cpp similarity index 98% rename from src/core/localserver.cpp rename to src/libs/core/localserver.cpp index 5fb02243e..116309842 100644 --- a/src/core/localserver.cpp +++ b/src/libs/core/localserver.cpp @@ -22,7 +22,7 @@ #include "localserver.h" -#include "registry/searchquery.h" +#include #include #include diff --git a/src/core/localserver.h b/src/libs/core/localserver.h similarity index 100% rename from src/core/localserver.h rename to src/libs/core/localserver.h diff --git a/src/core/settings.cpp b/src/libs/core/settings.cpp similarity index 100% rename from src/core/settings.cpp rename to src/libs/core/settings.cpp diff --git a/src/core/settings.h b/src/libs/core/settings.h similarity index 100% rename from src/core/settings.h rename to src/libs/core/settings.h diff --git a/src/libs/libs.pro b/src/libs/libs.pro new file mode 100644 index 000000000..a323f5d48 --- /dev/null +++ b/src/libs/libs.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + core \ + registry \ + ui \ + util diff --git a/src/registry/cancellationtoken.cpp b/src/libs/registry/cancellationtoken.cpp similarity index 100% rename from src/registry/cancellationtoken.cpp rename to src/libs/registry/cancellationtoken.cpp diff --git a/src/registry/cancellationtoken.h b/src/libs/registry/cancellationtoken.h similarity index 100% rename from src/registry/cancellationtoken.h rename to src/libs/registry/cancellationtoken.h diff --git a/src/registry/docset.cpp b/src/libs/registry/docset.cpp similarity index 99% rename from src/registry/docset.cpp rename to src/libs/registry/docset.cpp index 5b1059734..0a1105d85 100644 --- a/src/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -26,7 +26,8 @@ #include "cancellationtoken.h" #include "searchquery.h" #include "searchresult.h" -#include "util/plist.h" + +#include #include #include diff --git a/src/registry/docset.h b/src/libs/registry/docset.h similarity index 100% rename from src/registry/docset.h rename to src/libs/registry/docset.h diff --git a/src/registry/docsetmetadata.cpp b/src/libs/registry/docsetmetadata.cpp similarity index 100% rename from src/registry/docsetmetadata.cpp rename to src/libs/registry/docsetmetadata.cpp diff --git a/src/registry/docsetmetadata.h b/src/libs/registry/docsetmetadata.h similarity index 100% rename from src/registry/docsetmetadata.h rename to src/libs/registry/docsetmetadata.h diff --git a/src/registry/docsetregistry.cpp b/src/libs/registry/docsetregistry.cpp similarity index 100% rename from src/registry/docsetregistry.cpp rename to src/libs/registry/docsetregistry.cpp diff --git a/src/registry/docsetregistry.h b/src/libs/registry/docsetregistry.h similarity index 100% rename from src/registry/docsetregistry.h rename to src/libs/registry/docsetregistry.h diff --git a/src/registry/listmodel.cpp b/src/libs/registry/listmodel.cpp similarity index 100% rename from src/registry/listmodel.cpp rename to src/libs/registry/listmodel.cpp diff --git a/src/registry/listmodel.h b/src/libs/registry/listmodel.h similarity index 100% rename from src/registry/listmodel.h rename to src/libs/registry/listmodel.h diff --git a/src/libs/registry/registry.pri b/src/libs/registry/registry.pri new file mode 100644 index 000000000..e998c795b --- /dev/null +++ b/src/libs/registry/registry.pri @@ -0,0 +1 @@ +ZEAL_LIB_NAME = Registry diff --git a/src/libs/registry/registry.pro b/src/libs/registry/registry.pro new file mode 100644 index 000000000..9007b98b0 --- /dev/null +++ b/src/libs/registry/registry.pro @@ -0,0 +1,6 @@ +include($$ZEAL_LIBRARY_PRI) + +QT += sql + +HEADERS += $$files(*.h) +SOURCES += $$files(*.cpp) diff --git a/src/registry/searchmodel.cpp b/src/libs/registry/searchmodel.cpp similarity index 99% rename from src/registry/searchmodel.cpp rename to src/libs/registry/searchmodel.cpp index ae98b5531..b477b9f8a 100644 --- a/src/registry/searchmodel.cpp +++ b/src/libs/registry/searchmodel.cpp @@ -23,7 +23,7 @@ #include "searchmodel.h" -#include "registry/docset.h" +#include "docset.h" #include diff --git a/src/registry/searchmodel.h b/src/libs/registry/searchmodel.h similarity index 100% rename from src/registry/searchmodel.h rename to src/libs/registry/searchmodel.h diff --git a/src/registry/searchquery.cpp b/src/libs/registry/searchquery.cpp similarity index 100% rename from src/registry/searchquery.cpp rename to src/libs/registry/searchquery.cpp diff --git a/src/registry/searchquery.h b/src/libs/registry/searchquery.h similarity index 100% rename from src/registry/searchquery.h rename to src/libs/registry/searchquery.h diff --git a/src/registry/searchresult.cpp b/src/libs/registry/searchresult.cpp similarity index 100% rename from src/registry/searchresult.cpp rename to src/libs/registry/searchresult.cpp diff --git a/src/registry/searchresult.h b/src/libs/registry/searchresult.h similarity index 100% rename from src/registry/searchresult.h rename to src/libs/registry/searchresult.h diff --git a/src/ui/aboutdialog.cpp b/src/libs/ui/aboutdialog.cpp similarity index 100% rename from src/ui/aboutdialog.cpp rename to src/libs/ui/aboutdialog.cpp diff --git a/src/ui/aboutdialog.h b/src/libs/ui/aboutdialog.h similarity index 100% rename from src/ui/aboutdialog.h rename to src/libs/ui/aboutdialog.h diff --git a/src/ui/docsetlistitemdelegate.cpp b/src/libs/ui/docsetlistitemdelegate.cpp similarity index 98% rename from src/ui/docsetlistitemdelegate.cpp rename to src/libs/ui/docsetlistitemdelegate.cpp index d7fa3a7f2..e872bf930 100644 --- a/src/ui/docsetlistitemdelegate.cpp +++ b/src/libs/ui/docsetlistitemdelegate.cpp @@ -23,7 +23,7 @@ #include "docsetlistitemdelegate.h" -#include "registry/listmodel.h" +#include #include diff --git a/src/ui/docsetlistitemdelegate.h b/src/libs/ui/docsetlistitemdelegate.h similarity index 100% rename from src/ui/docsetlistitemdelegate.h rename to src/libs/ui/docsetlistitemdelegate.h diff --git a/src/ui/forms/aboutdialog.ui b/src/libs/ui/forms/aboutdialog.ui similarity index 100% rename from src/ui/forms/aboutdialog.ui rename to src/libs/ui/forms/aboutdialog.ui diff --git a/src/ui/forms/mainwindow.ui b/src/libs/ui/forms/mainwindow.ui similarity index 100% rename from src/ui/forms/mainwindow.ui rename to src/libs/ui/forms/mainwindow.ui diff --git a/src/ui/forms/settingsdialog.ui b/src/libs/ui/forms/settingsdialog.ui similarity index 100% rename from src/ui/forms/settingsdialog.ui rename to src/libs/ui/forms/settingsdialog.ui diff --git a/src/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp similarity index 99% rename from src/ui/mainwindow.cpp rename to src/libs/ui/mainwindow.cpp index 466e8f45e..928f79ae6 100644 --- a/src/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -27,11 +27,13 @@ #include "aboutdialog.h" #include "searchitemdelegate.h" #include "settingsdialog.h" -#include "core/application.h" -#include "core/settings.h" -#include "registry/docsetregistry.h" -#include "registry/listmodel.h" -#include "registry/searchmodel.h" +#include "qxtglobalshortcut/qxtglobalshortcut.h" + +#include +#include +#include +#include +#include #include #include @@ -58,8 +60,6 @@ typedef QWebEnginePage QWebPage; #include #endif -#include - // TODO: [Qt 5.5] Remove in favour of native Qt support (QTBUG-31762) #ifdef USE_APPINDICATOR #undef signals diff --git a/src/ui/mainwindow.h b/src/libs/ui/mainwindow.h similarity index 97% rename from src/ui/mainwindow.h rename to src/libs/ui/mainwindow.h index 5ade8c5c3..6893afa30 100644 --- a/src/ui/mainwindow.h +++ b/src/libs/ui/mainwindow.h @@ -24,8 +24,8 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include "registry/searchquery.h" -#include "registry/cancellationtoken.h" +#include +#include #include diff --git a/src/ui/progressitemdelegate.cpp b/src/libs/ui/progressitemdelegate.cpp similarity index 100% rename from src/ui/progressitemdelegate.cpp rename to src/libs/ui/progressitemdelegate.cpp diff --git a/src/ui/progressitemdelegate.h b/src/libs/ui/progressitemdelegate.h similarity index 100% rename from src/ui/progressitemdelegate.h rename to src/libs/ui/progressitemdelegate.h diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.cpp similarity index 100% rename from src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.cpp rename to src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.cpp diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.h similarity index 100% rename from src/3rdparty/qxtglobalshortcut/qxtglobalshortcut.h rename to src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.h diff --git a/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.pri b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.pri new file mode 100644 index 000000000..d4c3e3c69 --- /dev/null +++ b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut.pri @@ -0,0 +1,6 @@ +HEADERS += $$files($$PWD/*.h) +SOURCES += $$PWD/qxtglobalshortcut.cpp + +unix:!macx:SOURCES += $$PWD/qxtglobalshortcut_x11.cpp +win32:SOURCES += $$PWD/qxtglobalshortcut_win.cpp +macx:SOURCES += $$PWD/qxtglobalshortcut_mac.cpp diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_mac.cpp similarity index 100% rename from src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_mac.cpp rename to src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_mac.cpp diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_p.h similarity index 100% rename from src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_p.h rename to src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_p.h diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_win.cpp similarity index 100% rename from src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_win.cpp rename to src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_win.cpp diff --git a/src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp b/src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_x11.cpp similarity index 100% rename from src/3rdparty/qxtglobalshortcut/qxtglobalshortcut_x11.cpp rename to src/libs/ui/qxtglobalshortcut/qxtglobalshortcut_x11.cpp diff --git a/src/ui/searchitemdelegate.cpp b/src/libs/ui/searchitemdelegate.cpp similarity index 100% rename from src/ui/searchitemdelegate.cpp rename to src/libs/ui/searchitemdelegate.cpp diff --git a/src/ui/searchitemdelegate.h b/src/libs/ui/searchitemdelegate.h similarity index 100% rename from src/ui/searchitemdelegate.h rename to src/libs/ui/searchitemdelegate.h diff --git a/src/ui/settingsdialog.cpp b/src/libs/ui/settingsdialog.cpp similarity index 99% rename from src/ui/settingsdialog.cpp rename to src/libs/ui/settingsdialog.cpp index ac590b6a4..4deff7bc7 100644 --- a/src/ui/settingsdialog.cpp +++ b/src/libs/ui/settingsdialog.cpp @@ -26,10 +26,11 @@ #include "docsetlistitemdelegate.h" #include "progressitemdelegate.h" -#include "core/application.h" -#include "core/settings.h" -#include "registry/docsetregistry.h" -#include "registry/listmodel.h" + +#include +#include +#include +#include #include #include diff --git a/src/ui/settingsdialog.h b/src/libs/ui/settingsdialog.h similarity index 98% rename from src/ui/settingsdialog.h rename to src/libs/ui/settingsdialog.h index dc97e5117..93945920c 100644 --- a/src/ui/settingsdialog.h +++ b/src/libs/ui/settingsdialog.h @@ -24,7 +24,7 @@ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H -#include "registry/docsetmetadata.h" +#include #include #include diff --git a/src/ui/ui.pri b/src/libs/ui/ui.pri similarity index 57% rename from src/ui/ui.pri rename to src/libs/ui/ui.pri index 1a2a104a5..037c979bd 100644 --- a/src/ui/ui.pri +++ b/src/libs/ui/ui.pri @@ -1,13 +1,6 @@ -HEADERS += \ - $$files($$PWD/*.h) \ - $$files($$PWD/widgets/*.h) +ZEAL_LIB_NAME = Ui -SOURCES += \ - $$files($$PWD/*.cpp) \ - $$files($$PWD/widgets/*.cpp) - -FORMS += \ - $$files($$PWD/forms/*.ui) +QT += widgets unix:!macx { packagesExist(appindicator-0.1) { @@ -19,3 +12,15 @@ unix:!macx { message("AppIndicator support: No.") } } + +# QxtGlobalShortcut dependencies +unix:!macx { + QT += x11extras + + CONFIG += link_pkgconfig + PKGCONFIG += x11 xcb xcb-keysyms +} + +macx { + LIBS += -framework Carbon +} diff --git a/src/libs/ui/ui.pro b/src/libs/ui/ui.pro new file mode 100644 index 000000000..659af247d --- /dev/null +++ b/src/libs/ui/ui.pro @@ -0,0 +1,14 @@ +include($$ZEAL_LIBRARY_PRI) + +HEADERS += \ + $$files(*.h) \ + $$files(widgets/*.h) + +SOURCES += \ + $$files(*.cpp) \ + $$files(widgets/*.cpp) + +FORMS += \ + $$files(forms/*.ui) + +include(qxtglobalshortcut/qxtglobalshortcut.pri) diff --git a/src/ui/widgets/searchablewebview.cpp b/src/libs/ui/widgets/searchablewebview.cpp similarity index 100% rename from src/ui/widgets/searchablewebview.cpp rename to src/libs/ui/widgets/searchablewebview.cpp diff --git a/src/ui/widgets/searchablewebview.h b/src/libs/ui/widgets/searchablewebview.h similarity index 100% rename from src/ui/widgets/searchablewebview.h rename to src/libs/ui/widgets/searchablewebview.h diff --git a/src/ui/widgets/searchedit.cpp b/src/libs/ui/widgets/searchedit.cpp similarity index 99% rename from src/ui/widgets/searchedit.cpp rename to src/libs/ui/widgets/searchedit.cpp index 0ec39a1b1..34794913e 100644 --- a/src/ui/widgets/searchedit.cpp +++ b/src/libs/ui/widgets/searchedit.cpp @@ -23,7 +23,7 @@ #include "searchedit.h" -#include "registry/searchquery.h" +#include #include #include diff --git a/src/ui/widgets/searchedit.h b/src/libs/ui/widgets/searchedit.h similarity index 100% rename from src/ui/widgets/searchedit.h rename to src/libs/ui/widgets/searchedit.h diff --git a/src/ui/widgets/shortcutedit.cpp b/src/libs/ui/widgets/shortcutedit.cpp similarity index 100% rename from src/ui/widgets/shortcutedit.cpp rename to src/libs/ui/widgets/shortcutedit.cpp diff --git a/src/ui/widgets/shortcutedit.h b/src/libs/ui/widgets/shortcutedit.h similarity index 100% rename from src/ui/widgets/shortcutedit.h rename to src/libs/ui/widgets/shortcutedit.h diff --git a/src/ui/widgets/toolbarframe.cpp b/src/libs/ui/widgets/toolbarframe.cpp similarity index 100% rename from src/ui/widgets/toolbarframe.cpp rename to src/libs/ui/widgets/toolbarframe.cpp diff --git a/src/ui/widgets/toolbarframe.h b/src/libs/ui/widgets/toolbarframe.h similarity index 100% rename from src/ui/widgets/toolbarframe.h rename to src/libs/ui/widgets/toolbarframe.h diff --git a/src/ui/widgets/webview.cpp b/src/libs/ui/widgets/webview.cpp similarity index 100% rename from src/ui/widgets/webview.cpp rename to src/libs/ui/widgets/webview.cpp diff --git a/src/ui/widgets/webview.h b/src/libs/ui/widgets/webview.h similarity index 100% rename from src/ui/widgets/webview.h rename to src/libs/ui/widgets/webview.h diff --git a/src/util/plist.cpp b/src/libs/util/plist.cpp similarity index 100% rename from src/util/plist.cpp rename to src/libs/util/plist.cpp diff --git a/src/util/plist.h b/src/libs/util/plist.h similarity index 100% rename from src/util/plist.h rename to src/libs/util/plist.h diff --git a/src/libs/util/util.pri b/src/libs/util/util.pri new file mode 100644 index 000000000..3a565341a --- /dev/null +++ b/src/libs/util/util.pri @@ -0,0 +1 @@ +ZEAL_LIB_NAME = Util diff --git a/src/libs/util/util.pro b/src/libs/util/util.pro new file mode 100644 index 000000000..1c61c1c65 --- /dev/null +++ b/src/libs/util/util.pro @@ -0,0 +1,4 @@ +include($$ZEAL_LIBRARY_PRI) + +HEADERS += $$files(*.h) +SOURCES += $$files(*.cpp) diff --git a/src/util/version.cpp b/src/libs/util/version.cpp similarity index 100% rename from src/util/version.cpp rename to src/libs/util/version.cpp diff --git a/src/util/version.h b/src/libs/util/version.h similarity index 100% rename from src/util/version.h rename to src/libs/util/version.h diff --git a/src/registry/registry.pri b/src/registry/registry.pri deleted file mode 100644 index b943e5a67..000000000 --- a/src/registry/registry.pri +++ /dev/null @@ -1,5 +0,0 @@ -HEADERS += \ - $$files($$PWD/*.h) - -SOURCES += \ - $$files($$PWD/*.cpp) diff --git a/src/src.pro b/src/src.pro index 34f1936af..9d7845825 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,38 +1,10 @@ -include($$SRC_ROOT/common.pri) +TEMPLATE = subdirs -TEMPLATE = app +SUBDIRS += \ + app \ + libs -QT += gui widgets sql concurrent +app.subdir = app +libs.subdir = libs -HEADERS += \ - util/version.h \ - util/plist.h - -SOURCES += \ - main.cpp \ - util/version.cpp \ - util/plist.cpp - -include(core/core.pri) -include(registry/registry.pri) -include(ui/ui.pri) -include(3rdparty/qxtglobalshortcut/qxtglobalshortcut.pri) - -RESOURCES += \ - resources/zeal.qrc - -DESTDIR = $$BUILD_ROOT/bin - -unix:!macx { - TARGET = zeal -} - -win32 { - TARGET = zeal - RC_ICONS = resources/zeal.ico -} - -macx { - TARGET = Zeal - ICON = resources/zeal.icns -} +app.depends = libs From cb273926739ea9e88934348aae312c0c418a43f3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 02:30:03 -0400 Subject: [PATCH 217/273] app: Reorder link dependencies --- src/app/app.pro | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/app.pro b/src/app/app.pro index e57067898..180e60323 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -26,6 +26,9 @@ macx { ICON = resources/zeal.icns } +# FIXME: Hardcoded link line & cyclic dependencies. +LIBS += -lCore -lUi -lRegistry -lUtil + # Depend on all dependencies of libraries for(lib_dir, $$list($$files($$SRC_ROOT/src/libs/*))) { !equals(lib_dir, $$SRC_ROOT/src/libs/libs.pro) { @@ -33,6 +36,3 @@ for(lib_dir, $$list($$files($$SRC_ROOT/src/libs/*))) { # LIBS += -l$$ZEAL_LIB_NAME } } - -# FIXME: Hardcoded link line & cyclic dependencies. -LIBS += -lUi -lCore -lUi -lRegistry -lUtil From 1f26d795cc1d45579766cd3cc11d534779844a8d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 02:58:56 -0400 Subject: [PATCH 218/273] qmake: Disable ar warnings on Windows This is a workaround for AppVeyor failing builds because of stderr output. --- qmake/common.pri | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qmake/common.pri b/qmake/common.pri index 06129878a..64a61c7a0 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -17,6 +17,9 @@ DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII DEFINES *= QT_NO_CAST_TO_ASCII DEFINES *= QT_NO_URL_CAST_FROM_STRING +# Workaround for AppVeyor: Do not warn if the library had to be created. +win32:QMAKE_AR += -c + # Keep build directory clean MOC_DIR = $$BUILD_ROOT/.moc OBJECTS_DIR = $$BUILD_ROOT/.obj From 29ecbbbf05c443a056fd7ac8e546609eea9767b8 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 04:05:13 -0400 Subject: [PATCH 219/273] Revert "qmake: Disable ar warnings on Windows" This reverts commit 1f26d795cc1d45579766cd3cc11d534779844a8d. QMAKE_AR needs the full command, not ar arguments. --- qmake/common.pri | 3 --- 1 file changed, 3 deletions(-) diff --git a/qmake/common.pri b/qmake/common.pri index 64a61c7a0..06129878a 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -17,9 +17,6 @@ DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII DEFINES *= QT_NO_CAST_TO_ASCII DEFINES *= QT_NO_URL_CAST_FROM_STRING -# Workaround for AppVeyor: Do not warn if the library had to be created. -win32:QMAKE_AR += -c - # Keep build directory clean MOC_DIR = $$BUILD_ROOT/.moc OBJECTS_DIR = $$BUILD_ROOT/.obj From 012c2c508d51f92fa19a534a2fdf18b752658ba3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 04:06:36 -0400 Subject: [PATCH 220/273] qmake: Reenable silent build --- qmake/common.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/common.pri b/qmake/common.pri index 06129878a..cfb7571ce 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -5,7 +5,7 @@ # include($$ZEAL_COMMON_PRI) # Compilation settings -CONFIG += c++11 #silent +CONFIG += c++11 silent # Shared include path INCLUDEPATH += $$SRC_ROOT/src/libs From 61179da2d1a8853e7daef6e16ffe0cd2d840ebcb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 04:15:01 -0400 Subject: [PATCH 221/273] qmake: Another attempt to silence ar on Windows --- qmake/common.pri | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qmake/common.pri b/qmake/common.pri index cfb7571ce..ffae4815b 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -17,6 +17,10 @@ DEFINES *= QT_RESTRICTED_CAST_FROM_ASCII DEFINES *= QT_NO_CAST_TO_ASCII DEFINES *= QT_NO_URL_CAST_FROM_STRING +# Workaround for AppVeyor: Do not warn if the library had to be created. +# Based on https://codereview.qt-project.org/150326 +win32-g++:QMAKE_LIB = ar -rc + # Keep build directory clean MOC_DIR = $$BUILD_ROOT/.moc OBJECTS_DIR = $$BUILD_ROOT/.obj From 144ecddc743943b2cc09a1f916b17ca022ad42b9 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 14:41:13 -0400 Subject: [PATCH 222/273] registry: Move everything into Zeal::Registry namespace All other subprojects updated accordingly. --- src/app/main.cpp | 2 +- src/libs/core/application.cpp | 6 ++-- src/libs/core/application.h | 8 +++-- src/libs/core/localserver.cpp | 5 ++-- src/libs/core/localserver.h | 6 ++-- src/libs/registry/cancellationtoken.cpp | 2 +- src/libs/registry/cancellationtoken.h | 6 ++-- src/libs/registry/docset.cpp | 2 +- src/libs/registry/docset.h | 2 ++ src/libs/registry/docsetmetadata.cpp | 2 +- src/libs/registry/docsetmetadata.h | 2 ++ src/libs/registry/docsetregistry.cpp | 4 +-- src/libs/registry/docsetregistry.h | 2 ++ src/libs/registry/listmodel.cpp | 2 +- src/libs/registry/listmodel.h | 2 ++ src/libs/registry/searchmodel.cpp | 2 +- src/libs/registry/searchmodel.h | 2 ++ src/libs/registry/searchquery.cpp | 6 ++-- src/libs/registry/searchquery.h | 8 +++-- src/libs/registry/searchresult.cpp | 2 +- src/libs/registry/searchresult.h | 2 ++ src/libs/ui/docsetlistitemdelegate.cpp | 4 ++- src/libs/ui/mainwindow.cpp | 38 ++++++++++++------------ src/libs/ui/mainwindow.h | 9 ++++-- src/libs/ui/settingsdialog.cpp | 39 +++++++++++++------------ src/libs/ui/settingsdialog.h | 8 +++-- src/libs/ui/widgets/searchedit.cpp | 4 ++- 27 files changed, 106 insertions(+), 71 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index b726efa96..6c27c9cad 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -51,7 +51,7 @@ struct CommandLineParameters { bool force; bool preventActivation; - SearchQuery query; + Registry::SearchQuery query; #ifdef Q_OS_WIN32 bool registerProtocolHandlers; bool unregisterProtocolHandlers; diff --git a/src/libs/core/application.cpp b/src/libs/core/application.cpp index c5fa7af20..c2f500c5c 100644 --- a/src/libs/core/application.cpp +++ b/src/libs/core/application.cpp @@ -73,7 +73,7 @@ Application::Application(QObject *parent) : connect(m_settings, &Settings::updated, this, &Application::applySettings); applySettings(); - m_docsetRegistry = new DocsetRegistry(); + m_docsetRegistry = new Registry::DocsetRegistry(); m_docsetRegistry->init(m_settings->docsetPath); m_mainWindow = new MainWindow(this); @@ -117,12 +117,12 @@ Settings *Application::settings() const return m_settings; } -DocsetRegistry *Application::docsetRegistry() +Registry::DocsetRegistry *Application::docsetRegistry() { return m_docsetRegistry; } -void Application::executeQuery(const SearchQuery &query, bool preventActivation) +void Application::executeQuery(const Registry::SearchQuery &query, bool preventActivation) { m_mainWindow->search(query); diff --git a/src/libs/core/application.h b/src/libs/core/application.h index 06078c91e..749fc8ca7 100644 --- a/src/libs/core/application.h +++ b/src/libs/core/application.h @@ -33,8 +33,10 @@ class MainWindow; namespace Zeal { +namespace Registry { class DocsetRegistry; class SearchQuery; +} // namespace Registry namespace Core { @@ -53,10 +55,10 @@ class Application : public QObject QNetworkAccessManager *networkManager() const; Settings *settings() const; - DocsetRegistry *docsetRegistry(); + Registry::DocsetRegistry *docsetRegistry(); public slots: - void executeQuery(const SearchQuery &query, bool preventActivation); + void executeQuery(const Registry::SearchQuery &query, bool preventActivation); void extract(const QString &filePath, const QString &destination, const QString &root = QString()); QNetworkReply *download(const QUrl &url); void checkForUpdates(bool quiet = false); @@ -84,7 +86,7 @@ private slots: QThread *m_extractorThread = nullptr; Extractor *m_extractor = nullptr; - DocsetRegistry *m_docsetRegistry = nullptr; + Registry::DocsetRegistry *m_docsetRegistry = nullptr; MainWindow *m_mainWindow = nullptr; }; diff --git a/src/libs/core/localserver.cpp b/src/libs/core/localserver.cpp index 116309842..efac2193e 100644 --- a/src/libs/core/localserver.cpp +++ b/src/libs/core/localserver.cpp @@ -29,6 +29,7 @@ #include #include +using namespace Zeal; using namespace Zeal::Core; namespace { @@ -46,7 +47,7 @@ LocalServer::LocalServer(QObject *parent) return; QDataStream in(connection.data()); - Zeal::SearchQuery query; + Registry::SearchQuery query; bool preventActivation; in >> query; in >> preventActivation; @@ -91,7 +92,7 @@ bool LocalServer::start(bool force) * \param preventActivation If \c true, application window will not activated. * \return \c true if communication with another instance has been successful. */ -bool LocalServer::sendQuery(const SearchQuery &query, bool preventActivation) +bool LocalServer::sendQuery(const Registry::SearchQuery &query, bool preventActivation) { QScopedPointer socket(new QLocalSocket()); socket->connectToServer(LocalServerName); diff --git a/src/libs/core/localserver.h b/src/libs/core/localserver.h index c774cbc10..034dea028 100644 --- a/src/libs/core/localserver.h +++ b/src/libs/core/localserver.h @@ -29,7 +29,9 @@ class QLocalServer; namespace Zeal { +namespace Registry { class SearchQuery; +} // namespace Registry namespace Core { @@ -43,10 +45,10 @@ class LocalServer : public QObject bool start(bool force = false); - static bool sendQuery(const SearchQuery &query, bool preventActivation); + static bool sendQuery(const Registry::SearchQuery &query, bool preventActivation); signals: - void newQuery(const SearchQuery &query, bool preventActivation); + void newQuery(const Registry::SearchQuery &query, bool preventActivation); private: QLocalServer *m_localServer = nullptr; diff --git a/src/libs/registry/cancellationtoken.cpp b/src/libs/registry/cancellationtoken.cpp index 64fa457e5..b767c4c52 100644 --- a/src/libs/registry/cancellationtoken.cpp +++ b/src/libs/registry/cancellationtoken.cpp @@ -22,7 +22,7 @@ #include "cancellationtoken.h" -using namespace Zeal; +using namespace Zeal::Registry; CancellationToken::CancellationToken() { diff --git a/src/libs/registry/cancellationtoken.h b/src/libs/registry/cancellationtoken.h index ff00b1b7b..585a87e87 100644 --- a/src/libs/registry/cancellationtoken.h +++ b/src/libs/registry/cancellationtoken.h @@ -26,6 +26,7 @@ #include namespace Zeal { +namespace Registry { /// Token that stores whether cancel was called on it. /// In async code can be used to check if another thread called cancel. @@ -40,8 +41,9 @@ struct CancellationToken QSharedPointer m_cancelled; }; -} +} // namespace Registry +} // namespace Zeal -Q_DECLARE_METATYPE(Zeal::CancellationToken) +Q_DECLARE_METATYPE(Zeal::Registry::CancellationToken) #endif // CANCELLATIONTOKEN_H diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index 0a1105d85..c7f852c72 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -39,7 +39,7 @@ #include #include -using namespace Zeal; +using namespace Zeal::Registry; namespace { const char IndexNamePrefix[] = "__zi_name"; // zi - Zeal index diff --git a/src/libs/registry/docset.h b/src/libs/registry/docset.h index acd92d48c..475adeb6e 100644 --- a/src/libs/registry/docset.h +++ b/src/libs/registry/docset.h @@ -31,6 +31,7 @@ class QSqlDatabase; namespace Zeal { +namespace Registry { struct CancellationToken; struct SearchResult; @@ -100,6 +101,7 @@ class Docset mutable QMap> m_symbols; }; +} // namespace Registry } // namespace Zeal #endif // DOCSET_H diff --git a/src/libs/registry/docsetmetadata.cpp b/src/libs/registry/docsetmetadata.cpp index f8cfb94a3..42d3b392e 100644 --- a/src/libs/registry/docsetmetadata.cpp +++ b/src/libs/registry/docsetmetadata.cpp @@ -30,7 +30,7 @@ #include #include -using namespace Zeal; +using namespace Zeal::Registry; DocsetMetadata::DocsetMetadata() { diff --git a/src/libs/registry/docsetmetadata.h b/src/libs/registry/docsetmetadata.h index b5b8ca4f7..5672bf769 100644 --- a/src/libs/registry/docsetmetadata.h +++ b/src/libs/registry/docsetmetadata.h @@ -30,6 +30,7 @@ #include namespace Zeal { +namespace Registry { class DocsetMetadata { @@ -74,6 +75,7 @@ class DocsetMetadata QList m_urls; }; +} // namespace Registry } // namespace Zeal #endif // DOCSETMETADATA_H diff --git a/src/libs/registry/docsetregistry.cpp b/src/libs/registry/docsetregistry.cpp index 6d316d265..0994ec9d5 100644 --- a/src/libs/registry/docsetregistry.cpp +++ b/src/libs/registry/docsetregistry.cpp @@ -34,7 +34,7 @@ #include -using namespace Zeal; +using namespace Zeal::Registry; void MergeQueryResults(QList &finalResult, const QList &partial) { @@ -47,7 +47,7 @@ DocsetRegistry::DocsetRegistry(QObject *parent) : { // Register for use in signal connections. qRegisterMetaType("CancellationToken"); - qRegisterMetaType>("QList"); + qRegisterMetaType>("QList"); // FIXME: Only search should be performed in a separate thread moveToThread(m_thread); diff --git a/src/libs/registry/docsetregistry.h b/src/libs/registry/docsetregistry.h index 936b89a47..2b8bcadc4 100644 --- a/src/libs/registry/docsetregistry.h +++ b/src/libs/registry/docsetregistry.h @@ -31,6 +31,7 @@ class QThread; namespace Zeal { +namespace Registry { struct CancellationToken; struct SearchResult; @@ -76,6 +77,7 @@ private slots: QMap m_docsets; }; +} // namespace Registry } // namespace Zeal #endif // DOCSETREGISTRY_H diff --git a/src/libs/registry/listmodel.cpp b/src/libs/registry/listmodel.cpp index 81dd22d91..e963aa381 100644 --- a/src/libs/registry/listmodel.cpp +++ b/src/libs/registry/listmodel.cpp @@ -26,7 +26,7 @@ #include "docset.h" #include "docsetregistry.h" -using namespace Zeal; +using namespace Zeal::Registry; ListModel::ListModel(DocsetRegistry *docsetRegistry, QObject *parent) : QAbstractItemModel(parent), diff --git a/src/libs/registry/listmodel.h b/src/libs/registry/listmodel.h index c10ac4d44..2d0ed913e 100644 --- a/src/libs/registry/listmodel.h +++ b/src/libs/registry/listmodel.h @@ -28,6 +28,7 @@ #include namespace Zeal { +namespace Registry { class Docset; class DocsetRegistry; @@ -84,6 +85,7 @@ private slots: QMap m_docsetItems; }; +} // namespace Registry } // namespace Zeal #endif // LISTMODEL_H diff --git a/src/libs/registry/searchmodel.cpp b/src/libs/registry/searchmodel.cpp index b477b9f8a..8b78bcf0a 100644 --- a/src/libs/registry/searchmodel.cpp +++ b/src/libs/registry/searchmodel.cpp @@ -27,7 +27,7 @@ #include -using namespace Zeal; +using namespace Zeal::Registry; SearchModel::SearchModel(QObject *parent) : QAbstractItemModel(parent) diff --git a/src/libs/registry/searchmodel.h b/src/libs/registry/searchmodel.h index 51ec39ced..d2a7dad0a 100644 --- a/src/libs/registry/searchmodel.h +++ b/src/libs/registry/searchmodel.h @@ -29,6 +29,7 @@ #include namespace Zeal { +namespace Registry { class SearchModel : public QAbstractItemModel { @@ -62,6 +63,7 @@ public slots: QList m_dataList; }; +} // namespace Registry } // namespace Zeal #endif // SEARCHMODEL_H diff --git a/src/libs/registry/searchquery.cpp b/src/libs/registry/searchquery.cpp index de51af78f..2daa72464 100644 --- a/src/libs/registry/searchquery.cpp +++ b/src/libs/registry/searchquery.cpp @@ -23,7 +23,7 @@ #include "searchquery.h" -using namespace Zeal; +using namespace Zeal::Registry; namespace { const char prefixSeparator = ':'; @@ -136,13 +136,13 @@ QString SearchQuery::sanitizedQuery() const return q; } -QDataStream &Zeal::operator<<(QDataStream &out, const SearchQuery &query) +QDataStream &operator<<(QDataStream &out, const Zeal::Registry::SearchQuery &query) { out << query.toString(); return out; } -QDataStream &Zeal::operator>>(QDataStream &in, SearchQuery &query) +QDataStream &operator>>(QDataStream &in, Zeal::Registry::SearchQuery &query) { QString str; in >> str; diff --git a/src/libs/registry/searchquery.h b/src/libs/registry/searchquery.h index 5b62c9039..f0aec9c46 100644 --- a/src/libs/registry/searchquery.h +++ b/src/libs/registry/searchquery.h @@ -27,6 +27,7 @@ #include namespace Zeal { +namespace Registry { /** * @short The search query model. @@ -84,9 +85,10 @@ class SearchQuery QString m_keywordPrefix; }; -QDataStream &operator<<(QDataStream &out, const SearchQuery &query); -QDataStream &operator>>(QDataStream &in, SearchQuery &query); - +} // namespace Registry } // namespace Zeal +QDataStream &operator<<(QDataStream &out, const Zeal::Registry::SearchQuery &query); +QDataStream &operator>>(QDataStream &in, Zeal::Registry::SearchQuery &query); + #endif // SEARCHQUERY_H diff --git a/src/libs/registry/searchresult.cpp b/src/libs/registry/searchresult.cpp index c6447d0d3..74c8bfd09 100644 --- a/src/libs/registry/searchresult.cpp +++ b/src/libs/registry/searchresult.cpp @@ -23,7 +23,7 @@ #include "searchresult.h" -using namespace Zeal; +using namespace Zeal::Registry; bool SearchResult::operator<(const SearchResult &r) const { diff --git a/src/libs/registry/searchresult.h b/src/libs/registry/searchresult.h index 98443e2c4..9c3264a6a 100644 --- a/src/libs/registry/searchresult.h +++ b/src/libs/registry/searchresult.h @@ -27,6 +27,7 @@ #include namespace Zeal { +namespace Registry { class Docset; @@ -46,6 +47,7 @@ struct SearchResult bool operator<(const SearchResult &r) const; }; +} // namespace Registry } // namespace Zeal #endif // SEARCHRESULT_H diff --git a/src/libs/ui/docsetlistitemdelegate.cpp b/src/libs/ui/docsetlistitemdelegate.cpp index e872bf930..c368cf2b8 100644 --- a/src/libs/ui/docsetlistitemdelegate.cpp +++ b/src/libs/ui/docsetlistitemdelegate.cpp @@ -27,6 +27,8 @@ #include +using namespace Zeal; + DocsetListItemDelegate::DocsetListItemDelegate(QObject *parent) : QItemDelegate(parent) { @@ -37,7 +39,7 @@ void DocsetListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem { QItemDelegate::paint(painter, option, index); - if (!index.model()->data(index, Zeal::ListModel::UpdateAvailableRole).toBool()) + if (!index.model()->data(index, Registry::ListModel::UpdateAvailableRole).toBool()) return; const QString text = tr("Update available"); diff --git a/src/libs/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp index 928f79ae6..6d7c0226b 100644 --- a/src/libs/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -78,8 +78,8 @@ struct TabState { explicit TabState() { - searchModel = new Zeal::SearchModel(); - tocModel = new Zeal::SearchModel(); + searchModel = new Registry::SearchModel(); + tocModel = new Registry::SearchModel(); webPage = new QWebPage(); #ifndef USE_WEBENGINE @@ -96,8 +96,8 @@ struct TabState , tocScrollPosition(other.tocScrollPosition) , webViewZoomFactor(other.webViewZoomFactor) { - searchModel = new Zeal::SearchModel(*other.searchModel); - tocModel = new Zeal::SearchModel(*other.tocModel); + searchModel = new Registry::SearchModel(*other.searchModel); + tocModel = new Registry::SearchModel(*other.tocModel); webPage = new QWebPage(); #ifndef USE_WEBENGINE @@ -159,13 +159,13 @@ struct TabState QString searchQuery; // Content/Search results tree view state - Zeal::SearchModel *searchModel = nullptr; + Registry::SearchModel *searchModel = nullptr; QModelIndexList selections; QModelIndexList expansions; int searchScrollPosition = 0; // TOC list view state - Zeal::SearchModel *tocModel = nullptr; + Registry::SearchModel *tocModel = nullptr; int tocScrollPosition = 0; QWebPage *webPage = nullptr; @@ -177,7 +177,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui(new Ui::MainWindow), m_application(app), m_settings(app->settings()), - m_zealListModel(new ListModel(app->docsetRegistry(), this)), + m_zealListModel(new Registry::ListModel(app->docsetRegistry(), this)), m_globalShortcut(new QxtGlobalShortcut(m_settings->showShortcut, this)), m_openDocsetTimer(new QTimer(this)) { @@ -310,9 +310,9 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : ui->lineEdit->setFocus(); setupSearchBoxCompletions(); SearchItemDelegate *delegate = new SearchItemDelegate(ui->treeView); - delegate->setDecorationRoles({Zeal::SearchModel::DocsetIconRole, Qt::DecorationRole}); + delegate->setDecorationRoles({Registry::SearchModel::DocsetIconRole, Qt::DecorationRole}); connect(ui->lineEdit, &QLineEdit::textChanged, [delegate](const QString &text) { - delegate->setHighlight(Zeal::SearchQuery::fromString(text).query()); + delegate->setHighlight(Registry::SearchQuery::fromString(text).query()); }); ui->treeView->setItemDelegate(delegate); @@ -332,7 +332,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : const QString name = docsetName(url); m_tabBar->setTabIcon(m_tabBar->currentIndex(), docsetIcon(name)); - Docset *docset = m_application->docsetRegistry()->docset(name); + Registry::Docset *docset = m_application->docsetRegistry()->docset(name); if (docset) currentTabState()->tocModel->setResults(docset->relatedLinks(url)); @@ -355,12 +355,12 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : QDesktopServices::openUrl(url); }); - connect(m_application->docsetRegistry(), &DocsetRegistry::queryCompleted, - this, [this](const QList &results) { + connect(m_application->docsetRegistry(), &Registry::DocsetRegistry::queryCompleted, + this, [this](const QList &results) { currentTabState()->searchModel->setResults(results); }); - connect(m_application->docsetRegistry(), &DocsetRegistry::docsetRemoved, + connect(m_application->docsetRegistry(), &Registry::DocsetRegistry::docsetRemoved, this, [this](const QString &name) { setupSearchBoxCompletions(); for (TabState *tabState : m_tabStates) { @@ -383,7 +383,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : } }); - connect(m_application->docsetRegistry(), &DocsetRegistry::docsetAdded, + connect(m_application->docsetRegistry(), &Registry::DocsetRegistry::docsetAdded, this, [this](const QString &) { setupSearchBoxCompletions(); }); @@ -394,7 +394,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : currentTabState()->searchQuery = text; m_cancelSearch.cancel(); - m_cancelSearch = CancellationToken(); + m_cancelSearch = Registry::CancellationToken(); m_application->docsetRegistry()->search(text, m_cancelSearch); if (text.isEmpty()) { currentTabState()->tocModel->setResults(); @@ -476,7 +476,7 @@ MainWindow::~MainWindow() qDeleteAll(m_tabStates); } -void MainWindow::search(const SearchQuery &query) +void MainWindow::search(const Registry::SearchQuery &query) { if (query.isEmpty()) return; @@ -514,7 +514,7 @@ QString MainWindow::docsetName(const QUrl &url) const QIcon MainWindow::docsetIcon(const QString &docsetName) const { - Docset *docset = m_application->docsetRegistry()->docset(docsetName); + Registry::Docset *docset = m_application->docsetRegistry()->docset(docsetName); return docset ? docset->icon() : QIcon(QStringLiteral(":/icons/logo/icon.png")); } @@ -553,6 +553,7 @@ void MainWindow::createTab(int index) else if (index == -1) index = m_tabStates.size(); + using Registry::SearchModel; TabState *newTab = new TabState(); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::syncToc); @@ -569,6 +570,7 @@ void MainWindow::duplicateTab(int index) if (index < 0 || index >= m_tabStates.size()) return; + using Registry::SearchModel; TabState *newTab = new TabState(*m_tabStates.at(index)); connect(newTab->searchModel, &SearchModel::queryCompleted, this, &MainWindow::queryCompleted); connect(newTab->tocModel, &SearchModel::queryCompleted, this, &MainWindow::syncToc); @@ -615,7 +617,7 @@ TabState *MainWindow::currentTabState() const void MainWindow::setupSearchBoxCompletions() { QStringList completions; - for (const Docset * const docset: m_application->docsetRegistry()->docsets()) { + for (const Registry::Docset * const docset: m_application->docsetRegistry()->docsets()) { if (docset->keywords().isEmpty()) continue; diff --git a/src/libs/ui/mainwindow.h b/src/libs/ui/mainwindow.h index 6893afa30..7d886d777 100644 --- a/src/libs/ui/mainwindow.h +++ b/src/libs/ui/mainwindow.h @@ -52,7 +52,10 @@ class Application; class Settings; } // namespace Core +namespace Registry { class ListModel; +} //namespace Registry + } // namespace Zeal struct TabState; @@ -64,7 +67,7 @@ class MainWindow : public QMainWindow explicit MainWindow(Zeal::Core::Application *app, QWidget *parent = nullptr); ~MainWindow() override; - void search(const Zeal::SearchQuery &query); + void search(const Zeal::Registry::SearchQuery &query); void bringToFront(); void createTab(int index = -1); @@ -106,12 +109,12 @@ private slots: Ui::MainWindow *ui = nullptr; Zeal::Core::Application *m_application = nullptr; Zeal::Core::Settings *m_settings = nullptr; - Zeal::ListModel *m_zealListModel = nullptr; + Zeal::Registry::ListModel *m_zealListModel = nullptr; QMenu *m_backMenu = nullptr; QMenu *m_forwardMenu = nullptr; - Zeal::CancellationToken m_cancelSearch; + Zeal::Registry::CancellationToken m_cancelSearch; QxtGlobalShortcut *m_globalShortcut = nullptr; diff --git a/src/libs/ui/settingsdialog.cpp b/src/libs/ui/settingsdialog.cpp index 4deff7bc7..6f6b797f0 100644 --- a/src/libs/ui/settingsdialog.cpp +++ b/src/libs/ui/settingsdialog.cpp @@ -77,6 +77,9 @@ SettingsDialog::SettingsDialog(Core::Application *app, QWidget *parent) : m_application(app), m_docsetRegistry(app->docsetRegistry()) { + using Registry::DocsetRegistry; + using Registry::ListModel; + ui->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -101,7 +104,7 @@ SettingsDialog::SettingsDialog(Core::Application *app, QWidget *parent) : ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); for (const QModelIndex &index : selectionModel->selectedIndexes()) { - if (index.data(Zeal::ListModel::UpdateAvailableRole).toBool()) { + if (index.data(ListModel::UpdateAvailableRole).toBool()) { ui->updateSelectedDocsetsButton->setEnabled(true); return; } @@ -188,16 +191,16 @@ void SettingsDialog::addDashFeed() void SettingsDialog::updateSelectedDocsets() { for (const QModelIndex &index : ui->installedDocsetList->selectionModel()->selectedIndexes()) { - if (!index.data(Zeal::ListModel::UpdateAvailableRole).toBool()) + if (!index.data(Registry::ListModel::UpdateAvailableRole).toBool()) continue; - downloadDashDocset(index.data(Zeal::ListModel::DocsetNameRole).toString()); + downloadDashDocset(index.data(Registry::ListModel::DocsetNameRole).toString()); } } void SettingsDialog::updateAllDocsets() { - for (const Docset * const docset : m_docsetRegistry->docsets()) { + for (const Registry::Docset * const docset : m_docsetRegistry->docsets()) { if (!docset->hasUpdate) continue; @@ -227,7 +230,7 @@ void SettingsDialog::removeSelectedDocsets() QStringList names; for (const QModelIndex &index : selectonModel->selectedIndexes()) - names << index.data(ListModel::DocsetNameRole).toString(); + names << index.data(Registry::ListModel::DocsetNameRole).toString(); removeDocsets(names); } @@ -239,7 +242,7 @@ void SettingsDialog::updateDocsetFilter(const QString &filterString) QListWidgetItem *item = ui->availableDocsetList->item(i); // Skip installed docsets - if (m_docsetRegistry->contains(item->data(ListModel::DocsetNameRole).toString())) + if (m_docsetRegistry->contains(item->data(Registry::ListModel::DocsetNameRole).toString())) continue; item->setHidden(doSearch && !item->text().contains(filterString, Qt::CaseInsensitive)); @@ -339,8 +342,8 @@ void SettingsDialog::downloadCompleted() } case DownloadDashFeed: { - DocsetMetadata metadata - = DocsetMetadata::fromDashFeed(reply->request().url(), reply->readAll()); + Registry::DocsetMetadata metadata + = Registry::DocsetMetadata::fromDashFeed(reply->request().url(), reply->readAll()); if (metadata.urls().isEmpty()) { QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Invalid docset feed!")); @@ -357,7 +360,7 @@ void SettingsDialog::downloadCompleted() case DownloadDocset: { const QString docsetName = reply->property(DocsetNameProperty).toString(); - const DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + const Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) ? m_availableDocsets[docsetName] : m_userFeeds[docsetName]; @@ -465,7 +468,7 @@ void SettingsDialog::extractionCompleted(const QString &filePath) const QString docsetPath = dataDir.absoluteFilePath(docsetName + QLatin1String(".docset")); // Write metadata about docset - DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) ? m_availableDocsets[docsetName] : m_userFeeds[docsetName]; metadata.save(docsetPath, metadata.latestVersion()); @@ -503,7 +506,7 @@ void SettingsDialog::extractionProgress(const QString &filePath, qint64 extracte } } - DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) ? m_availableDocsets[docsetName] : m_userFeeds[docsetName]; @@ -529,7 +532,7 @@ void SettingsDialog::on_downloadDocsetButton_clicked() item->setData(ProgressItemDelegate::ValueRole, 0); item->setData(ProgressItemDelegate::ShowProgressRole, true); - downloadDashDocset(item->data(ListModel::DocsetNameRole).toString()); + downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); } } @@ -587,7 +590,7 @@ QListWidgetItem *SettingsDialog::findDocsetListItem(const QString &title) const bool SettingsDialog::updatesAvailable() const { - for (Docset *docset : m_docsetRegistry->docsets()) { + for (Registry::Docset *docset : m_docsetRegistry->docsets()) { if (docset->hasUpdate) return true; } @@ -648,21 +651,21 @@ void SettingsDialog::processDocsetList(const QJsonArray &list) for (const QJsonValue &v : list) { QJsonObject docsetJson = v.toObject(); - DocsetMetadata metadata(docsetJson); + Registry::DocsetMetadata metadata(docsetJson); m_availableDocsets.insert(metadata.name(), metadata); } // TODO: Move into dedicated method - for (const DocsetMetadata &metadata : m_availableDocsets) { + for (const Registry::DocsetMetadata &metadata : m_availableDocsets) { QListWidgetItem *listItem = new QListWidgetItem(metadata.icon(), metadata.title(), ui->availableDocsetList); - listItem->setData(ListModel::DocsetNameRole, metadata.name()); + listItem->setData(Registry::ListModel::DocsetNameRole, metadata.name()); listItem->setCheckState(Qt::Unchecked); if (m_docsetRegistry->contains(metadata.name())) { listItem->setHidden(true); - Docset *docset = m_docsetRegistry->docset(metadata.name()); + Registry::Docset *docset = m_docsetRegistry->docset(metadata.name()); if (metadata.latestVersion() != docset->version() || (metadata.latestVersion() == docset->version() @@ -752,7 +755,7 @@ void SettingsDialog::resetProgress() QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); bool hasSelectedUpdates = false; for (const QModelIndex &index : selectionModel->selectedIndexes()) { - if (index.data(Zeal::ListModel::UpdateAvailableRole).toBool()) { + if (index.data(Registry::ListModel::UpdateAvailableRole).toBool()) { hasSelectedUpdates = true; break; } diff --git a/src/libs/ui/settingsdialog.h b/src/libs/ui/settingsdialog.h index 93945920c..5d127b885 100644 --- a/src/libs/ui/settingsdialog.h +++ b/src/libs/ui/settingsdialog.h @@ -41,7 +41,9 @@ class SettingsDialog; namespace Zeal { +namespace Registry { class DocsetRegistry; +} // namespace Registry namespace Core { class Application; @@ -81,15 +83,15 @@ private slots: Ui::SettingsDialog *ui = nullptr; Core::Application *m_application = nullptr; - DocsetRegistry *m_docsetRegistry = nullptr; + Registry::DocsetRegistry *m_docsetRegistry = nullptr; QList m_replies; qint64 m_combinedTotal = 0; qint64 m_combinedReceived = 0; // TODO: Create a special model - QMap m_availableDocsets; - QMap m_userFeeds; + QMap m_availableDocsets; + QMap m_userFeeds; QHash m_tmpFiles; diff --git a/src/libs/ui/widgets/searchedit.cpp b/src/libs/ui/widgets/searchedit.cpp index 34794913e..851a40a5a 100644 --- a/src/libs/ui/widgets/searchedit.cpp +++ b/src/libs/ui/widgets/searchedit.cpp @@ -31,6 +31,8 @@ #include #include +using namespace Zeal; + SearchEdit::SearchEdit(QWidget *parent) : QLineEdit(parent) { @@ -154,7 +156,7 @@ QString SearchEdit::currentCompletion(const QString &text) const int SearchEdit::queryStart() const { - const Zeal::SearchQuery currentQuery = Zeal::SearchQuery::fromString(text()); + const Registry::SearchQuery currentQuery = Registry::SearchQuery::fromString(text()); // Keep the filter for the first Escape press return currentQuery.query().isEmpty() ? 0 : currentQuery.keywordPrefixSize(); } From 4aa20b048fc46011ed48f109858c0c81337be26b Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 19:24:04 -0400 Subject: [PATCH 223/273] qmake: Enforce relink --- src/app/app.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/app.pro b/src/app/app.pro index 180e60323..6f2d5551d 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -33,6 +33,7 @@ LIBS += -lCore -lUi -lRegistry -lUtil for(lib_dir, $$list($$files($$SRC_ROOT/src/libs/*))) { !equals(lib_dir, $$SRC_ROOT/src/libs/libs.pro) { include($$lib_dir/$$basename(lib_dir).pri) + PRE_TARGETDEPS += $$BUILD_ROOT/.lib/$$ZEAL_LIB_NAME.a # LIBS += -l$$ZEAL_LIB_NAME } } From bcbea61fcc9d7adc556bd1684fd3e7ddf17accf0 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 21:47:02 -0400 Subject: [PATCH 224/273] ui: Move docset management UI into a dedicated dialog (fixes #354) --- src/libs/ui/docsetsdialog.cpp | 767 ++++++++++++++++++++++++++++ src/libs/ui/docsetsdialog.h | 121 +++++ src/libs/ui/forms/docsetsdialog.ui | 248 +++++++++ src/libs/ui/forms/mainwindow.ui | 12 + src/libs/ui/forms/settingsdialog.ui | 173 +------ src/libs/ui/mainwindow.cpp | 7 + src/libs/ui/settingsdialog.cpp | 715 +------------------------- src/libs/ui/settingsdialog.h | 63 --- 8 files changed, 1162 insertions(+), 944 deletions(-) create mode 100644 src/libs/ui/docsetsdialog.cpp create mode 100644 src/libs/ui/docsetsdialog.h create mode 100644 src/libs/ui/forms/docsetsdialog.ui diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp new file mode 100644 index 000000000..cbd360681 --- /dev/null +++ b/src/libs/ui/docsetsdialog.cpp @@ -0,0 +1,767 @@ +/**************************************************************************** +** +** Copyright (C) 2015-2016 Oleg Shparber +** Copyright (C) 2013-2014 Jerzy Kozera +** Contact: https://go.zealdocs.org/l/contact +** +** This file is part of Zeal. +** +** Zeal 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. +** +** Zeal 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 Zeal. If not, see . +** +****************************************************************************/ + +#include "docsetsdialog.h" +#include "ui_docsetsdialog.h" + +#include "docsetlistitemdelegate.h" +#include "progressitemdelegate.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Zeal; + +namespace { +const char ApiServerUrl[] = "http://api.zealdocs.org/v1"; +const char RedirectServerUrl[] = "https://go.zealdocs.org"; +// TODO: Each source plugin should have its own cache +const char DocsetListCacheFileName[] = "com.kapeli.json"; + +// TODO: Make the timeout period configurable +constexpr int CacheTimeout = 24 * 60 * 60 * 1000; // 24 hours in microseconds + +// QNetworkReply properties +const char DocsetNameProperty[] = "docsetName"; +const char DownloadTypeProperty[] = "downloadType"; +const char DownloadPreviousReceived[] = "downloadPreviousReceived"; +const char ListItemIndexProperty[] = "listItem"; +} + +DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : + QDialog(parent), + ui(new Ui::DocsetsDialog()), + m_application(app), + m_docsetRegistry(app->docsetRegistry()) +{ + using Registry::DocsetRegistry; + using Registry::ListModel; + + ui->setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + +#ifdef Q_OS_OSX + ui->availableDocsetList->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->installedDocsetList->setAttribute(Qt::WA_MacShowFocusRect, false); +#endif + + ui->docsetsProgress->hide(); + + ui->installedDocsetList->setItemDelegate(new DocsetListItemDelegate(this)); + ui->installedDocsetList->setModel(new ListModel(app->docsetRegistry(), this)); + + ui->installedDocsetList->setSelectionMode(QAbstractItemView::ExtendedSelection); + QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); + connect(selectionModel, &QItemSelectionModel::selectionChanged, + [this, selectionModel]() { + if (!m_replies.isEmpty()) + return; + + ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); + + for (const QModelIndex &index : selectionModel->selectedIndexes()) { + if (index.data(ListModel::UpdateAvailableRole).toBool()) { + ui->updateSelectedDocsetsButton->setEnabled(true); + return; + } + } + ui->updateSelectedDocsetsButton->setEnabled(false); + }); + connect(ui->updateSelectedDocsetsButton, &QPushButton::clicked, + this, &DocsetsDialog::updateSelectedDocsets); + connect(ui->updateAllDocsetsButton, &QPushButton::clicked, + this, &DocsetsDialog::updateAllDocsets); + connect(ui->removeDocsetsButton, &QPushButton::clicked, + this, &DocsetsDialog::removeSelectedDocsets); + connect(ui->docsetFilterInput, &QLineEdit::textEdited, + this, &DocsetsDialog::updateDocsetFilter); + + ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); + connect(m_docsetRegistry, &DocsetRegistry::docsetRemoved, this, [this](const QString name) { + QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); + if (!item) + return; + + item->setHidden(false); + }); + connect(m_docsetRegistry, &DocsetRegistry::docsetAdded, this, [this](const QString name) { + QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); + if (!item) + return; + + item->setHidden(true); + }); + + // Setup signals & slots + connect(ui->addFeedButton, &QPushButton::clicked, this, &DocsetsDialog::addDashFeed); + connect(ui->refreshButton, &QPushButton::clicked, this, &DocsetsDialog::downloadDocsetList); + + connect(m_application, &Core::Application::extractionCompleted, + this, &DocsetsDialog::extractionCompleted); + connect(m_application, &Core::Application::extractionError, + this, &DocsetsDialog::extractionError); + connect(m_application, &Core::Application::extractionProgress, + this, &DocsetsDialog::extractionProgress); + + loadDocsetList(); +} + +DocsetsDialog::~DocsetsDialog() +{ + delete ui; +} + +void DocsetsDialog::reject() +{ + if (m_replies.isEmpty() && m_tmpFiles.isEmpty()) { + QDialog::reject(); + return; + } + + QMessageBox::information(this, QStringLiteral("Zeal"), + tr("An operation is in progress, wait for it to finish, or cancel.")); +} + +void DocsetsDialog::addDashFeed() +{ + QString clipboardText = QApplication::clipboard()->text(); + if (!clipboardText.startsWith(QLatin1String("dash-feed://"))) + clipboardText.clear(); + + QString feedUrl = QInputDialog::getText(this, QStringLiteral("Zeal"), tr("Feed URL:"), + QLineEdit::Normal, clipboardText); + if (feedUrl.isEmpty()) + return; + + if (feedUrl.startsWith(QLatin1String("dash-feed://"))) { + feedUrl = feedUrl.remove(0, 12); + feedUrl = QUrl::fromPercentEncoding(feedUrl.toUtf8()); + } + + QNetworkReply *reply = download(QUrl(feedUrl)); + reply->setProperty(DownloadTypeProperty, DownloadDashFeed); + connect(reply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); +} + +void DocsetsDialog::updateSelectedDocsets() +{ + for (const QModelIndex &index : ui->installedDocsetList->selectionModel()->selectedIndexes()) { + if (!index.data(Registry::ListModel::UpdateAvailableRole).toBool()) + continue; + + downloadDashDocset(index.data(Registry::ListModel::DocsetNameRole).toString()); + } +} + +void DocsetsDialog::updateAllDocsets() +{ + for (const Registry::Docset * const docset : m_docsetRegistry->docsets()) { + if (!docset->hasUpdate) + continue; + + downloadDashDocset(docset->name()); + } +} + +void DocsetsDialog::removeSelectedDocsets() +{ + QItemSelectionModel *selectonModel = ui->installedDocsetList->selectionModel(); + if (!selectonModel->hasSelection()) + return; + + int ret; + if (selectonModel->selectedIndexes().count() == 1) { + const QString docsetTitle = selectonModel->selectedIndexes().first().data().toString(); + ret = QMessageBox::question(this, QStringLiteral("Zeal"), + tr("Remove %1 docset?").arg(docsetTitle)); + } else { + ret = QMessageBox::question(this, QStringLiteral("Zeal"), + tr("Remove %1 docsets?") + .arg(selectonModel->selectedIndexes().count())); + } + + if (ret == QMessageBox::No) + return; + + QStringList names; + for (const QModelIndex &index : selectonModel->selectedIndexes()) + names << index.data(Registry::ListModel::DocsetNameRole).toString(); + removeDocsets(names); +} + +void DocsetsDialog::updateDocsetFilter(const QString &filterString) +{ + const bool doSearch = !filterString.simplified().isEmpty(); + + for (int i = 0; i < ui->availableDocsetList->count(); ++i) { + QListWidgetItem *item = ui->availableDocsetList->item(i); + + // Skip installed docsets + if (m_docsetRegistry->contains(item->data(Registry::ListModel::DocsetNameRole).toString())) + continue; + + item->setHidden(doSearch && !item->text().contains(filterString, Qt::CaseInsensitive)); + } +} + +/*! + \internal + Should be connected to all \l QNetworkReply::finished signals in order to process possible + HTTP-redirects correctly. +*/ +void DocsetsDialog::downloadCompleted() +{ + QScopedPointer reply( + qobject_cast(sender())); + + m_replies.removeOne(reply.data()); + + if (reply->error() != QNetworkReply::NoError) { + if (reply->error() != QNetworkReply::OperationCanceledError) { + const int ret = QMessageBox::warning(this, QStringLiteral("Zeal"), reply->errorString(), + QMessageBox::Retry | QMessageBox::Default, + QMessageBox::Cancel | QMessageBox::Escape, + QMessageBox::NoButton); + + if (ret == QMessageBox::Retry) { + QNetworkReply *newReply = download(reply->request().url()); + + // Copy properties + newReply->setProperty(DocsetNameProperty, reply->property(DocsetNameProperty)); + newReply->setProperty(DownloadTypeProperty, reply->property(DownloadTypeProperty)); + newReply->setProperty(ListItemIndexProperty, + reply->property(ListItemIndexProperty)); + + connect(newReply, &QNetworkReply::finished, + this, &DocsetsDialog::downloadCompleted); + return; + } + + bool ok; + QListWidgetItem *listItem = ui->availableDocsetList->item( + reply->property(ListItemIndexProperty).toInt(&ok)); + if (ok && listItem) + listItem->setData(ProgressItemDelegate::ShowProgressRole, false); + } + + if (m_replies.isEmpty()) + resetProgress(); + + return; + } + + QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (redirectUrl.isValid()) { + if (redirectUrl.isRelative()) + redirectUrl = reply->request().url().resolved(redirectUrl); + + // TODO: Verify if scheme can be missing + if (redirectUrl.scheme().isEmpty()) + redirectUrl.setScheme(reply->request().url().scheme()); + + QNetworkReply *newReply = download(redirectUrl); + + // Copy properties + newReply->setProperty(DocsetNameProperty, reply->property(DocsetNameProperty)); + newReply->setProperty(DownloadTypeProperty, reply->property(DownloadTypeProperty)); + newReply->setProperty(ListItemIndexProperty, reply->property(ListItemIndexProperty)); + + connect(newReply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); + + return; + } + + switch (reply->property(DownloadTypeProperty).toUInt()) { + case DownloadDocsetList: { + const QByteArray data = reply->readAll(); + + QScopedPointer file(new QFile(cacheLocation(DocsetListCacheFileName))); + if (file->open(QIODevice::WriteOnly)) + file->write(data); + + ui->lastUpdatedLabel->setText(QFileInfo(file->fileName()) + .lastModified().toString(Qt::SystemLocaleShortDate)); + + QJsonParseError jsonError; + const QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error != QJsonParseError::NoError) { + QMessageBox::warning(this, QStringLiteral("Zeal"), + tr("Corrupted docset list: ") + jsonError.errorString()); + break; + } + + processDocsetList(jsonDoc.array()); + resetProgress(); + break; + } + + case DownloadDashFeed: { + Registry::DocsetMetadata metadata + = Registry::DocsetMetadata::fromDashFeed(reply->request().url(), reply->readAll()); + + if (metadata.urls().isEmpty()) { + QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Invalid docset feed!")); + break; + } + + m_userFeeds[metadata.name()] = metadata; + QNetworkReply *reply = download(metadata.url()); + reply->setProperty(DocsetNameProperty, metadata.name()); + reply->setProperty(DownloadTypeProperty, DownloadDocset); + connect(reply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); + break; + } + + case DownloadDocset: { + const QString docsetName = reply->property(DocsetNameProperty).toString(); + const Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + ? m_availableDocsets[docsetName] + : m_userFeeds[docsetName]; + + // TODO: Implement an explicit and verbose docset update logic + QDir dir(m_application->settings()->docsetPath); + const QString docsetDirName = docsetName + QLatin1String(".docset"); + if (dir.exists(docsetDirName)) { + m_docsetRegistry->remove(docsetName); + const QString tmpName = QStringLiteral(".toDelete") + + QString::number(QDateTime::currentMSecsSinceEpoch()); + dir.rename(docsetDirName, tmpName); + QtConcurrent::run([=] { + QDir d(dir); + if (!d.cd(tmpName)) + return; + d.removeRecursively(); + }); + } + + QTemporaryFile *tmpFile = m_tmpFiles[docsetName]; + if (!tmpFile) { + tmpFile = new QTemporaryFile(this); + tmpFile->open(); + m_tmpFiles.insert(docsetName, tmpFile); + } + + while (reply->bytesAvailable()) + tmpFile->write(reply->read(1024 * 1024)); // Use small chunks + tmpFile->close(); + + QListWidgetItem *item = findDocsetListItem(metadata.title()); + if (item) { + item->setData(ProgressItemDelegate::ValueRole, 0); + item->setData(ProgressItemDelegate::FormatRole, tr("Installing: %p%")); + } + + m_tmpFiles.insert(metadata.name(), tmpFile); + m_application->extract(tmpFile->fileName(), m_application->settings()->docsetPath, + metadata.name() + QLatin1String(".docset")); + break; + } + } + + // If all enqueued downloads have finished executing + if (m_replies.isEmpty()) + resetProgress(); +} + +// creates a total download progress for multiple QNetworkReplies +void DocsetsDialog::downloadProgress(qint64 received, qint64 total) +{ + // Don't show progress for non-docset pages + if (total == -1 || received < 10240) + return; + + QNetworkReply *reply = qobject_cast(sender()); + if (!reply || !reply->isOpen()) + return; + + if (reply->property(DownloadTypeProperty).toInt() == DownloadDocset) { + const QString docsetName = reply->property(DocsetNameProperty).toString(); + + QTemporaryFile *tmpFile = m_tmpFiles[docsetName]; + if (!tmpFile) { + tmpFile = new QTemporaryFile(this); + tmpFile->open(); + m_tmpFiles.insert(docsetName, tmpFile); + } + + tmpFile->write(reply->read(received)); + } + + // Try to get the item associated to the request + QListWidgetItem *item + = ui->availableDocsetList->item(reply->property(ListItemIndexProperty).toInt()); + if (item) + item->setData(ProgressItemDelegate::ValueRole, percent(received, total)); + + qint64 previousReceived = 0; + const QVariant previousReceivedVariant = reply->property(DownloadPreviousReceived); + if (!previousReceivedVariant.isValid()) + m_combinedTotal += total; + else + previousReceived = previousReceivedVariant.toLongLong(); + + m_combinedReceived += received - previousReceived; + reply->setProperty(DownloadPreviousReceived, received); + + displayProgress(); +} + +void DocsetsDialog::extractionCompleted(const QString &filePath) +{ + QString docsetName; + + // FIXME: Come up with a better approach + for (const QString &key : m_tmpFiles.keys()) { + if (m_tmpFiles[key]->fileName() == filePath) { + docsetName = key; + break; + } + } + + const QDir dataDir(m_application->settings()->docsetPath); + const QString docsetPath = dataDir.absoluteFilePath(docsetName + QLatin1String(".docset")); + + // Write metadata about docset + Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + ? m_availableDocsets[docsetName] + : m_userFeeds[docsetName]; + metadata.save(docsetPath, metadata.latestVersion()); + + m_docsetRegistry->addDocset(docsetPath); + + QListWidgetItem *listItem = findDocsetListItem(metadata.title()); + if (listItem) { + listItem->setHidden(true); + listItem->setCheckState(Qt::Unchecked); + listItem->setData(ProgressItemDelegate::ShowProgressRole, false); + } + resetProgress(); + delete m_tmpFiles.take(docsetName); +} + +void DocsetsDialog::extractionError(const QString &filePath, const QString &errorString) +{ + const QString docsetName = QFileInfo(filePath).baseName() + QLatin1String(".docset"); + QMessageBox::warning(this, QStringLiteral("Zeal"), + tr("Cannot extract docset %1: %2").arg(docsetName, errorString)); + // TODO: Update list item state (hide progress bar) + delete m_tmpFiles.take(docsetName); +} + +void DocsetsDialog::extractionProgress(const QString &filePath, qint64 extracted, qint64 total) +{ + QString docsetName; + + // FIXME: Come up with a better approach + for (const QString &key : m_tmpFiles.keys()) { + if (m_tmpFiles[key]->fileName() == filePath) { + docsetName = key; + break; + } + } + + Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + ? m_availableDocsets[docsetName] + : m_userFeeds[docsetName]; + + QListWidgetItem *listItem = findDocsetListItem(metadata.title()); + if (listItem) + listItem->setData(ProgressItemDelegate::ValueRole, percent(extracted, total)); +} + +void DocsetsDialog::on_downloadDocsetButton_clicked() +{ + if (!m_replies.isEmpty()) { + cancelDownloads(); + return; + } + + // Find each checked item, and create a NetworkRequest for it. + for (int i = 0; i < ui->availableDocsetList->count(); ++i) { + QListWidgetItem *item = ui->availableDocsetList->item(i); + if (item->checkState() != Qt::Checked) + continue; + + item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); + item->setData(ProgressItemDelegate::ValueRole, 0); + item->setData(ProgressItemDelegate::ShowProgressRole, true); + + downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); + } +} + +void DocsetsDialog::loadDocsetList() +{ + const QFileInfo fi(cacheLocation(DocsetListCacheFileName)); + if (!fi.exists() || fi.lastModified().msecsTo(QDateTime::currentDateTime()) > CacheTimeout) { + downloadDocsetList(); + return; + } + + QScopedPointer file(new QFile(fi.filePath())); + if (!file->open(QIODevice::ReadOnly)) { + downloadDocsetList(); + return; + } + + QJsonParseError jsonError; + const QJsonDocument jsonDoc = QJsonDocument::fromJson(file->readAll(), &jsonError); + + if (jsonError.error != QJsonParseError::NoError) { + downloadDocsetList(); + return; + } + + // TODO: Show more user friendly labels, like "5 hours ago" + ui->lastUpdatedLabel->setText(fi.lastModified().toString(Qt::SystemLocaleShortDate)); + processDocsetList(jsonDoc.array()); +} + +QListWidgetItem *DocsetsDialog::findDocsetListItem(const QString &title) const +{ + for (int i = 0; i < ui->availableDocsetList->count(); ++i) { + QListWidgetItem *item = ui->availableDocsetList->item(i); + + if (item->text() == title) + return item; + } + + return nullptr; +} + +bool DocsetsDialog::updatesAvailable() const +{ + for (Registry::Docset *docset : m_docsetRegistry->docsets()) { + if (docset->hasUpdate) + return true; + } + + return false; +} + +QNetworkReply *DocsetsDialog::download(const QUrl &url) +{ + displayProgress(); + + QNetworkReply *reply = m_application->download(url); + connect(reply, &QNetworkReply::downloadProgress, this, &DocsetsDialog::downloadProgress); + m_replies.append(reply); + + // Installed docsets + ui->addFeedButton->setEnabled(false); + ui->updateSelectedDocsetsButton->setEnabled(false); + ui->updateAllDocsetsButton->setEnabled(false); + ui->removeDocsetsButton->setEnabled(false); + + // Available docsets + ui->refreshButton->setEnabled(false); + ui->downloadDocsetButton->setText(tr("Stop downloads")); + + return reply; +} + +void DocsetsDialog::cancelDownloads() +{ + for (QNetworkReply *reply : m_replies) { + // Hide progress bar + QListWidgetItem *listItem + = ui->availableDocsetList->item(reply->property(ListItemIndexProperty).toInt()); + if (listItem) + listItem->setData(ProgressItemDelegate::ShowProgressRole, false); + + if (reply->property(DownloadTypeProperty).toInt() == DownloadDocset) + delete m_tmpFiles.take(reply->property(DocsetNameProperty).toString()); + + reply->abort(); + } + resetProgress(); +} + +void DocsetsDialog::downloadDocsetList() +{ + ui->availableDocsetList->clear(); + m_availableDocsets.clear(); + + QNetworkReply *reply = download(QUrl(ApiServerUrl + QLatin1String("/docsets"))); + reply->setProperty(DownloadTypeProperty, DownloadDocsetList); + connect(reply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); +} + +void DocsetsDialog::processDocsetList(const QJsonArray &list) +{ + for (const QJsonValue &v : list) { + QJsonObject docsetJson = v.toObject(); + + Registry::DocsetMetadata metadata(docsetJson); + m_availableDocsets.insert(metadata.name(), metadata); + } + + // TODO: Move into dedicated method + for (const Registry::DocsetMetadata &metadata : m_availableDocsets) { + QListWidgetItem *listItem + = new QListWidgetItem(metadata.icon(), metadata.title(), ui->availableDocsetList); + listItem->setData(Registry::ListModel::DocsetNameRole, metadata.name()); + listItem->setCheckState(Qt::Unchecked); + + if (m_docsetRegistry->contains(metadata.name())) { + listItem->setHidden(true); + + Registry::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 DocsetsDialog::downloadDashDocset(const QString &name) +{ + if (!m_availableDocsets.contains(name)) + return; + + const QString urlString = RedirectServerUrl + QStringLiteral("/d/com.kapeli/%1/latest"); + QNetworkReply *reply = download(QUrl(urlString.arg(name))); + reply->setProperty(DocsetNameProperty, name); + reply->setProperty(DownloadTypeProperty, DownloadDocset); + reply->setProperty(ListItemIndexProperty, + ui->availableDocsetList->row(findDocsetListItem(m_availableDocsets[name].title()))); + + connect(reply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); +} + +void DocsetsDialog::removeDocsets(const QStringList &names) +{ + for (const QString &name : names) { + const QString title = m_docsetRegistry->docset(name)->title(); + m_docsetRegistry->remove(name); + + const QDir dataDir(m_application->settings()->docsetPath); + if (dataDir.exists()) { + ui->docsetsProgress->show(); + ui->removeDocsetsButton->setEnabled(false); + displayProgress(); + + QFuture future = QtConcurrent::run([=] { + QDir docsetDir(dataDir); + return docsetDir.cd(name + QLatin1String(".docset")) + && docsetDir.removeRecursively(); + }); + QFutureWatcher *watcher = new QFutureWatcher(); + watcher->setFuture(future); + connect(watcher, &QFutureWatcher::finished, [=] { + if (!watcher->result()) { + QMessageBox::warning(this, QStringLiteral("Zeal"), + tr("Cannot delete docset %1!").arg(title)); + } + + resetProgress(); + + QListWidgetItem *listItem = findDocsetListItem(title); + if (listItem) + listItem->setHidden(false); + + watcher->deleteLater(); + }); + } + } +} + +void DocsetsDialog::displayProgress() +{ + ui->docsetsProgress->setValue(percent(m_combinedReceived, m_combinedTotal)); + ui->docsetsProgress->setMaximum(100); + ui->docsetsProgress->setVisible(!m_replies.isEmpty()); +} + +void DocsetsDialog::resetProgress() +{ + if (!m_replies.isEmpty()) + return; + + m_combinedReceived = 0; + m_combinedTotal = 0; + displayProgress(); + + // Installed docsets + ui->addFeedButton->setEnabled(true); + QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); + bool hasSelectedUpdates = false; + for (const QModelIndex &index : selectionModel->selectedIndexes()) { + if (index.data(Registry::ListModel::UpdateAvailableRole).toBool()) { + hasSelectedUpdates = true; + break; + } + } + ui->updateSelectedDocsetsButton->setEnabled(hasSelectedUpdates); + ui->updateAllDocsetsButton->setEnabled(updatesAvailable()); + ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); + + // Available docsets + ui->refreshButton->setEnabled(true); + ui->downloadDocsetButton->setText(tr("Download")); +} + +int DocsetsDialog::percent(qint64 fraction, qint64 total) +{ + if (!total) + return 0; + + return static_cast(fraction / static_cast(total) * 100); +} + +QString DocsetsDialog::cacheLocation(const QString &fileName) +{ +#ifndef PORTABLE_BUILD + const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); +#else + const QDir cacheDir(QCoreApplication::applicationDirPath() + QLatin1String("/cache")); +#endif + // TODO: Report error + QDir().mkpath(cacheDir.path()); + + return cacheDir.filePath(fileName); +} diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h new file mode 100644 index 000000000..909797e76 --- /dev/null +++ b/src/libs/ui/docsetsdialog.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2015-2016 Oleg Shparber +** Copyright (C) 2013-2014 Jerzy Kozera +** Contact: https://go.zealdocs.org/l/contact +** +** This file is part of Zeal. +** +** Zeal 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. +** +** Zeal 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 Zeal. If not, see . +** +****************************************************************************/ + +#ifndef DOCSETSDIALOG_H +#define DOCSETSDIALOG_H + +#include + +#include +#include +#include + +class QListWidgetItem; +class QNetworkReply; +class QTemporaryFile; +class QUrl; + +namespace Ui { +class DocsetsDialog; +} + +namespace Zeal { + +namespace Registry { +class DocsetRegistry; +} // namespace Registry + +namespace Core { +class Application; +} + +class DocsetsDialog : public QDialog +{ + Q_OBJECT +public: + explicit DocsetsDialog(Core::Application *app, QWidget *parent = nullptr); + ~DocsetsDialog() override; + + void reject() override; + +private slots: + void addDashFeed(); + void updateSelectedDocsets(); + void updateAllDocsets(); + void removeSelectedDocsets(); + void updateDocsetFilter(const QString &filterString); + + void downloadCompleted(); + void downloadProgress(qint64 received, qint64 total); + + void extractionCompleted(const QString &filePath); + void extractionError(const QString &filePath, const QString &errorString); + void extractionProgress(const QString &filePath, qint64 extracted, qint64 total); + + void on_downloadDocsetButton_clicked(); + void loadDocsetList(); + +private: + enum DownloadType { + DownloadDashFeed, + DownloadDocset, + DownloadDocsetList + }; + + Ui::DocsetsDialog *ui = nullptr; + Core::Application *m_application = nullptr; + Registry::DocsetRegistry *m_docsetRegistry = nullptr; + + QList m_replies; + qint64 m_combinedTotal = 0; + qint64 m_combinedReceived = 0; + + // TODO: Create a special model + QMap m_availableDocsets; + QMap m_userFeeds; + + QHash m_tmpFiles; + + QListWidgetItem *findDocsetListItem(const QString &title) const; + bool updatesAvailable() const; + + QNetworkReply *download(const QUrl &url); + void cancelDownloads(); + + void downloadDocsetList(); + void processDocsetList(const QJsonArray &list); + + void downloadDashDocset(const QString &name); + void removeDocsets(const QStringList &names); + + void displayProgress(); + void resetProgress(); + + static inline int percent(qint64 fraction, qint64 total); + + static QString cacheLocation(const QString &fileName); +}; + +} // namespace Zeal + +#endif // DOCSETSDIALOG_H diff --git a/src/libs/ui/forms/docsetsdialog.ui b/src/libs/ui/forms/docsetsdialog.ui new file mode 100644 index 000000000..8bee1ed43 --- /dev/null +++ b/src/libs/ui/forms/docsetsdialog.ui @@ -0,0 +1,248 @@ + + + DocsetsDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 624 + 505 + + + + Zeal Options + + + + + + 0 + + + + Docsets + + + + + + Installed docsets + + + + + + + 16 + 16 + + + + + + + + + + Add feed + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Update + + + + + + + false + + + Update all + + + + + + + false + + + Remove + + + + + + + 0 + + + + + + + + + + + + Downloadable docsets + + + + + + + 16 + 16 + + + + + + + + Filter docsets + + + true + + + + + + + + + Last updated: + + + + + + + + + + + + + + Refresh + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + Download + + + + + + + + + <i>Docsets are provided by <a href="https://kapeli.com/dash">Dash</a>, the OS X Documentation Browser.</i> + + + Qt::RichText + + + true + + + + + + + + + + + + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + DocsetsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DocsetsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/libs/ui/forms/mainwindow.ui b/src/libs/ui/forms/mainwindow.ui index daebae94d..ab4d3a3a1 100644 --- a/src/libs/ui/forms/mainwindow.ui +++ b/src/libs/ui/forms/mainwindow.ui @@ -231,8 +231,15 @@ + + + &Tools + + + + @@ -327,6 +334,11 @@ &Find + + + &Docsets... + + diff --git a/src/libs/ui/forms/settingsdialog.ui b/src/libs/ui/forms/settingsdialog.ui index d01631368..c5cdd646d 100644 --- a/src/libs/ui/forms/settingsdialog.ui +++ b/src/libs/ui/forms/settingsdialog.ui @@ -393,173 +393,13 @@ - - - Installed docsets + + + Docsets are now available via the <b>Tools</b> menu. - - - - - - 16 - 16 - - - - - - - - - - Add feed - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - Update - - - - - - - false - - - Update all - - - - - - - false - - - Remove - - - - - - - 0 - - - - - - - - - - - - Downloadable docsets + + Qt::AlignCenter - - - - - - 16 - 16 - - - - - - - - Filter docsets - - - true - - - - - - - - - Last updated: - - - - - - - - - - - - - - Refresh - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - Download - - - - - - - - - <i>Docsets are provided by <a href="https://kapeli.com/dash">Dash</a>, the OS X Documentation Browser.</i> - - - Qt::RichText - - - true - - - - @@ -568,9 +408,6 @@ - - Qt::Horizontal - QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok diff --git a/src/libs/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp index 6d7c0226b..9a28fae32 100644 --- a/src/libs/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -25,6 +25,7 @@ #include "ui_mainwindow.h" #include "aboutdialog.h" +#include "docsetsdialog.h" #include "searchitemdelegate.h" #include "settingsdialog.h" #include "qxtglobalshortcut/qxtglobalshortcut.h" @@ -235,6 +236,12 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : connect(ui->actionBack, &QAction::triggered, ui->webView, &SearchableWebView::back); connect(ui->actionForward, &QAction::triggered, ui->webView, &SearchableWebView::forward); + // Tools Menu + connect(ui->actionDocsets, &QAction::triggered, [this]() { + QScopedPointer dialog(new DocsetsDialog(m_application, this)); + dialog->exec(); + }); + // Help Menu connect(ui->actionSubmitFeedback, &QAction::triggered, [this]() { QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/zealdocs/zeal/issues"))); diff --git a/src/libs/ui/settingsdialog.cpp b/src/libs/ui/settingsdialog.cpp index 6f6b797f0..78ca60b6c 100644 --- a/src/libs/ui/settingsdialog.cpp +++ b/src/libs/ui/settingsdialog.cpp @@ -24,26 +24,12 @@ #include "settingsdialog.h" #include "ui_settingsdialog.h" -#include "docsetlistitemdelegate.h" -#include "progressitemdelegate.h" - #include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include - -#include #ifdef USE_WEBENGINE #include @@ -55,87 +41,14 @@ typedef QWebEngineSettings QWebSettings; using namespace Zeal; -namespace { -const char ApiServerUrl[] = "http://api.zealdocs.org/v1"; -const char RedirectServerUrl[] = "https://go.zealdocs.org"; -// TODO: Each source plugin should have its own cache -const char DocsetListCacheFileName[] = "com.kapeli.json"; - -// TODO: Make the timeout period configurable -constexpr int CacheTimeout = 24 * 60 * 60 * 1000; // 24 hours in microseconds - -// QNetworkReply properties -const char DocsetNameProperty[] = "docsetName"; -const char DownloadTypeProperty[] = "downloadType"; -const char DownloadPreviousReceived[] = "downloadPreviousReceived"; -const char ListItemIndexProperty[] = "listItem"; -} - SettingsDialog::SettingsDialog(Core::Application *app, QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog()), - m_application(app), - m_docsetRegistry(app->docsetRegistry()) + m_application(app) { - using Registry::DocsetRegistry; - using Registry::ListModel; - ui->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); -#ifdef Q_OS_OSX - ui->availableDocsetList->setAttribute(Qt::WA_MacShowFocusRect, false); - ui->installedDocsetList->setAttribute(Qt::WA_MacShowFocusRect, false); -#endif - - ui->downloadableGroup->hide(); - ui->docsetsProgress->hide(); - - ui->installedDocsetList->setItemDelegate(new DocsetListItemDelegate(this)); - ui->installedDocsetList->setModel(new ListModel(app->docsetRegistry(), this)); - - ui->installedDocsetList->setSelectionMode(QAbstractItemView::ExtendedSelection); - QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); - connect(selectionModel, &QItemSelectionModel::selectionChanged, - [this, selectionModel]() { - if (!m_replies.isEmpty()) - return; - - ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); - - for (const QModelIndex &index : selectionModel->selectedIndexes()) { - if (index.data(ListModel::UpdateAvailableRole).toBool()) { - ui->updateSelectedDocsetsButton->setEnabled(true); - return; - } - } - ui->updateSelectedDocsetsButton->setEnabled(false); - }); - connect(ui->updateSelectedDocsetsButton, &QPushButton::clicked, - this, &SettingsDialog::updateSelectedDocsets); - connect(ui->updateAllDocsetsButton, &QPushButton::clicked, - this, &SettingsDialog::updateAllDocsets); - connect(ui->removeDocsetsButton, &QPushButton::clicked, - this, &SettingsDialog::removeSelectedDocsets); - connect(ui->docsetFilterInput, &QLineEdit::textEdited, - this, &SettingsDialog::updateDocsetFilter); - - ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); - connect(m_docsetRegistry, &DocsetRegistry::docsetRemoved, this, [this](const QString name) { - QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); - if (!item) - return; - - item->setHidden(false); - }); - connect(m_docsetRegistry, &DocsetRegistry::docsetAdded, this, [this](const QString name) { - QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); - if (!item) - return; - - item->setHidden(true); - }); - // Setup signals & slots connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::saveSettings); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &SettingsDialog::loadSettings); @@ -149,16 +62,6 @@ SettingsDialog::SettingsDialog(Core::Application *app, QWidget *parent) : QWebSettings::globalSettings()->setFontSize(QWebSettings::MinimumFontSize, value); }); - connect(ui->addFeedButton, &QPushButton::clicked, this, &SettingsDialog::addDashFeed); - connect(ui->refreshButton, &QPushButton::clicked, this, &SettingsDialog::downloadDocsetList); - - connect(m_application, &Core::Application::extractionCompleted, - this, &SettingsDialog::extractionCompleted); - connect(m_application, &Core::Application::extractionError, - this, &SettingsDialog::extractionError); - connect(m_application, &Core::Application::extractionProgress, - this, &SettingsDialog::extractionProgress); - loadSettings(); } @@ -167,375 +70,6 @@ SettingsDialog::~SettingsDialog() delete ui; } -void SettingsDialog::addDashFeed() -{ - QString clipboardText = QApplication::clipboard()->text(); - if (!clipboardText.startsWith(QLatin1String("dash-feed://"))) - clipboardText.clear(); - - QString feedUrl = QInputDialog::getText(this, QStringLiteral("Zeal"), tr("Feed URL:"), - QLineEdit::Normal, clipboardText); - if (feedUrl.isEmpty()) - return; - - if (feedUrl.startsWith(QLatin1String("dash-feed://"))) { - feedUrl = feedUrl.remove(0, 12); - feedUrl = QUrl::fromPercentEncoding(feedUrl.toUtf8()); - } - - QNetworkReply *reply = download(QUrl(feedUrl)); - reply->setProperty(DownloadTypeProperty, DownloadDashFeed); - connect(reply, &QNetworkReply::finished, this, &SettingsDialog::downloadCompleted); -} - -void SettingsDialog::updateSelectedDocsets() -{ - for (const QModelIndex &index : ui->installedDocsetList->selectionModel()->selectedIndexes()) { - if (!index.data(Registry::ListModel::UpdateAvailableRole).toBool()) - continue; - - downloadDashDocset(index.data(Registry::ListModel::DocsetNameRole).toString()); - } -} - -void SettingsDialog::updateAllDocsets() -{ - for (const Registry::Docset * const docset : m_docsetRegistry->docsets()) { - if (!docset->hasUpdate) - continue; - - downloadDashDocset(docset->name()); - } -} - -void SettingsDialog::removeSelectedDocsets() -{ - QItemSelectionModel *selectonModel = ui->installedDocsetList->selectionModel(); - if (!selectonModel->hasSelection()) - return; - - int ret; - if (selectonModel->selectedIndexes().count() == 1) { - const QString docsetTitle = selectonModel->selectedIndexes().first().data().toString(); - ret = QMessageBox::question(this, QStringLiteral("Zeal"), - tr("Remove %1 docset?").arg(docsetTitle)); - } else { - ret = QMessageBox::question(this, QStringLiteral("Zeal"), - tr("Remove %1 docsets?") - .arg(selectonModel->selectedIndexes().count())); - } - - if (ret == QMessageBox::No) - return; - - QStringList names; - for (const QModelIndex &index : selectonModel->selectedIndexes()) - names << index.data(Registry::ListModel::DocsetNameRole).toString(); - removeDocsets(names); -} - -void SettingsDialog::updateDocsetFilter(const QString &filterString) -{ - const bool doSearch = !filterString.simplified().isEmpty(); - - for (int i = 0; i < ui->availableDocsetList->count(); ++i) { - QListWidgetItem *item = ui->availableDocsetList->item(i); - - // Skip installed docsets - if (m_docsetRegistry->contains(item->data(Registry::ListModel::DocsetNameRole).toString())) - continue; - - item->setHidden(doSearch && !item->text().contains(filterString, Qt::CaseInsensitive)); - } -} - -/*! - \internal - Should be connected to all \l QNetworkReply::finished signals in order to process possible - HTTP-redirects correctly. -*/ -void SettingsDialog::downloadCompleted() -{ - QScopedPointer reply( - qobject_cast(sender())); - - m_replies.removeOne(reply.data()); - - if (reply->error() != QNetworkReply::NoError) { - if (reply->error() != QNetworkReply::OperationCanceledError) { - const int ret = QMessageBox::warning(this, QStringLiteral("Zeal"), reply->errorString(), - QMessageBox::Retry | QMessageBox::Default, - QMessageBox::Cancel | QMessageBox::Escape, - QMessageBox::NoButton); - - if (ret == QMessageBox::Retry) { - QNetworkReply *newReply = download(reply->request().url()); - - // Copy properties - newReply->setProperty(DocsetNameProperty, reply->property(DocsetNameProperty)); - newReply->setProperty(DownloadTypeProperty, reply->property(DownloadTypeProperty)); - newReply->setProperty(ListItemIndexProperty, - reply->property(ListItemIndexProperty)); - - connect(newReply, &QNetworkReply::finished, - this, &SettingsDialog::downloadCompleted); - return; - } - - bool ok; - QListWidgetItem *listItem = ui->availableDocsetList->item( - reply->property(ListItemIndexProperty).toInt(&ok)); - if (ok && listItem) - listItem->setData(ProgressItemDelegate::ShowProgressRole, false); - } - - if (m_replies.isEmpty()) - resetProgress(); - - return; - } - - QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - if (redirectUrl.isValid()) { - if (redirectUrl.isRelative()) - redirectUrl = reply->request().url().resolved(redirectUrl); - - // TODO: Verify if scheme can be missing - if (redirectUrl.scheme().isEmpty()) - redirectUrl.setScheme(reply->request().url().scheme()); - - QNetworkReply *newReply = download(redirectUrl); - - // Copy properties - newReply->setProperty(DocsetNameProperty, reply->property(DocsetNameProperty)); - newReply->setProperty(DownloadTypeProperty, reply->property(DownloadTypeProperty)); - newReply->setProperty(ListItemIndexProperty, reply->property(ListItemIndexProperty)); - - connect(newReply, &QNetworkReply::finished, this, &SettingsDialog::downloadCompleted); - - return; - } - - switch (reply->property(DownloadTypeProperty).toUInt()) { - case DownloadDocsetList: { - const QByteArray data = reply->readAll(); - - QScopedPointer file(new QFile(cacheLocation(DocsetListCacheFileName))); - if (file->open(QIODevice::WriteOnly)) - file->write(data); - - ui->lastUpdatedLabel->setText(QFileInfo(file->fileName()) - .lastModified().toString(Qt::SystemLocaleShortDate)); - - QJsonParseError jsonError; - const QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); - - if (jsonError.error != QJsonParseError::NoError) { - QMessageBox::warning(this, QStringLiteral("Zeal"), - tr("Corrupted docset list: ") + jsonError.errorString()); - break; - } - - processDocsetList(jsonDoc.array()); - resetProgress(); - break; - } - - case DownloadDashFeed: { - Registry::DocsetMetadata metadata - = Registry::DocsetMetadata::fromDashFeed(reply->request().url(), reply->readAll()); - - if (metadata.urls().isEmpty()) { - QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Invalid docset feed!")); - break; - } - - m_userFeeds[metadata.name()] = metadata; - QNetworkReply *reply = download(metadata.url()); - reply->setProperty(DocsetNameProperty, metadata.name()); - reply->setProperty(DownloadTypeProperty, DownloadDocset); - connect(reply, &QNetworkReply::finished, this, &SettingsDialog::downloadCompleted); - break; - } - - case DownloadDocset: { - const QString docsetName = reply->property(DocsetNameProperty).toString(); - const Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) - ? m_availableDocsets[docsetName] - : m_userFeeds[docsetName]; - - // TODO: Implement an explicit and verbose docset update logic - QDir dir(m_application->settings()->docsetPath); - const QString docsetDirName = docsetName + QLatin1String(".docset"); - if (dir.exists(docsetDirName)) { - m_docsetRegistry->remove(docsetName); - const QString tmpName = QStringLiteral(".toDelete") - + QString::number(QDateTime::currentMSecsSinceEpoch()); - dir.rename(docsetDirName, tmpName); - QtConcurrent::run([=] { - QDir d(dir); - if (!d.cd(tmpName)) - return; - d.removeRecursively(); - }); - } - - QTemporaryFile *tmpFile = m_tmpFiles[docsetName]; - if (!tmpFile) { - tmpFile = new QTemporaryFile(this); - tmpFile->open(); - m_tmpFiles.insert(docsetName, tmpFile); - } - - while (reply->bytesAvailable()) - tmpFile->write(reply->read(1024 * 1024)); // Use small chunks - tmpFile->close(); - - QListWidgetItem *item = findDocsetListItem(metadata.title()); - if (item) { - item->setData(ProgressItemDelegate::ValueRole, 0); - item->setData(ProgressItemDelegate::FormatRole, tr("Installing: %p%")); - } - - m_tmpFiles.insert(metadata.name(), tmpFile); - m_application->extract(tmpFile->fileName(), m_application->settings()->docsetPath, - metadata.name() + QLatin1String(".docset")); - break; - } - } - - // If all enqueued downloads have finished executing - if (m_replies.isEmpty()) - resetProgress(); -} - -// creates a total download progress for multiple QNetworkReplies -void SettingsDialog::downloadProgress(qint64 received, qint64 total) -{ - // Don't show progress for non-docset pages - if (total == -1 || received < 10240) - return; - - QNetworkReply *reply = qobject_cast(sender()); - if (!reply || !reply->isOpen()) - return; - - if (reply->property(DownloadTypeProperty).toInt() == DownloadDocset) { - const QString docsetName = reply->property(DocsetNameProperty).toString(); - - QTemporaryFile *tmpFile = m_tmpFiles[docsetName]; - if (!tmpFile) { - tmpFile = new QTemporaryFile(this); - tmpFile->open(); - m_tmpFiles.insert(docsetName, tmpFile); - } - - tmpFile->write(reply->read(received)); - } - - // Try to get the item associated to the request - QListWidgetItem *item - = ui->availableDocsetList->item(reply->property(ListItemIndexProperty).toInt()); - if (item) - item->setData(ProgressItemDelegate::ValueRole, percent(received, total)); - - qint64 previousReceived = 0; - const QVariant previousReceivedVariant = reply->property(DownloadPreviousReceived); - if (!previousReceivedVariant.isValid()) - m_combinedTotal += total; - else - previousReceived = previousReceivedVariant.toLongLong(); - - m_combinedReceived += received - previousReceived; - reply->setProperty(DownloadPreviousReceived, received); - - displayProgress(); -} - -void SettingsDialog::extractionCompleted(const QString &filePath) -{ - QString docsetName; - - // FIXME: Come up with a better approach - for (const QString &key : m_tmpFiles.keys()) { - if (m_tmpFiles[key]->fileName() == filePath) { - docsetName = key; - break; - } - } - - const QDir dataDir(m_application->settings()->docsetPath); - const QString docsetPath = dataDir.absoluteFilePath(docsetName + QLatin1String(".docset")); - - // Write metadata about docset - Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) - ? m_availableDocsets[docsetName] - : m_userFeeds[docsetName]; - metadata.save(docsetPath, metadata.latestVersion()); - - m_docsetRegistry->addDocset(docsetPath); - - QListWidgetItem *listItem = findDocsetListItem(metadata.title()); - if (listItem) { - listItem->setHidden(true); - listItem->setCheckState(Qt::Unchecked); - listItem->setData(ProgressItemDelegate::ShowProgressRole, false); - } - resetProgress(); - delete m_tmpFiles.take(docsetName); -} - -void SettingsDialog::extractionError(const QString &filePath, const QString &errorString) -{ - const QString docsetName = QFileInfo(filePath).baseName() + QLatin1String(".docset"); - QMessageBox::warning(this, QStringLiteral("Zeal"), - tr("Cannot extract docset %1: %2").arg(docsetName, errorString)); - // TODO: Update list item state (hide progress bar) - delete m_tmpFiles.take(docsetName); -} - -void SettingsDialog::extractionProgress(const QString &filePath, qint64 extracted, qint64 total) -{ - QString docsetName; - - // FIXME: Come up with a better approach - for (const QString &key : m_tmpFiles.keys()) { - if (m_tmpFiles[key]->fileName() == filePath) { - docsetName = key; - break; - } - } - - Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) - ? m_availableDocsets[docsetName] - : m_userFeeds[docsetName]; - - QListWidgetItem *listItem = findDocsetListItem(metadata.title()); - if (listItem) - listItem->setData(ProgressItemDelegate::ValueRole, percent(extracted, total)); -} - -void SettingsDialog::on_downloadDocsetButton_clicked() -{ - if (!m_replies.isEmpty()) { - cancelDownloads(); - return; - } - - // Find each checked item, and create a NetworkRequest for it. - for (int i = 0; i < ui->availableDocsetList->count(); ++i) { - QListWidgetItem *item = ui->availableDocsetList->item(i); - if (item->checkState() != Qt::Checked) - continue; - - item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); - item->setData(ProgressItemDelegate::ValueRole, 0); - item->setData(ProgressItemDelegate::ShowProgressRole, true); - - downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); - } -} - void SettingsDialog::on_storageButton_clicked() { const QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), @@ -545,230 +79,6 @@ void SettingsDialog::on_storageButton_clicked() } -void SettingsDialog::on_tabWidget_currentChanged(int current) -{ - if (ui->tabWidget->widget(current) != ui->docsetsTab || ui->availableDocsetList->count()) - return; - - const QFileInfo fi(cacheLocation(DocsetListCacheFileName)); - - if (!fi.exists() || fi.lastModified().msecsTo(QDateTime::currentDateTime()) > CacheTimeout) { - downloadDocsetList(); - return; - } - - QScopedPointer file(new QFile(fi.filePath())); - if (!file->open(QIODevice::ReadOnly)) { - downloadDocsetList(); - return; - } - - QJsonParseError jsonError; - const QJsonDocument jsonDoc = QJsonDocument::fromJson(file->readAll(), &jsonError); - - if (jsonError.error != QJsonParseError::NoError) { - downloadDocsetList(); - return; - } - - // TODO: Show more user friendly labels, like "5 hours ago" - ui->lastUpdatedLabel->setText(fi.lastModified().toString(Qt::SystemLocaleShortDate)); - processDocsetList(jsonDoc.array()); -} - -QListWidgetItem *SettingsDialog::findDocsetListItem(const QString &title) const -{ - for (int i = 0; i < ui->availableDocsetList->count(); ++i) { - QListWidgetItem *item = ui->availableDocsetList->item(i); - - if (item->text() == title) - return item; - } - - return nullptr; -} - -bool SettingsDialog::updatesAvailable() const -{ - for (Registry::Docset *docset : m_docsetRegistry->docsets()) { - if (docset->hasUpdate) - return true; - } - - return false; -} - -QNetworkReply *SettingsDialog::download(const QUrl &url) -{ - displayProgress(); - - QNetworkReply *reply = m_application->download(url); - connect(reply, &QNetworkReply::downloadProgress, this, &SettingsDialog::downloadProgress); - m_replies.append(reply); - - // Installed docsets - ui->addFeedButton->setEnabled(false); - ui->updateSelectedDocsetsButton->setEnabled(false); - ui->updateAllDocsetsButton->setEnabled(false); - ui->removeDocsetsButton->setEnabled(false); - - // Available docsets - ui->refreshButton->setEnabled(false); - ui->downloadDocsetButton->setText(tr("Stop downloads")); - - return reply; -} - -void SettingsDialog::cancelDownloads() -{ - for (QNetworkReply *reply : m_replies) { - // Hide progress bar - QListWidgetItem *listItem - = ui->availableDocsetList->item(reply->property(ListItemIndexProperty).toInt()); - if (listItem) - listItem->setData(ProgressItemDelegate::ShowProgressRole, false); - - if (reply->property(DownloadTypeProperty).toInt() == DownloadDocset) - delete m_tmpFiles.take(reply->property(DocsetNameProperty).toString()); - - reply->abort(); - } - resetProgress(); -} - -void SettingsDialog::downloadDocsetList() -{ - ui->availableDocsetList->clear(); - m_availableDocsets.clear(); - - QNetworkReply *reply = download(QUrl(ApiServerUrl + QLatin1String("/docsets"))); - reply->setProperty(DownloadTypeProperty, DownloadDocsetList); - connect(reply, &QNetworkReply::finished, this, &SettingsDialog::downloadCompleted); -} - -void SettingsDialog::processDocsetList(const QJsonArray &list) -{ - for (const QJsonValue &v : list) { - QJsonObject docsetJson = v.toObject(); - - Registry::DocsetMetadata metadata(docsetJson); - m_availableDocsets.insert(metadata.name(), metadata); - } - - // TODO: Move into dedicated method - for (const Registry::DocsetMetadata &metadata : m_availableDocsets) { - QListWidgetItem *listItem - = new QListWidgetItem(metadata.icon(), metadata.title(), ui->availableDocsetList); - listItem->setData(Registry::ListModel::DocsetNameRole, metadata.name()); - listItem->setCheckState(Qt::Unchecked); - - if (m_docsetRegistry->contains(metadata.name())) { - listItem->setHidden(true); - - Registry::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 SettingsDialog::downloadDashDocset(const QString &name) -{ - if (!m_availableDocsets.contains(name)) - return; - - const QString urlString = RedirectServerUrl + QStringLiteral("/d/com.kapeli/%1/latest"); - QNetworkReply *reply = download(QUrl(urlString.arg(name))); - reply->setProperty(DocsetNameProperty, name); - reply->setProperty(DownloadTypeProperty, DownloadDocset); - reply->setProperty(ListItemIndexProperty, - ui->availableDocsetList->row(findDocsetListItem(m_availableDocsets[name].title()))); - - connect(reply, &QNetworkReply::finished, this, &SettingsDialog::downloadCompleted); -} - -void SettingsDialog::removeDocsets(const QStringList &names) -{ - for (const QString &name : names) { - const QString title = m_docsetRegistry->docset(name)->title(); - m_docsetRegistry->remove(name); - - const QDir dataDir(m_application->settings()->docsetPath); - if (dataDir.exists()) { - ui->docsetsProgress->show(); - ui->removeDocsetsButton->setEnabled(false); - displayProgress(); - - QFuture future = QtConcurrent::run([=] { - QDir docsetDir(dataDir); - return docsetDir.cd(name + QLatin1String(".docset")) - && docsetDir.removeRecursively(); - }); - QFutureWatcher *watcher = new QFutureWatcher(); - watcher->setFuture(future); - connect(watcher, &QFutureWatcher::finished, [=] { - if (!watcher->result()) { - QMessageBox::warning(this, QStringLiteral("Zeal"), - tr("Cannot delete docset %1!").arg(title)); - } - - resetProgress(); - - QListWidgetItem *listItem = findDocsetListItem(title); - if (listItem) - listItem->setHidden(false); - - watcher->deleteLater(); - }); - } - } -} - -void SettingsDialog::displayProgress() -{ - ui->docsetsProgress->setValue(percent(m_combinedReceived, m_combinedTotal)); - ui->docsetsProgress->setMaximum(100); - ui->docsetsProgress->setVisible(!m_replies.isEmpty()); -} - -void SettingsDialog::resetProgress() -{ - if (!m_replies.isEmpty()) - return; - - m_combinedReceived = 0; - m_combinedTotal = 0; - displayProgress(); - - // Installed docsets - ui->addFeedButton->setEnabled(true); - QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); - bool hasSelectedUpdates = false; - for (const QModelIndex &index : selectionModel->selectedIndexes()) { - if (index.data(Registry::ListModel::UpdateAvailableRole).toBool()) { - hasSelectedUpdates = true; - break; - } - } - ui->updateSelectedDocsetsButton->setEnabled(hasSelectedUpdates); - ui->updateAllDocsetsButton->setEnabled(updatesAvailable()); - ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); - - // Available docsets - ui->refreshButton->setEnabled(true); - ui->downloadDocsetButton->setText(tr("Download")); -} - void SettingsDialog::loadSettings() { const Core::Settings * const settings = m_application->settings(); @@ -828,7 +138,7 @@ void SettingsDialog::saveSettings() if (QDir::fromNativeSeparators(ui->storageEdit->text()) != settings->docsetPath) { settings->docsetPath = QDir::fromNativeSeparators(ui->storageEdit->text()); - m_docsetRegistry->init(settings->docsetPath); + m_application->docsetRegistry()->init(settings->docsetPath); } // Network Tab @@ -848,24 +158,3 @@ void SettingsDialog::saveSettings() settings->save(); } - -int SettingsDialog::percent(qint64 fraction, qint64 total) -{ - if (!total) - return 0; - - return static_cast(fraction / static_cast(total) * 100); -} - -QString SettingsDialog::cacheLocation(const QString &fileName) -{ -#ifndef PORTABLE_BUILD - const QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); -#else - const QDir cacheDir(QCoreApplication::applicationDirPath() + QLatin1String("/cache")); -#endif - // TODO: Report error - QDir().mkpath(cacheDir.path()); - - return cacheDir.filePath(fileName); -} diff --git a/src/libs/ui/settingsdialog.h b/src/libs/ui/settingsdialog.h index 5d127b885..a6d134911 100644 --- a/src/libs/ui/settingsdialog.h +++ b/src/libs/ui/settingsdialog.h @@ -24,16 +24,7 @@ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H -#include - #include -#include -#include - -class QListWidgetItem; -class QNetworkReply; -class QTemporaryFile; -class QUrl; namespace Ui { class SettingsDialog; @@ -41,10 +32,6 @@ class SettingsDialog; namespace Zeal { -namespace Registry { -class DocsetRegistry; -} // namespace Registry - namespace Core { class Application; } @@ -57,64 +44,14 @@ class SettingsDialog : public QDialog ~SettingsDialog() override; private slots: - void addDashFeed(); - void updateSelectedDocsets(); - void updateAllDocsets(); - void removeSelectedDocsets(); - void updateDocsetFilter(const QString &filterString); - - void downloadCompleted(); - void downloadProgress(qint64 received, qint64 total); - - void extractionCompleted(const QString &filePath); - void extractionError(const QString &filePath, const QString &errorString); - void extractionProgress(const QString &filePath, qint64 extracted, qint64 total); - - void on_downloadDocsetButton_clicked(); void on_storageButton_clicked(); - void on_tabWidget_currentChanged(int current); private: - enum DownloadType { - DownloadDashFeed, - DownloadDocset, - DownloadDocsetList - }; - Ui::SettingsDialog *ui = nullptr; Core::Application *m_application = nullptr; - Registry::DocsetRegistry *m_docsetRegistry = nullptr; - - QList m_replies; - qint64 m_combinedTotal = 0; - qint64 m_combinedReceived = 0; - - // TODO: Create a special model - QMap m_availableDocsets; - QMap m_userFeeds; - - QHash m_tmpFiles; - - QListWidgetItem *findDocsetListItem(const QString &title) const; - bool updatesAvailable() const; - - QNetworkReply *download(const QUrl &url); - void cancelDownloads(); - - void downloadDocsetList(); - void processDocsetList(const QJsonArray &list); - - void downloadDashDocset(const QString &name); - void removeDocsets(const QStringList &names); - - void displayProgress(); - void resetProgress(); void loadSettings(); void saveSettings(); - static inline int percent(qint64 fraction, qint64 total); - - static QString cacheLocation(const QString &fileName); }; } // namespace Zeal From 81357c3bbf796832ca2276d294eb2b45847c8675 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 21:47:13 -0400 Subject: [PATCH 225/273] registry: Remove QDebug include --- src/libs/registry/docsetregistry.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/registry/docsetregistry.cpp b/src/libs/registry/docsetregistry.cpp index 0994ec9d5..c91f374eb 100644 --- a/src/libs/registry/docsetregistry.cpp +++ b/src/libs/registry/docsetregistry.cpp @@ -26,7 +26,6 @@ #include "cancellationtoken.h" #include "searchresult.h" -#include #include #include From 3ebbf497d284ff6a8b0d3d0db7e24e8d8c77eebf Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 22:05:21 -0400 Subject: [PATCH 226/273] qmake: Fix PRE_TARGETDEPS --- src/app/app.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/app.pro b/src/app/app.pro index 6f2d5551d..540aa1566 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -33,7 +33,7 @@ LIBS += -lCore -lUi -lRegistry -lUtil for(lib_dir, $$list($$files($$SRC_ROOT/src/libs/*))) { !equals(lib_dir, $$SRC_ROOT/src/libs/libs.pro) { include($$lib_dir/$$basename(lib_dir).pri) - PRE_TARGETDEPS += $$BUILD_ROOT/.lib/$$ZEAL_LIB_NAME.a -# LIBS += -l$$ZEAL_LIB_NAME + PRE_TARGETDEPS += $$BUILD_ROOT/.lib/lib$${ZEAL_LIB_NAME}.a + # LIBS += -l$$ZEAL_LIB_NAME } } From c37607019141b7b9b68b66452166219c2b8c0b60 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 22:18:55 -0400 Subject: [PATCH 227/273] qmake: Set QMAKE_LIB only for Qt versions below 5.6.0 --- qmake/common.pri | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qmake/common.pri b/qmake/common.pri index ffae4815b..1b15edece 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -19,7 +19,9 @@ DEFINES *= QT_NO_URL_CAST_FROM_STRING # Workaround for AppVeyor: Do not warn if the library had to be created. # Based on https://codereview.qt-project.org/150326 -win32-g++:QMAKE_LIB = ar -rc +win32-g++:lessThan(QT_VERSION, "5.6.0") { + QMAKE_LIB = ar -rc +} # Keep build directory clean MOC_DIR = $$BUILD_ROOT/.moc From c9ec84fcb3ad41f07c6176882ed0f90e425346e7 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 11 Sep 2016 23:55:25 -0400 Subject: [PATCH 228/273] app: Do not use ::exit() inside main() --- src/app/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 6c27c9cad..0ca13fd54 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -191,11 +191,11 @@ int main(int argc, char *argv[]) if (clParams.unregisterProtocolHandlers) { unregisterProtocolHandlers(protocols); - ::exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } else { registerProtocolHandlers(protocols, clParams.registerProtocolHandlers); if (clParams.registerProtocolHandlers) - ::exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } #endif From b68790a7d3148b7564ab6ea54c4597fd9d7a38c4 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 12 Sep 2016 22:29:24 -0400 Subject: [PATCH 229/273] ui: Fix handling of extraction errors in DocsetsDialog --- src/libs/ui/docsetsdialog.cpp | 46 ++++++++++++++++++++--------------- src/libs/ui/docsetsdialog.h | 3 +++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index cbd360681..7c55a0d1c 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -443,15 +443,7 @@ void DocsetsDialog::downloadProgress(qint64 received, qint64 total) void DocsetsDialog::extractionCompleted(const QString &filePath) { - QString docsetName; - - // FIXME: Come up with a better approach - for (const QString &key : m_tmpFiles.keys()) { - if (m_tmpFiles[key]->fileName() == filePath) { - docsetName = key; - break; - } - } + const QString docsetName = docsetNameForTmpFilePath(filePath); const QDir dataDir(m_application->settings()->docsetPath); const QString docsetPath = dataDir.absoluteFilePath(docsetName + QLatin1String(".docset")); @@ -470,30 +462,33 @@ void DocsetsDialog::extractionCompleted(const QString &filePath) listItem->setCheckState(Qt::Unchecked); listItem->setData(ProgressItemDelegate::ShowProgressRole, false); } + resetProgress(); delete m_tmpFiles.take(docsetName); } void DocsetsDialog::extractionError(const QString &filePath, const QString &errorString) { - const QString docsetName = QFileInfo(filePath).baseName() + QLatin1String(".docset"); + const QString docsetName = docsetNameForTmpFilePath(filePath); + QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Cannot extract docset %1: %2").arg(docsetName, errorString)); - // TODO: Update list item state (hide progress bar) + + const Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) + ? m_availableDocsets[docsetName] + : m_userFeeds[docsetName]; + + QListWidgetItem *listItem = findDocsetListItem(metadata.title()); + if (listItem) + listItem->setData(ProgressItemDelegate::ShowProgressRole, false); + + resetProgress(); delete m_tmpFiles.take(docsetName); } void DocsetsDialog::extractionProgress(const QString &filePath, qint64 extracted, qint64 total) { - QString docsetName; - - // FIXME: Come up with a better approach - for (const QString &key : m_tmpFiles.keys()) { - if (m_tmpFiles[key]->fileName() == filePath) { - docsetName = key; - break; - } - } + const QString docsetName = docsetNameForTmpFilePath(filePath); Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) ? m_availableDocsets[docsetName] @@ -745,6 +740,17 @@ void DocsetsDialog::resetProgress() ui->downloadDocsetButton->setText(tr("Download")); } +QString DocsetsDialog::docsetNameForTmpFilePath(const QString &filePath) const +{ + for (const QString &key : m_tmpFiles.keys()) { + if (m_tmpFiles[key]->fileName() == filePath) { + return key; + } + } + + return QString(); +} + int DocsetsDialog::percent(qint64 fraction, qint64 total) { if (!total) diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index 909797e76..6ccc78a16 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -111,6 +111,9 @@ private slots: void displayProgress(); void resetProgress(); + // FIXME: Come up with a better approach + QString docsetNameForTmpFilePath(const QString &filePath) const; + static inline int percent(qint64 fraction, qint64 total); static QString cacheLocation(const QString &fileName); From 6b1349cdcea0f9e5476abafd56da037eb5c526cb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 12 Sep 2016 22:44:29 -0400 Subject: [PATCH 230/273] ui: Optimize lookups in the available docset list --- src/libs/ui/docsetsdialog.cpp | 36 ++++++++++++----------------------- src/libs/ui/docsetsdialog.h | 2 +- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 7c55a0d1c..d791f458b 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -112,14 +112,14 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); connect(m_docsetRegistry, &DocsetRegistry::docsetRemoved, this, [this](const QString name) { - QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); + QListWidgetItem *item = findDocsetListItem(name); if (!item) return; item->setHidden(false); }); connect(m_docsetRegistry, &DocsetRegistry::docsetAdded, this, [this](const QString name) { - QListWidgetItem *item = findDocsetListItem(m_availableDocsets[name].title()); + QListWidgetItem *item = findDocsetListItem(name); if (!item) return; @@ -349,9 +349,6 @@ void DocsetsDialog::downloadCompleted() case DownloadDocset: { const QString docsetName = reply->property(DocsetNameProperty).toString(); - const Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) - ? m_availableDocsets[docsetName] - : m_userFeeds[docsetName]; // TODO: Implement an explicit and verbose docset update logic QDir dir(m_application->settings()->docsetPath); @@ -380,15 +377,15 @@ void DocsetsDialog::downloadCompleted() tmpFile->write(reply->read(1024 * 1024)); // Use small chunks tmpFile->close(); - QListWidgetItem *item = findDocsetListItem(metadata.title()); + QListWidgetItem *item = findDocsetListItem(docsetName); if (item) { item->setData(ProgressItemDelegate::ValueRole, 0); item->setData(ProgressItemDelegate::FormatRole, tr("Installing: %p%")); } - m_tmpFiles.insert(metadata.name(), tmpFile); + m_tmpFiles.insert(docsetName, tmpFile); m_application->extract(tmpFile->fileName(), m_application->settings()->docsetPath, - metadata.name() + QLatin1String(".docset")); + docsetName + QLatin1String(".docset")); break; } } @@ -456,7 +453,7 @@ void DocsetsDialog::extractionCompleted(const QString &filePath) m_docsetRegistry->addDocset(docsetPath); - QListWidgetItem *listItem = findDocsetListItem(metadata.title()); + QListWidgetItem *listItem = findDocsetListItem(docsetName); if (listItem) { listItem->setHidden(true); listItem->setCheckState(Qt::Unchecked); @@ -474,11 +471,7 @@ void DocsetsDialog::extractionError(const QString &filePath, const QString &erro QMessageBox::warning(this, QStringLiteral("Zeal"), tr("Cannot extract docset %1: %2").arg(docsetName, errorString)); - const Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) - ? m_availableDocsets[docsetName] - : m_userFeeds[docsetName]; - - QListWidgetItem *listItem = findDocsetListItem(metadata.title()); + QListWidgetItem *listItem = findDocsetListItem(docsetName); if (listItem) listItem->setData(ProgressItemDelegate::ShowProgressRole, false); @@ -489,12 +482,7 @@ void DocsetsDialog::extractionError(const QString &filePath, const QString &erro void DocsetsDialog::extractionProgress(const QString &filePath, qint64 extracted, qint64 total) { const QString docsetName = docsetNameForTmpFilePath(filePath); - - Registry::DocsetMetadata metadata = m_availableDocsets.contains(docsetName) - ? m_availableDocsets[docsetName] - : m_userFeeds[docsetName]; - - QListWidgetItem *listItem = findDocsetListItem(metadata.title()); + QListWidgetItem *listItem = findDocsetListItem(docsetName); if (listItem) listItem->setData(ProgressItemDelegate::ValueRole, percent(extracted, total)); } @@ -547,12 +535,12 @@ void DocsetsDialog::loadDocsetList() processDocsetList(jsonDoc.array()); } -QListWidgetItem *DocsetsDialog::findDocsetListItem(const QString &title) const +QListWidgetItem *DocsetsDialog::findDocsetListItem(const QString &name) const { for (int i = 0; i < ui->availableDocsetList->count(); ++i) { QListWidgetItem *item = ui->availableDocsetList->item(i); - if (item->text() == title) + if (item->data(Registry::ListModel::DocsetNameRole).toString() == name) return item; } @@ -663,7 +651,7 @@ void DocsetsDialog::downloadDashDocset(const QString &name) reply->setProperty(DocsetNameProperty, name); reply->setProperty(DownloadTypeProperty, DownloadDocset); reply->setProperty(ListItemIndexProperty, - ui->availableDocsetList->row(findDocsetListItem(m_availableDocsets[name].title()))); + ui->availableDocsetList->row(findDocsetListItem(name))); connect(reply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); } @@ -695,7 +683,7 @@ void DocsetsDialog::removeDocsets(const QStringList &names) resetProgress(); - QListWidgetItem *listItem = findDocsetListItem(title); + QListWidgetItem *listItem = findDocsetListItem(name); if (listItem) listItem->setHidden(false); diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index 6ccc78a16..f394b1c45 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -96,7 +96,7 @@ private slots: QHash m_tmpFiles; - QListWidgetItem *findDocsetListItem(const QString &title) const; + QListWidgetItem *findDocsetListItem(const QString &name) const; bool updatesAvailable() const; QNetworkReply *download(const QUrl &url); From c835790453796724964c4997d6640942458674f9 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 12 Sep 2016 23:13:14 -0400 Subject: [PATCH 231/273] ui: Fix DocsetsDialog window title --- src/libs/ui/forms/docsetsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ui/forms/docsetsdialog.ui b/src/libs/ui/forms/docsetsdialog.ui index 8bee1ed43..7224d2195 100644 --- a/src/libs/ui/forms/docsetsdialog.ui +++ b/src/libs/ui/forms/docsetsdialog.ui @@ -14,7 +14,7 @@ - Zeal Options + Docsets From bc3ddd7776f9b3c63010057a4690175006db599d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 12 Sep 2016 23:36:27 -0400 Subject: [PATCH 232/273] ui: Allow to double click a docset to download --- src/libs/ui/docsetsdialog.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index d791f458b..9040786a6 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -111,6 +111,20 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : this, &DocsetsDialog::updateDocsetFilter); ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); + connect(ui->availableDocsetList, &QListWidget::itemActivated, + this, [this](QListWidgetItem *item) { + + // Do nothing if download is already in progress + if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) + return; + + item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); + item->setData(ProgressItemDelegate::ValueRole, 0); + item->setData(ProgressItemDelegate::ShowProgressRole, true); + + downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); + }); + connect(m_docsetRegistry, &DocsetRegistry::docsetRemoved, this, [this](const QString name) { QListWidgetItem *item = findDocsetListItem(name); if (!item) From 1bde003f4ae165d83dd8897d8a838e4ce3ed6f0e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 13 Sep 2016 21:55:50 -0400 Subject: [PATCH 233/273] ui: Unify sizes of Preferences and Docsets dialogs --- src/libs/ui/forms/docsetsdialog.ui | 4 ++-- src/libs/ui/forms/settingsdialog.ui | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/ui/forms/docsetsdialog.ui b/src/libs/ui/forms/docsetsdialog.ui index 7224d2195..36c30d730 100644 --- a/src/libs/ui/forms/docsetsdialog.ui +++ b/src/libs/ui/forms/docsetsdialog.ui @@ -9,8 +9,8 @@ 0 0 - 624 - 505 + 600 + 500 diff --git a/src/libs/ui/forms/settingsdialog.ui b/src/libs/ui/forms/settingsdialog.ui index c5cdd646d..4bc79ad32 100644 --- a/src/libs/ui/forms/settingsdialog.ui +++ b/src/libs/ui/forms/settingsdialog.ui @@ -9,8 +9,8 @@ 0 0 - 624 - 505 + 600 + 500 From 6f79cffb346840940643da53a1c1c6dc65bf3537 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 13 Sep 2016 21:57:35 -0400 Subject: [PATCH 234/273] ui: Show installed and available docsets on different tabs --- src/libs/ui/docsetsdialog.cpp | 63 +++--- src/libs/ui/docsetsdialog.h | 3 +- src/libs/ui/forms/docsetsdialog.ui | 341 +++++++++++++++-------------- 3 files changed, 212 insertions(+), 195 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 9040786a6..a42ef291c 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -79,7 +79,8 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : ui->installedDocsetList->setAttribute(Qt::WA_MacShowFocusRect, false); #endif - ui->docsetsProgress->hide(); + ui->combinedProgressBar->hide(); + ui->cancelButton->hide(); ui->installedDocsetList->setItemDelegate(new DocsetListItemDelegate(this)); ui->installedDocsetList->setModel(new ListModel(app->docsetRegistry(), this)); @@ -140,7 +141,6 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : item->setHidden(true); }); - // Setup signals & slots connect(ui->addFeedButton, &QPushButton::clicked, this, &DocsetsDialog::addDashFeed); connect(ui->refreshButton, &QPushButton::clicked, this, &DocsetsDialog::downloadDocsetList); @@ -151,6 +151,8 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : connect(m_application, &Core::Application::extractionProgress, this, &DocsetsDialog::extractionProgress); + connect(ui->cancelButton, &QPushButton::clicked, this, &DocsetsDialog::cancelDownloads); + loadDocsetList(); } @@ -449,7 +451,7 @@ void DocsetsDialog::downloadProgress(qint64 received, qint64 total) m_combinedReceived += received - previousReceived; reply->setProperty(DownloadPreviousReceived, received); - displayProgress(); + updateCombinedProgress(); } void DocsetsDialog::extractionCompleted(const QString &filePath) @@ -503,17 +505,16 @@ void DocsetsDialog::extractionProgress(const QString &filePath, qint64 extracted void DocsetsDialog::on_downloadDocsetButton_clicked() { - if (!m_replies.isEmpty()) { - cancelDownloads(); - return; - } - // Find each checked item, and create a NetworkRequest for it. for (int i = 0; i < ui->availableDocsetList->count(); ++i) { QListWidgetItem *item = ui->availableDocsetList->item(i); if (item->checkState() != Qt::Checked) continue; + // Do nothing if download is already in progress + if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) + return; + item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); item->setData(ProgressItemDelegate::ValueRole, 0); item->setData(ProgressItemDelegate::ShowProgressRole, true); @@ -573,8 +574,6 @@ bool DocsetsDialog::updatesAvailable() const QNetworkReply *DocsetsDialog::download(const QUrl &url) { - displayProgress(); - QNetworkReply *reply = m_application->download(url); connect(reply, &QNetworkReply::downloadProgress, this, &DocsetsDialog::downloadProgress); m_replies.append(reply); @@ -587,7 +586,8 @@ QNetworkReply *DocsetsDialog::download(const QUrl &url) // Available docsets ui->refreshButton->setEnabled(false); - ui->downloadDocsetButton->setText(tr("Stop downloads")); + + updateCombinedProgress(); return reply; } @@ -650,9 +650,6 @@ void DocsetsDialog::processDocsetList(const QJsonArray &list) } ui->installedDocsetList->reset(); - - if (!m_availableDocsets.isEmpty()) - ui->downloadableGroup->show(); } void DocsetsDialog::downloadDashDocset(const QString &name) @@ -673,20 +670,24 @@ void DocsetsDialog::downloadDashDocset(const QString &name) void DocsetsDialog::removeDocsets(const QStringList &names) { for (const QString &name : names) { + if (m_docsetsBeingDeleted.contains(name)) + continue; + + m_docsetsBeingDeleted << name; + const QString title = m_docsetRegistry->docset(name)->title(); m_docsetRegistry->remove(name); const QDir dataDir(m_application->settings()->docsetPath); if (dataDir.exists()) { - ui->docsetsProgress->show(); - ui->removeDocsetsButton->setEnabled(false); - displayProgress(); + updateCombinedProgress(); QFuture future = QtConcurrent::run([=] { QDir docsetDir(dataDir); return docsetDir.cd(name + QLatin1String(".docset")) && docsetDir.removeRecursively(); }); + QFutureWatcher *watcher = new QFutureWatcher(); watcher->setFuture(future); connect(watcher, &QFutureWatcher::finished, [=] { @@ -695,23 +696,33 @@ void DocsetsDialog::removeDocsets(const QStringList &names) tr("Cannot delete docset %1!").arg(title)); } - resetProgress(); - QListWidgetItem *listItem = findDocsetListItem(name); if (listItem) listItem->setHidden(false); watcher->deleteLater(); + + m_docsetsBeingDeleted.removeOne(name); + + updateCombinedProgress(); }); } } } -void DocsetsDialog::displayProgress() +void DocsetsDialog::updateCombinedProgress() { - ui->docsetsProgress->setValue(percent(m_combinedReceived, m_combinedTotal)); - ui->docsetsProgress->setMaximum(100); - ui->docsetsProgress->setVisible(!m_replies.isEmpty()); + if (m_replies.isEmpty() && m_tmpFiles.isEmpty() && m_docsetsBeingDeleted.isEmpty()) { + ui->cancelButton->hide(); + ui->combinedProgressBar->hide(); + ui->combinedProgressBar->setMaximum(100); + ui->combinedProgressBar->setValue(0); + return; + } + + ui->combinedProgressBar->show(); + ui->combinedProgressBar->setValue(percent(m_combinedReceived, m_combinedTotal)); + ui->cancelButton->show(); } void DocsetsDialog::resetProgress() @@ -719,9 +730,12 @@ void DocsetsDialog::resetProgress() if (!m_replies.isEmpty()) return; + ui->cancelButton->hide(); + ui->combinedProgressBar->hide(); + ui->combinedProgressBar->setValue(0); + m_combinedReceived = 0; m_combinedTotal = 0; - displayProgress(); // Installed docsets ui->addFeedButton->setEnabled(true); @@ -739,7 +753,6 @@ void DocsetsDialog::resetProgress() // Available docsets ui->refreshButton->setEnabled(true); - ui->downloadDocsetButton->setText(tr("Download")); } QString DocsetsDialog::docsetNameForTmpFilePath(const QString &filePath) const diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index f394b1c45..a6bc3edc4 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -95,6 +95,7 @@ private slots: QMap m_userFeeds; QHash m_tmpFiles; + QStringList m_docsetsBeingDeleted; QListWidgetItem *findDocsetListItem(const QString &name) const; bool updatesAvailable() const; @@ -108,7 +109,7 @@ private slots: void downloadDashDocset(const QString &name); void removeDocsets(const QStringList &names); - void displayProgress(); + void updateCombinedProgress(); void resetProgress(); // FIXME: Come up with a better approach diff --git a/src/libs/ui/forms/docsetsdialog.ui b/src/libs/ui/forms/docsetsdialog.ui index 36c30d730..6bd54f003 100644 --- a/src/libs/ui/forms/docsetsdialog.ui +++ b/src/libs/ui/forms/docsetsdialog.ui @@ -22,179 +22,161 @@ 0 - + - Docsets + Installed - - - Installed docsets + + + + 16 + 16 + - - - - - - 16 - 16 - - - - - - - - - - Add feed - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - Update - - - - - - - false - - - Update all - - - - - - - false - - - Remove - - - - - - - 0 - - - - - - - - - Downloadable docsets + + + + + Add feed + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Update + + + + + + + false + + + Update all + + + + + + + false + + + Remove + + + + + + + + + + Available + + + + + + Filter docsets + + + true + + + + + + + + 16 + 16 + + + + + + + + + + Last updated: + + + + + + + + + + + + + + Refresh + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + Download + + + + + + + + + <i>Docsets are provided by <a href="https://kapeli.com/dash">Dash</a>, the OS X Documentation Browser.</i> + + + Qt::RichText + + + true - - - - - - 16 - 16 - - - - - - - - Filter docsets - - - true - - - - - - - - - Last updated: - - - - - - - - - - - - - - Refresh - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - true - - - Download - - - - - - - - - <i>Docsets are provided by <a href="https://kapeli.com/dash">Dash</a>, the OS X Documentation Browser.</i> - - - Qt::RichText - - - true - - - - @@ -202,11 +184,32 @@ - - - QDialogButtonBox::Close - - + + + + + + 100 + 0 + + + + + + + + Cancel + + + + + + + QDialogButtonBox::Close + + + + From 8d053b00d7639e6e01172748e743069d8d68a3bd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 00:48:56 -0400 Subject: [PATCH 235/273] ui: Use multiple selection for choosing docsets to download No more checkboxes! --- src/libs/ui/docsetsdialog.cpp | 75 +++++++++++++++++++----------- src/libs/ui/docsetsdialog.h | 3 +- src/libs/ui/forms/docsetsdialog.ui | 10 +++- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index a42ef291c..5016d1c6e 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -82,16 +82,13 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : ui->combinedProgressBar->hide(); ui->cancelButton->hide(); + // Installed docsets tab ui->installedDocsetList->setItemDelegate(new DocsetListItemDelegate(this)); ui->installedDocsetList->setModel(new ListModel(app->docsetRegistry(), this)); - ui->installedDocsetList->setSelectionMode(QAbstractItemView::ExtendedSelection); QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); connect(selectionModel, &QItemSelectionModel::selectionChanged, [this, selectionModel]() { - if (!m_replies.isEmpty()) - return; - ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); for (const QModelIndex &index : selectionModel->selectedIndexes()) { @@ -111,10 +108,13 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : connect(ui->docsetFilterInput, &QLineEdit::textEdited, this, &DocsetsDialog::updateDocsetFilter); + // Available docsets tab ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); connect(ui->availableDocsetList, &QListWidget::itemActivated, this, [this](QListWidgetItem *item) { + item->setSelected(false); + // Do nothing if download is already in progress if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) return; @@ -126,6 +126,29 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); }); + selectionModel = ui->availableDocsetList->selectionModel(); + connect(selectionModel, &QItemSelectionModel::selectionChanged, + [this, selectionModel]() { + bool hasSelection = false; + + for (const QModelIndex &index : selectionModel->selectedIndexes()) { + const QString docsetName = index.data(Registry::ListModel::DocsetNameRole).toString(); + QListWidgetItem *item = findDocsetListItem(docsetName); + + // Do nothing if download is already in progress + if (!item || item->data(ProgressItemDelegate::ShowProgressRole).toBool()) + continue; + + hasSelection = true; + break; + } + + ui->downloadDocsetsButton->setEnabled(hasSelection); + }); + + connect(ui->downloadDocsetsButton, &QPushButton::clicked, + this, &DocsetsDialog::downloadSelectedDocsets); + connect(m_docsetRegistry, &DocsetRegistry::docsetRemoved, this, [this](const QString name) { QListWidgetItem *item = findDocsetListItem(name); if (!item) @@ -254,6 +277,28 @@ void DocsetsDialog::updateDocsetFilter(const QString &filterString) } } +void DocsetsDialog::downloadSelectedDocsets() +{ + for (const QModelIndex &index : ui->availableDocsetList->selectionModel()->selectedIndexes()) { + const QString docsetName = index.data(Registry::ListModel::DocsetNameRole).toString(); + QListWidgetItem *item = findDocsetListItem(docsetName); + if (!item) + continue; + + item->setSelected(false); + + // Do nothing if download is already in progress + if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) + continue; + + item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); + item->setData(ProgressItemDelegate::ValueRole, 0); + item->setData(ProgressItemDelegate::ShowProgressRole, true); + + downloadDashDocset(docsetName); + } +} + /*! \internal Should be connected to all \l QNetworkReply::finished signals in order to process possible @@ -472,7 +517,6 @@ void DocsetsDialog::extractionCompleted(const QString &filePath) QListWidgetItem *listItem = findDocsetListItem(docsetName); if (listItem) { listItem->setHidden(true); - listItem->setCheckState(Qt::Unchecked); listItem->setData(ProgressItemDelegate::ShowProgressRole, false); } @@ -503,26 +547,6 @@ void DocsetsDialog::extractionProgress(const QString &filePath, qint64 extracted listItem->setData(ProgressItemDelegate::ValueRole, percent(extracted, total)); } -void DocsetsDialog::on_downloadDocsetButton_clicked() -{ - // Find each checked item, and create a NetworkRequest for it. - for (int i = 0; i < ui->availableDocsetList->count(); ++i) { - QListWidgetItem *item = ui->availableDocsetList->item(i); - if (item->checkState() != Qt::Checked) - continue; - - // Do nothing if download is already in progress - if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) - return; - - item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); - item->setData(ProgressItemDelegate::ValueRole, 0); - item->setData(ProgressItemDelegate::ShowProgressRole, true); - - downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); - } -} - void DocsetsDialog::loadDocsetList() { const QFileInfo fi(cacheLocation(DocsetListCacheFileName)); @@ -633,7 +657,6 @@ void DocsetsDialog::processDocsetList(const QJsonArray &list) QListWidgetItem *listItem = new QListWidgetItem(metadata.icon(), metadata.title(), ui->availableDocsetList); listItem->setData(Registry::ListModel::DocsetNameRole, metadata.name()); - listItem->setCheckState(Qt::Unchecked); if (m_docsetRegistry->contains(metadata.name())) { listItem->setHidden(true); diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index a6bc3edc4..55096a238 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -65,6 +65,8 @@ private slots: void removeSelectedDocsets(); void updateDocsetFilter(const QString &filterString); + void downloadSelectedDocsets(); + void downloadCompleted(); void downloadProgress(qint64 received, qint64 total); @@ -72,7 +74,6 @@ private slots: void extractionError(const QString &filePath, const QString &errorString); void extractionProgress(const QString &filePath, qint64 extracted, qint64 total); - void on_downloadDocsetButton_clicked(); void loadDocsetList(); private: diff --git a/src/libs/ui/forms/docsetsdialog.ui b/src/libs/ui/forms/docsetsdialog.ui index 6bd54f003..c3ba0bbeb 100644 --- a/src/libs/ui/forms/docsetsdialog.ui +++ b/src/libs/ui/forms/docsetsdialog.ui @@ -29,6 +29,9 @@ + + QAbstractItemView::ExtendedSelection + 16 @@ -110,6 +113,9 @@ + + QAbstractItemView::ExtendedSelection + 16 @@ -155,9 +161,9 @@ - + - true + false Download From 25eb733db0cd2d03a1c2b585bc207e9d3e598869 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:04:16 -0400 Subject: [PATCH 236/273] ui: Unify docset removal logic --- src/libs/ui/docsetsdialog.cpp | 88 ++++++++++++++++------------------- src/libs/ui/docsetsdialog.h | 2 +- 2 files changed, 42 insertions(+), 48 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 5016d1c6e..b6dcc5e8f 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -256,10 +256,13 @@ void DocsetsDialog::removeSelectedDocsets() if (ret == QMessageBox::No) return; + // Gather names first, because model indicies become invalid when docsets are removed. QStringList names; for (const QModelIndex &index : selectonModel->selectedIndexes()) - names << index.data(Registry::ListModel::DocsetNameRole).toString(); - removeDocsets(names); + names.append(index.data(Registry::ListModel::DocsetNameRole).toString()); + + for (const QString &name : names) + removeDocset(name); } void DocsetsDialog::updateDocsetFilter(const QString &filterString) @@ -412,20 +415,9 @@ void DocsetsDialog::downloadCompleted() const QString docsetName = reply->property(DocsetNameProperty).toString(); // TODO: Implement an explicit and verbose docset update logic - QDir dir(m_application->settings()->docsetPath); - const QString docsetDirName = docsetName + QLatin1String(".docset"); - if (dir.exists(docsetDirName)) { - m_docsetRegistry->remove(docsetName); - const QString tmpName = QStringLiteral(".toDelete") - + QString::number(QDateTime::currentMSecsSinceEpoch()); - dir.rename(docsetDirName, tmpName); - QtConcurrent::run([=] { - QDir d(dir); - if (!d.cd(tmpName)) - return; - d.removeRecursively(); - }); - } + const QDir dir(m_application->settings()->docsetPath); + if (dir.exists(docsetName + QLatin1String(".docset"))) + removeDocset(docsetName); QTemporaryFile *tmpFile = m_tmpFiles[docsetName]; if (!tmpFile) { @@ -690,47 +682,49 @@ void DocsetsDialog::downloadDashDocset(const QString &name) connect(reply, &QNetworkReply::finished, this, &DocsetsDialog::downloadCompleted); } -void DocsetsDialog::removeDocsets(const QStringList &names) +void DocsetsDialog::removeDocset(const QString &name) { - for (const QString &name : names) { - if (m_docsetsBeingDeleted.contains(name)) - continue; + if (m_docsetsBeingDeleted.contains(name)) + return; - m_docsetsBeingDeleted << name; + m_docsetsBeingDeleted.append(name); - const QString title = m_docsetRegistry->docset(name)->title(); - m_docsetRegistry->remove(name); + Registry::Docset *docset = m_docsetRegistry->docset(name); + const QString title = docset->title(); + const QString docsetPath = docset->path(); + const QString tmpPath = docsetPath + QLatin1String(".deleteme.") + + QString::number(QDateTime::currentMSecsSinceEpoch()); - const QDir dataDir(m_application->settings()->docsetPath); - if (dataDir.exists()) { - updateCombinedProgress(); + // Rename first to allow simultaneous installation. + // TODO: Check for error + QDir().rename(docsetPath, tmpPath); + + m_docsetRegistry->remove(name); + + updateCombinedProgress(); - QFuture future = QtConcurrent::run([=] { - QDir docsetDir(dataDir); - return docsetDir.cd(name + QLatin1String(".docset")) - && docsetDir.removeRecursively(); - }); + QFuture future = QtConcurrent::run([tmpPath] { + return QDir(tmpPath).removeRecursively(); + }); - QFutureWatcher *watcher = new QFutureWatcher(); - watcher->setFuture(future); - connect(watcher, &QFutureWatcher::finished, [=] { - if (!watcher->result()) { - QMessageBox::warning(this, QStringLiteral("Zeal"), - tr("Cannot delete docset %1!").arg(title)); - } + QFutureWatcher *watcher = new QFutureWatcher(); + watcher->setFuture(future); + connect(watcher, &QFutureWatcher::finished, [=] { + if (!watcher->result()) { + QMessageBox::warning(this, QStringLiteral("Zeal"), + tr("Cannot delete docset %1!").arg(title)); + } - QListWidgetItem *listItem = findDocsetListItem(name); - if (listItem) - listItem->setHidden(false); + QListWidgetItem *listItem = findDocsetListItem(name); + if (listItem) + listItem->setHidden(false); - watcher->deleteLater(); + watcher->deleteLater(); - m_docsetsBeingDeleted.removeOne(name); + m_docsetsBeingDeleted.removeOne(name); - updateCombinedProgress(); - }); - } - } + updateCombinedProgress(); + }); } void DocsetsDialog::updateCombinedProgress() diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index 55096a238..a3a62e4e8 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -108,7 +108,7 @@ private slots: void processDocsetList(const QJsonArray &list); void downloadDashDocset(const QString &name); - void removeDocsets(const QStringList &names); + void removeDocset(const QString &name); void updateCombinedProgress(); void resetProgress(); From 08abd7385c1d46be581485c2505248f9fdc57aed Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:18:46 -0400 Subject: [PATCH 237/273] ui: Make multiple docset removal confimation plural aware --- src/libs/ui/docsetsdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index b6dcc5e8f..3f81f457b 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -249,8 +249,8 @@ void DocsetsDialog::removeSelectedDocsets() tr("Remove %1 docset?").arg(docsetTitle)); } else { ret = QMessageBox::question(this, QStringLiteral("Zeal"), - tr("Remove %1 docsets?") - .arg(selectonModel->selectedIndexes().count())); + tr("Remove %n docset(s)?", nullptr, + selectedIndexes.size())); } if (ret == QMessageBox::No) From 7c29eb313a338227e3e4dc91330739ecb0d2a73e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:20:18 -0400 Subject: [PATCH 238/273] ui: Clean up docset removal code a bit --- src/libs/ui/docsetsdialog.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 3f81f457b..6c8d2ef4f 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -243,8 +243,10 @@ void DocsetsDialog::removeSelectedDocsets() return; int ret; - if (selectonModel->selectedIndexes().count() == 1) { - const QString docsetTitle = selectonModel->selectedIndexes().first().data().toString(); + + const QModelIndexList selectedIndexes = selectonModel->selectedIndexes(); + if (selectedIndexes.size() == 1) { + const QString docsetTitle = selectedIndexes.first().data().toString(); ret = QMessageBox::question(this, QStringLiteral("Zeal"), tr("Remove %1 docset?").arg(docsetTitle)); } else { @@ -258,7 +260,7 @@ void DocsetsDialog::removeSelectedDocsets() // Gather names first, because model indicies become invalid when docsets are removed. QStringList names; - for (const QModelIndex &index : selectonModel->selectedIndexes()) + for (const QModelIndex &index : selectedIndexes) names.append(index.data(Registry::ListModel::DocsetNameRole).toString()); for (const QString &name : names) From 2ef529b235dc183f3eff366637143ba0ff2e1a2c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:22:36 -0400 Subject: [PATCH 239/273] ui: Remove duplicated line in DocsetsDialog --- src/libs/ui/docsetsdialog.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 6c8d2ef4f..fd4346a8b 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -438,7 +438,6 @@ void DocsetsDialog::downloadCompleted() item->setData(ProgressItemDelegate::FormatRole, tr("Installing: %p%")); } - m_tmpFiles.insert(docsetName, tmpFile); m_application->extract(tmpFile->fileName(), m_application->settings()->docsetPath, docsetName + QLatin1String(".docset")); break; From 33a82da9d2707519118aff8de5222b150005de98 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:25:07 -0400 Subject: [PATCH 240/273] ui: Fix SettingsDialog window title --- src/libs/ui/forms/settingsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ui/forms/settingsdialog.ui b/src/libs/ui/forms/settingsdialog.ui index 4bc79ad32..efc3a8965 100644 --- a/src/libs/ui/forms/settingsdialog.ui +++ b/src/libs/ui/forms/settingsdialog.ui @@ -14,7 +14,7 @@ - Zeal Options + Preferences From fa008f39c329def45597964a961c94bbaa904564 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:29:23 -0400 Subject: [PATCH 241/273] ui: Use better wording for the "operations pending" message box --- src/libs/ui/docsetsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index fd4346a8b..f4878cd10 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -192,7 +192,7 @@ void DocsetsDialog::reject() } QMessageBox::information(this, QStringLiteral("Zeal"), - tr("An operation is in progress, wait for it to finish, or cancel.")); + tr("Please wait for all operations to finish.")); } void DocsetsDialog::addDashFeed() From 6b9b49887498f8465177a3def2c9f8d181dbf15d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 02:30:42 -0400 Subject: [PATCH 242/273] ui: Do not allow to close DocsetsDialog if removal is in progress --- src/libs/ui/docsetsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index f4878cd10..d78a8b3d4 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -186,7 +186,7 @@ DocsetsDialog::~DocsetsDialog() void DocsetsDialog::reject() { - if (m_replies.isEmpty() && m_tmpFiles.isEmpty()) { + if (m_replies.isEmpty() && m_tmpFiles.isEmpty() && m_docsetsBeingDeleted.isEmpty()) { QDialog::reject(); return; } From bbcd3c610c029601a518b2e4146b85a1d3d4f214 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 22:03:02 -0400 Subject: [PATCH 243/273] qmake: Do not install static libs (fixes zealdocs/zeal-packaging#17) --- qmake/common.pri | 4 ---- src/app/app.pro | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/qmake/common.pri b/qmake/common.pri index 1b15edece..d6d2af612 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -68,8 +68,4 @@ CONFIG(zeal_portable) { unix:!macx { isEmpty(PREFIX): PREFIX = /usr message("Install prefix: $$PREFIX") - target.path = $$PREFIX/bin - - # Always install target - INSTALLS += target } diff --git a/src/app/app.pro b/src/app/app.pro index 540aa1566..7dfd39a05 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -14,6 +14,9 @@ DESTDIR = $$BUILD_ROOT/bin unix:!macx { TARGET = zeal + target.path = $$PREFIX/bin + + INSTALLS += target } win32 { From 24077dbd1ee3407e35a2f51ba323da7bf292090c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 14 Sep 2016 22:16:22 -0400 Subject: [PATCH 244/273] ui: Cleanup MainWindow's .ui a bit --- src/libs/ui/forms/mainwindow.ui | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/libs/ui/forms/mainwindow.ui b/src/libs/ui/forms/mainwindow.ui index ab4d3a3a1..6d26b9916 100644 --- a/src/libs/ui/forms/mainwindow.ui +++ b/src/libs/ui/forms/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 1050 - 579 + 900 + 600 @@ -29,9 +29,6 @@ - - Qt::Horizontal - false @@ -125,9 +122,6 @@ 0 - - 12 - 0 @@ -200,8 +194,8 @@ 0 0 - 1050 - 22 + 900 + 23 From c9d44a466097fe2589d87971fd5fc7226993405c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 15 Sep 2016 00:56:18 -0400 Subject: [PATCH 245/273] registry: Remove 100 results limit (fixes #593) --- src/libs/registry/docset.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index c7f852c72..81f8a7a61 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -267,7 +267,7 @@ QList Docset::search(const QString &query, const CancellationToken QString subNames = QStringLiteral(" OR %1 LIKE '%.%2%' ESCAPE '\\'"); subNames += QLatin1String(" OR %1 LIKE '%::%2%' ESCAPE '\\'"); subNames += QLatin1String(" OR %1 LIKE '%/%2%' ESCAPE '\\'"); - while (!token.isCanceled() && results.size() < 100) { + while (!token.isCanceled()) { QString curQuery = sanitizedQuery; QString notQuery; // don't return the same result twice if (withSubStrings) { @@ -283,7 +283,7 @@ QList Docset::search(const QString &query, const CancellationToken queryStr = QString("SELECT name, type, path " " FROM searchIndex " "WHERE (name LIKE '%1%' ESCAPE '\\' %3) %2 " - "ORDER BY name COLLATE NOCASE LIMIT 100") + "ORDER BY name COLLATE NOCASE") .arg(curQuery, notQuery, subNames.arg("name", curQuery)); } else { queryStr = QString("SELECT ztokenname, ztypename, zpath, zanchor " @@ -295,7 +295,7 @@ QList Docset::search(const QString &query, const CancellationToken "JOIN ztokentype " " ON ztoken.ztokentype = ztokentype.z_pk " "WHERE (ztokenname LIKE '%1%' ESCAPE '\\' %3) %2 " - "ORDER BY ztokenname COLLATE NOCASE LIMIT 100") + "ORDER BY ztokenname COLLATE NOCASE") .arg(curQuery, notQuery, subNames.arg("ztokenname", curQuery)); } @@ -315,9 +315,11 @@ QList Docset::search(const QString &query, const CancellationToken const_cast(this), path, sanitizedQuery}); } - if (withSubStrings) + if (results.size() >= 100 || withSubStrings) break; - withSubStrings = true; // try again searching for substrings + + // Try again with substrings. + withSubStrings = true; } return results; From 6c299469de100e7e5f29f1bc330e32fe77fec51a Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 15 Sep 2016 02:29:21 -0400 Subject: [PATCH 246/273] registry: Do not use search query for sorting results --- src/libs/registry/docset.cpp | 4 ++-- src/libs/registry/searchresult.cpp | 17 ++++++----------- src/libs/registry/searchresult.h | 3 --- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index 81f8a7a61..9fb377f37 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -312,7 +312,7 @@ QList Docset::search(const QString &query, const CancellationToken // TODO: Third should be type results.append(SearchResult{itemName, QString(), parseSymbolType(query.value(1).toString()), - const_cast(this), path, sanitizedQuery}); + const_cast(this), path}); } if (results.size() >= 100 || withSubStrings) @@ -365,7 +365,7 @@ QList Docset::relatedLinks(const QUrl &url) const results.append(SearchResult{sectionName, QString(), parseSymbolType(query.value(1).toString()), - const_cast(this), sectionPath, QString()}); + const_cast(this), sectionPath}); } if (results.size() == 1) diff --git a/src/libs/registry/searchresult.cpp b/src/libs/registry/searchresult.cpp index 74c8bfd09..29e01dafe 100644 --- a/src/libs/registry/searchresult.cpp +++ b/src/libs/registry/searchresult.cpp @@ -23,19 +23,14 @@ #include "searchresult.h" +#include "docset.h" + using namespace Zeal::Registry; -bool SearchResult::operator<(const SearchResult &r) const +bool SearchResult::operator<(const SearchResult &other) const { - const bool lhsStartsWithQuery = name.startsWith(query, Qt::CaseInsensitive); - const bool rhsStartsWithQuery = r.name.startsWith(query, Qt::CaseInsensitive); - - if (lhsStartsWithQuery != rhsStartsWithQuery) - return lhsStartsWithQuery > rhsStartsWithQuery; - - const int namesCmp = QString::compare(name, r.name, Qt::CaseInsensitive); - if (namesCmp) - return namesCmp < 0; + if (docset->name() == other.docset->name()) + return QString::compare(name, other.name, Qt::CaseInsensitive) < 0; - return QString::compare(parentName, r.parentName, Qt::CaseInsensitive) < 0; + return docset->name() < other.docset->name(); } diff --git a/src/libs/registry/searchresult.h b/src/libs/registry/searchresult.h index 9c3264a6a..a3a071f53 100644 --- a/src/libs/registry/searchresult.h +++ b/src/libs/registry/searchresult.h @@ -41,9 +41,6 @@ struct SearchResult QString path; - // TODO: Remove - QString query; - bool operator<(const SearchResult &r) const; }; From 9c11087c2e8f496f09fd8006aaf3cc2af3b5c1d3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 15 Sep 2016 03:07:37 -0400 Subject: [PATCH 247/273] registry: Remove unused field from SearchResult --- src/libs/registry/docset.cpp | 4 ++-- src/libs/registry/searchmodel.cpp | 5 +---- src/libs/registry/searchresult.h | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index 9fb377f37..22567aa6c 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -310,7 +310,7 @@ QList Docset::search(const QString &query, const CancellationToken } // TODO: Third should be type - results.append(SearchResult{itemName, QString(), + results.append(SearchResult{itemName, parseSymbolType(query.value(1).toString()), const_cast(this), path}); } @@ -363,7 +363,7 @@ QList Docset::relatedLinks(const QUrl &url) const sectionPath += query.value(3).toString(); } - results.append(SearchResult{sectionName, QString(), + results.append(SearchResult{sectionName, parseSymbolType(query.value(1).toString()), const_cast(this), sectionPath}); } diff --git a/src/libs/registry/searchmodel.cpp b/src/libs/registry/searchmodel.cpp index 8b78bcf0a..157cfd147 100644 --- a/src/libs/registry/searchmodel.cpp +++ b/src/libs/registry/searchmodel.cpp @@ -56,10 +56,7 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case 0: - if (item->parentName.isEmpty()) - return item->name; - else - return QString("%1 (%2)").arg(item->name, item->parentName); + return item->name; case 1: return QDir(item->docset->documentPath()).absoluteFilePath(item->path); default: diff --git a/src/libs/registry/searchresult.h b/src/libs/registry/searchresult.h index a3a071f53..d3a7ec769 100644 --- a/src/libs/registry/searchresult.h +++ b/src/libs/registry/searchresult.h @@ -34,7 +34,6 @@ class Docset; struct SearchResult { QString name; - QString parentName; QString type; Docset *docset; From 6e9bd48b281097d85ff264e5653a8aa3ce26d007 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 15 Sep 2016 03:10:45 -0400 Subject: [PATCH 248/273] registry: Greatly simplify search logic (#265) --- src/libs/registry/docset.cpp | 89 ++++++++++++------------------------ 1 file changed, 29 insertions(+), 60 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index 22567aa6c..a611a3790 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -253,73 +253,42 @@ QList Docset::search(const QString &query, const CancellationToken QList results; const SearchQuery searchQuery = SearchQuery::fromString(query); - const QString sanitizedQuery = searchQuery.sanitizedQuery(); - if (searchQuery.hasKeywords() && !searchQuery.hasKeywords(m_keywords)) return results; QString queryStr; + if (m_type == Docset::Type::Dash) { + queryStr = QStringLiteral("SELECT name, type, path " + " FROM searchIndex " + "WHERE (name LIKE '%%1%' ESCAPE '\\') " + "ORDER BY name COLLATE NOCASE") + .arg(searchQuery.sanitizedQuery()); + } else { + queryStr = QStringLiteral("SELECT ztokenname, ztypename, zpath, zanchor " + " FROM ztoken " + "JOIN ztokenmetainformation " + " ON ztoken.zmetainformation = ztokenmetainformation.z_pk " + "JOIN zfilepath " + " ON ztokenmetainformation.zfile = zfilepath.z_pk " + "JOIN ztokentype " + " ON ztoken.ztokentype = ztokentype.z_pk " + "WHERE (ztokenname LIKE '%%1%' ESCAPE '\\') " + "ORDER BY ztokenname COLLATE NOCASE") + .arg(searchQuery.sanitizedQuery()); + } - bool withSubStrings = false; - // %.%1% for long Django docset values like django.utils.http - // %::%1% for long C++ docset values like std::set - // %/%1% for long Go docset values like archive/tar - QString subNames = QStringLiteral(" OR %1 LIKE '%.%2%' ESCAPE '\\'"); - subNames += QLatin1String(" OR %1 LIKE '%::%2%' ESCAPE '\\'"); - subNames += QLatin1String(" OR %1 LIKE '%/%2%' ESCAPE '\\'"); - while (!token.isCanceled()) { - QString curQuery = sanitizedQuery; - QString notQuery; // don't return the same result twice - if (withSubStrings) { - // if less than 100 found starting with query, search all substrings - curQuery = QLatin1Char('%') + sanitizedQuery; - // don't return 'starting with' results twice - if (m_type == Docset::Type::Dash) - notQuery = QString(" AND NOT (name LIKE '%1%' ESCAPE '\\' %2) ").arg(sanitizedQuery, subNames.arg("name", sanitizedQuery)); - else - notQuery = QString(" AND NOT (ztokenname LIKE '%1%' ESCAPE '\\' %2) ").arg(sanitizedQuery, subNames.arg("ztokenname", sanitizedQuery)); - } - if (m_type == Docset::Type::Dash) { - queryStr = QString("SELECT name, type, path " - " FROM searchIndex " - "WHERE (name LIKE '%1%' ESCAPE '\\' %3) %2 " - "ORDER BY name COLLATE NOCASE") - .arg(curQuery, notQuery, subNames.arg("name", curQuery)); - } else { - queryStr = QString("SELECT ztokenname, ztypename, zpath, zanchor " - " FROM ztoken " - "JOIN ztokenmetainformation " - " ON ztoken.zmetainformation = ztokenmetainformation.z_pk " - "JOIN zfilepath " - " ON ztokenmetainformation.zfile = zfilepath.z_pk " - "JOIN ztokentype " - " ON ztoken.ztokentype = ztokentype.z_pk " - "WHERE (ztokenname LIKE '%1%' ESCAPE '\\' %3) %2 " - "ORDER BY ztokenname COLLATE NOCASE") - .arg(curQuery, notQuery, subNames.arg("ztokenname", curQuery)); - } - - QSqlQuery query(queryStr, database()); - while (query.next()) { - const QString itemName = query.value(0).toString(); - QString path = query.value(2).toString(); - if (m_type == Docset::Type::ZDash) { - const QString anchor = query.value(3).toString(); - if (!anchor.isEmpty()) - path += QLatin1Char('#') + anchor; - } - - // TODO: Third should be type - results.append(SearchResult{itemName, - parseSymbolType(query.value(1).toString()), - const_cast(this), path}); + QSqlQuery sqlQuery(queryStr, database()); + while (sqlQuery.next() && !token.isCanceled()) { + const QString itemName = sqlQuery.value(0).toString(); + QString path = sqlQuery.value(2).toString(); + if (m_type == Docset::Type::ZDash) { + const QString anchor = sqlQuery.value(3).toString(); + if (!anchor.isEmpty()) + path += QLatin1Char('#') + anchor; } - if (results.size() >= 100 || withSubStrings) - break; - - // Try again with substrings. - withSubStrings = true; + results.append(SearchResult{itemName, parseSymbolType(sqlQuery.value(1).toString()), + const_cast(this), path}); } return results; From a4fac24a5dd9cb3df12794cd5485fb5daedf23f6 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 15 Sep 2016 03:11:58 -0400 Subject: [PATCH 249/273] registry: Limit results to 1k per docset for queries < 3 symbols (#265) --- src/libs/registry/docset.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index a611a3790..face42f25 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -277,6 +277,11 @@ QList Docset::search(const QString &query, const CancellationToken .arg(searchQuery.sanitizedQuery()); } + // Limit for very short queries. + // TODO: Show a notification about the reduced result set. + if (searchQuery.query().size() < 3) + queryStr += QLatin1String(" LIMIT 1000"); + QSqlQuery sqlQuery(queryStr, database()); while (sqlQuery.next() && !token.isCanceled()) { const QString itemName = sqlQuery.value(0).toString(); From 10a11e2778c7a7d8177a159c4393e04721213597 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 17 Sep 2016 20:40:07 -0400 Subject: [PATCH 250/273] ui: Show tooltips for tabs --- src/libs/ui/mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp index 9a28fae32..d6781e0cf 100644 --- a/src/libs/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -353,6 +353,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) : setWindowTitle(QStringLiteral("%1 - Zeal").arg(title)); m_tabBar->setTabText(m_tabBar->currentIndex(), title); + m_tabBar->setTabToolTip(m_tabBar->currentIndex(), title); }); connect(ui->webView, &SearchableWebView::linkClicked, [this](const QUrl &url) { From 801d3e44e2f094a8cb0bf5c54789406d085dd5bc Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sat, 17 Sep 2016 20:53:48 -0400 Subject: [PATCH 251/273] registry: Ignore "unsorteddashtoc" as a keyword --- src/libs/registry/docset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index face42f25..c02c67763 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -146,7 +146,7 @@ Docset::Docset(const QString &path) : if (plist.contains(InfoPlist::DashDocSetFamily)) { const QString kw = plist[InfoPlist::DashDocSetFamily].toString(); - if (kw != QLatin1String("dashtoc")) + if (kw != QLatin1String("dashtoc") && kw != QLatin1String("unsorteddashtoc")) m_keywords << kw; } From feb35e8ecdb605e85b5ec4aa93e3939c3f27b19f Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 17:22:28 -0400 Subject: [PATCH 252/273] doc: Add Telegram and Twitter badges --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d2519f2d7..05b87eae2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Zeal -[![GitHub release](https://img.shields.io/github/release/zealdocs/zeal.svg?style=flat-square)](https://github.com/zealdocs/zeal/releases) [![IRC](https://img.shields.io/badge/irc-%23zealdocs-blue.svg?style=flat-square)](https://kiwiirc.com/client/irc.freenode.net/#zealdocs) +[![Changelog](https://img.shields.io/github/release/zealdocs/zeal.svg?style=flat-square)](https://github.com/zealdocs/zeal/releases) +[![IRC](https://img.shields.io/badge/chat-on%20irc-blue.svg?style=flat-square)](https://kiwiirc.com/client/irc.freenode.net/#zealdocs) +[![Telegram Chat](https://img.shields.io/badge/chat-on%20telegram-179cde.svg?style=flat-square)](https://telegram.me/zealdocschat) +[![Telegram Channel](https://img.shields.io/badge/follow-on%20telegram-179cde.svg?style=flat-square)](https://telegram.me/zealdocs) +[![Twitter](https://img.shields.io/badge/follow-on%20twitter-1da1f2.svg?style=flat-square)](https://twitter.com/zealdocs) > **zeal** *noun* > From 947b67a54d935f21e90ddfec3dfe171989c965c7 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 18:26:18 -0400 Subject: [PATCH 253/273] registry: Optimize docset selection with keywords present --- src/libs/registry/docset.cpp | 15 +++++---------- src/libs/registry/docsetregistry.cpp | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index c02c67763..d3ff86dde 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -24,7 +24,6 @@ #include "docset.h" #include "cancellationtoken.h" -#include "searchquery.h" #include "searchresult.h" #include @@ -250,19 +249,13 @@ const QMap &Docset::symbols(const QString &symbolType) const QList Docset::search(const QString &query, const CancellationToken &token) const { - QList results; - - const SearchQuery searchQuery = SearchQuery::fromString(query); - if (searchQuery.hasKeywords() && !searchQuery.hasKeywords(m_keywords)) - return results; - QString queryStr; if (m_type == Docset::Type::Dash) { queryStr = QStringLiteral("SELECT name, type, path " " FROM searchIndex " "WHERE (name LIKE '%%1%' ESCAPE '\\') " "ORDER BY name COLLATE NOCASE") - .arg(searchQuery.sanitizedQuery()); + .arg(query); } else { queryStr = QStringLiteral("SELECT ztokenname, ztypename, zpath, zanchor " " FROM ztoken " @@ -274,14 +267,16 @@ QList Docset::search(const QString &query, const CancellationToken " ON ztoken.ztokentype = ztokentype.z_pk " "WHERE (ztokenname LIKE '%%1%' ESCAPE '\\') " "ORDER BY ztokenname COLLATE NOCASE") - .arg(searchQuery.sanitizedQuery()); + .arg(query); } // Limit for very short queries. // TODO: Show a notification about the reduced result set. - if (searchQuery.query().size() < 3) + if (query.size() < 3) queryStr += QLatin1String(" LIMIT 1000"); + QList results; + QSqlQuery sqlQuery(queryStr, database()); while (sqlQuery.next() && !token.isCanceled()) { const QString itemName = sqlQuery.value(0).toString(); diff --git a/src/libs/registry/docsetregistry.cpp b/src/libs/registry/docsetregistry.cpp index c91f374eb..dbe18be00 100644 --- a/src/libs/registry/docsetregistry.cpp +++ b/src/libs/registry/docsetregistry.cpp @@ -24,6 +24,7 @@ #include "docsetregistry.h" #include "cancellationtoken.h" +#include "searchquery.h" #include "searchresult.h" #include @@ -141,11 +142,23 @@ void DocsetRegistry::search(const QString &query, const CancellationToken &token void DocsetRegistry::_runQuery(const QString &query, const CancellationToken &token) { + QList enabledDocsets; + + const SearchQuery searchQuery = SearchQuery::fromString(query); + if (searchQuery.hasKeywords()) { + for (Docset *docset : docsets()) { + if (searchQuery.hasKeywords(docset->keywords())) + enabledDocsets << docset; + } + } else { + enabledDocsets = docsets(); + } + QFuture> queryResultsFuture - = QtConcurrent::mappedReduced(docsets(), + = QtConcurrent::mappedReduced(enabledDocsets, std::bind(&Docset::search, std::placeholders::_1, - query, token), + searchQuery.sanitizedQuery(), token), &MergeQueryResults); QList results = queryResultsFuture.result(); From 302d6028e6db236748a229504e6bcc8f5ff69c0e Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 18:33:03 -0400 Subject: [PATCH 254/273] registry: Cleanup Docset a bit --- src/libs/registry/docset.cpp | 39 +++++++++++++++++------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index d3ff86dde..d4ce989d9 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -46,14 +46,14 @@ const char IndexNameVersion[] = "0001"; // Current index version namespace InfoPlist { const char CFBundleName[] = "CFBundleName"; -const char CFBundleIdentifier[] = "CFBundleIdentifier"; +//const char CFBundleIdentifier[] = "CFBundleIdentifier"; const char DashDocSetFamily[] = "DashDocSetFamily"; const char DashDocSetKeyword[] = "DashDocSetKeyword"; const char DashDocSetPluginKeyword[] = "DashDocSetPluginKeyword"; const char DashIndexFilePath[] = "dashIndexFilePath"; const char DocSetPlatformFamily[] = "DocSetPlatformFamily"; -const char IsDashDocset[] = "isDashDocset"; -const char IsJavaScriptEnabled[] = "isJavaScriptEnabled"; +//const char IsDashDocset[] = "isDashDocset"; +//const char IsJavaScriptEnabled[] = "isJavaScriptEnabled"; } } @@ -254,8 +254,7 @@ QList Docset::search(const QString &query, const CancellationToken queryStr = QStringLiteral("SELECT name, type, path " " FROM searchIndex " "WHERE (name LIKE '%%1%' ESCAPE '\\') " - "ORDER BY name COLLATE NOCASE") - .arg(query); + "ORDER BY name COLLATE NOCASE").arg(query); } else { queryStr = QStringLiteral("SELECT ztokenname, ztypename, zpath, zanchor " " FROM ztoken " @@ -266,8 +265,7 @@ QList Docset::search(const QString &query, const CancellationToken "JOIN ztokentype " " ON ztoken.ztokentype = ztokentype.z_pk " "WHERE (ztokenname LIKE '%%1%' ESCAPE '\\') " - "ORDER BY ztokenname COLLATE NOCASE") - .arg(query); + "ORDER BY ztokenname COLLATE NOCASE").arg(query); } // Limit for very short queries. @@ -287,8 +285,10 @@ QList Docset::search(const QString &query, const CancellationToken path += QLatin1Char('#') + anchor; } - results.append(SearchResult{itemName, parseSymbolType(sqlQuery.value(1).toString()), - const_cast(this), path}); + results.append({itemName, + parseSymbolType(sqlQuery.value(1).toString()), + const_cast(this), + path}); } return results; @@ -322,19 +322,16 @@ QList Docset::relatedLinks(const QUrl &url) const "WHERE zfilepath.zpath = \"%1\" AND ztokenmetainformation.zanchor IS NOT NULL"); } - QSqlQuery query(queryStr.arg(cleanUrl.toString()), database()); + QSqlQuery sqlQuery(queryStr.arg(cleanUrl.toString()), database()); + while (sqlQuery.next()) { + QString sectionPath = sqlQuery.value(2).toString(); + if (m_type == Docset::Type::ZDash) + sectionPath += QLatin1Char('#') + sqlQuery.value(3).toString(); - while (query.next()) { - const QString sectionName = query.value(0).toString(); - QString sectionPath = query.value(2).toString(); - if (m_type == Docset::Type::ZDash) { - sectionPath += QLatin1Char('#'); - sectionPath += query.value(3).toString(); - } - - results.append(SearchResult{sectionName, - parseSymbolType(query.value(1).toString()), - const_cast(this), sectionPath}); + results.append({sqlQuery.value(0).toString(), + parseSymbolType(sqlQuery.value(1).toString()), + const_cast(this), + sectionPath}); } if (results.size() == 1) From 7282698a9d372aa904c4da3f69415e140c610ca0 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 18:54:32 -0400 Subject: [PATCH 255/273] registry: Do not sort search results by docset --- src/libs/registry/searchresult.cpp | 10 ---------- src/libs/registry/searchresult.h | 5 ++++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/libs/registry/searchresult.cpp b/src/libs/registry/searchresult.cpp index 29e01dafe..1679f6620 100644 --- a/src/libs/registry/searchresult.cpp +++ b/src/libs/registry/searchresult.cpp @@ -23,14 +23,4 @@ #include "searchresult.h" -#include "docset.h" - using namespace Zeal::Registry; - -bool SearchResult::operator<(const SearchResult &other) const -{ - if (docset->name() == other.docset->name()) - return QString::compare(name, other.name, Qt::CaseInsensitive) < 0; - - return docset->name() < other.docset->name(); -} diff --git a/src/libs/registry/searchresult.h b/src/libs/registry/searchresult.h index d3a7ec769..438fe5e4d 100644 --- a/src/libs/registry/searchresult.h +++ b/src/libs/registry/searchresult.h @@ -40,7 +40,10 @@ struct SearchResult QString path; - bool operator<(const SearchResult &r) const; + inline bool operator<(const SearchResult &other) const + { + return QString::compare(name, other.name, Qt::CaseInsensitive) < 0; + } }; } // namespace Registry From 846892446ba2967a3308f9fdc5425d61fb9be311 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 19:10:46 -0400 Subject: [PATCH 256/273] registry: Move SQL sanitization to Docset SearchQuery should not know about the underlying search mechanism. --- src/libs/registry/docset.cpp | 11 +++++++++-- src/libs/registry/docsetregistry.cpp | 2 +- src/libs/registry/searchquery.cpp | 10 ---------- src/libs/registry/searchquery.h | 3 --- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index d4ce989d9..ac76ed885 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -249,12 +249,19 @@ const QMap &Docset::symbols(const QString &symbolType) const QList Docset::search(const QString &query, const CancellationToken &token) const { + // Make it safe to use in a SQL query. + QString sanitizedQuery = query; + sanitizedQuery.replace(QLatin1String("\\"), QLatin1String("\\\\")); + sanitizedQuery.replace(QLatin1String("_"), QLatin1String("\\_")); + sanitizedQuery.replace(QLatin1String("%"), QLatin1String("\\%")); + sanitizedQuery.replace(QLatin1String("'"), QLatin1String("''")); + QString queryStr; if (m_type == Docset::Type::Dash) { queryStr = QStringLiteral("SELECT name, type, path " " FROM searchIndex " "WHERE (name LIKE '%%1%' ESCAPE '\\') " - "ORDER BY name COLLATE NOCASE").arg(query); + "ORDER BY name COLLATE NOCASE").arg(sanitizedQuery); } else { queryStr = QStringLiteral("SELECT ztokenname, ztypename, zpath, zanchor " " FROM ztoken " @@ -265,7 +272,7 @@ QList Docset::search(const QString &query, const CancellationToken "JOIN ztokentype " " ON ztoken.ztokentype = ztokentype.z_pk " "WHERE (ztokenname LIKE '%%1%' ESCAPE '\\') " - "ORDER BY ztokenname COLLATE NOCASE").arg(query); + "ORDER BY ztokenname COLLATE NOCASE").arg(sanitizedQuery); } // Limit for very short queries. diff --git a/src/libs/registry/docsetregistry.cpp b/src/libs/registry/docsetregistry.cpp index dbe18be00..adc234c94 100644 --- a/src/libs/registry/docsetregistry.cpp +++ b/src/libs/registry/docsetregistry.cpp @@ -158,7 +158,7 @@ void DocsetRegistry::_runQuery(const QString &query, const CancellationToken &to = QtConcurrent::mappedReduced(enabledDocsets, std::bind(&Docset::search, std::placeholders::_1, - searchQuery.sanitizedQuery(), token), + searchQuery.query(), token), &MergeQueryResults); QList results = queryResultsFuture.result(); diff --git a/src/libs/registry/searchquery.cpp b/src/libs/registry/searchquery.cpp index 2daa72464..1dedf5c01 100644 --- a/src/libs/registry/searchquery.cpp +++ b/src/libs/registry/searchquery.cpp @@ -126,16 +126,6 @@ void SearchQuery::setQuery(const QString &str) m_query = str; } -QString SearchQuery::sanitizedQuery() const -{ - QString q = m_query; - q.replace(QLatin1String("\\"), QLatin1String("\\\\")); - q.replace(QLatin1String("_"), QLatin1String("\\_")); - q.replace(QLatin1String("%"), QLatin1String("\\%")); - q.replace(QLatin1String("'"), QLatin1String("''")); - return q; -} - QDataStream &operator<<(QDataStream &out, const Zeal::Registry::SearchQuery &query) { out << query.toString(); diff --git a/src/libs/registry/searchquery.h b/src/libs/registry/searchquery.h index f0aec9c46..27fe9f243 100644 --- a/src/libs/registry/searchquery.h +++ b/src/libs/registry/searchquery.h @@ -76,9 +76,6 @@ class SearchQuery QString query() const; void setQuery(const QString &str); - /// Returns the core query, sanitized for use in SQL queries - QString sanitizedQuery() const; - private: QString m_query; QStringList m_keywords; From cf22be91d003e03f1e581711be95c496c9218763 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 22:42:37 -0400 Subject: [PATCH 257/273] registry,ui: Create page addresses during docset loading This hides the internal docset structure inside the Docset class. --- src/libs/registry/docset.cpp | 55 ++++++++++++++++++------------- src/libs/registry/docset.h | 6 ++-- src/libs/registry/searchmodel.cpp | 2 +- src/libs/registry/searchresult.h | 3 +- src/libs/ui/mainwindow.cpp | 13 ++------ 5 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index ac76ed885..f5216d91c 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include using namespace Zeal::Registry; @@ -240,7 +239,7 @@ int Docset::symbolCount(const QString &symbolType) const return m_symbolCounts.value(symbolType); } -const QMap &Docset::symbols(const QString &symbolType) const +const QMap &Docset::symbols(const QString &symbolType) const { if (!m_symbols.contains(symbolType)) loadSymbols(symbolType); @@ -284,18 +283,10 @@ QList Docset::search(const QString &query, const CancellationToken QSqlQuery sqlQuery(queryStr, database()); while (sqlQuery.next() && !token.isCanceled()) { - const QString itemName = sqlQuery.value(0).toString(); - QString path = sqlQuery.value(2).toString(); - if (m_type == Docset::Type::ZDash) { - const QString anchor = sqlQuery.value(3).toString(); - if (!anchor.isEmpty()) - path += QLatin1Char('#') + anchor; - } - - results.append({itemName, + results.append({sqlQuery.value(0).toString(), parseSymbolType(sqlQuery.value(1).toString()), const_cast(this), - path}); + createPageUrl(sqlQuery.value(2).toString(), sqlQuery.value(3).toString())}); } return results; @@ -331,14 +322,10 @@ QList Docset::relatedLinks(const QUrl &url) const QSqlQuery sqlQuery(queryStr.arg(cleanUrl.toString()), database()); while (sqlQuery.next()) { - QString sectionPath = sqlQuery.value(2).toString(); - if (m_type == Docset::Type::ZDash) - sectionPath += QLatin1Char('#') + sqlQuery.value(3).toString(); - results.append({sqlQuery.value(0).toString(), parseSymbolType(sqlQuery.value(1).toString()), const_cast(this), - sectionPath}); + createPageUrl(sqlQuery.value(2).toString(), sqlQuery.value(3).toString())}); } if (results.size() == 1) @@ -418,10 +405,8 @@ void Docset::loadSymbols(const QString &symbolType, const QString &symbolString) if (m_type == Docset::Type::Dash) { queryStr = QStringLiteral("SELECT name, path FROM searchIndex WHERE type='%1' ORDER BY name ASC"); } else { - queryStr = QStringLiteral("SELECT ztokenname AS name, " - "CASE WHEN (zanchor IS NULL) THEN zpath " - "ELSE (zpath || '#' || zanchor) " - "END AS path FROM ztoken " + queryStr = QStringLiteral("SELECT ztokenname, zpath, zanchor " + "FROM ztoken " "JOIN ztokenmetainformation ON ztoken.zmetainformation = ztokenmetainformation.z_pk " "JOIN zfilepath ON ztokenmetainformation.zfile = zfilepath.z_pk " "JOIN ztokentype ON ztoken.ztokentype = ztokentype.z_pk WHERE ztypename='%1' " @@ -434,9 +419,10 @@ void Docset::loadSymbols(const QString &symbolType, const QString &symbolString) return; } - QMap &symbols = m_symbols[symbolType]; + QMap &symbols = m_symbols[symbolType]; while (query.next()) - symbols.insertMulti(query.value(0).toString(), QDir(documentPath()).absoluteFilePath(query.value(1).toString())); + symbols.insertMulti(query.value(0).toString(), + createPageUrl(query.value(1).toString(), query.value(2).toString())); } void Docset::createIndex() @@ -475,6 +461,29 @@ void Docset::createIndex() query.exec(indexCreateQuery.arg(IndexNamePrefix, IndexNameVersion, tableName, columnName)); } +QUrl Docset::createPageUrl(const QString &path, const QString &fragment) const +{ + QString realPath; + QString realFragment; + + if (fragment.isEmpty()) { + const QStringList urlParts = path.split(QLatin1Char('#')); + realPath = urlParts[0]; + if (urlParts.size() > 1) + realFragment = urlParts[1]; + } else { + realPath = path; + realFragment = fragment; + } + + QUrl url = QUrl::fromLocalFile(QDir(documentPath()).absoluteFilePath(realPath)); + if (!realFragment.isEmpty()) { + url.setFragment(realFragment, QUrl::DecodedMode); + } + + return url; +} + QString Docset::parseSymbolType(const QString &str) { // Dash symbol aliases diff --git a/src/libs/registry/docset.h b/src/libs/registry/docset.h index 475adeb6e..bb344cdcc 100644 --- a/src/libs/registry/docset.h +++ b/src/libs/registry/docset.h @@ -27,6 +27,7 @@ #include #include #include +#include class QSqlDatabase; @@ -60,7 +61,7 @@ class Docset QMap symbolCounts() const; int symbolCount(const QString &symbolType) const; - const QMap &symbols(const QString &symbolType) const; + const QMap &symbols(const QString &symbolType) const; QList search(const QString &query, const CancellationToken &token) const; QList relatedLinks(const QUrl &url) const; @@ -81,6 +82,7 @@ class Docset void loadSymbols(const QString &symbolType) const; void loadSymbols(const QString &symbolType, const QString &symbolString) const; void createIndex(); + QUrl createPageUrl(const QString &path, const QString &fragment = QString()) const; static QString parseSymbolType(const QString &str); @@ -98,7 +100,7 @@ class Docset QMap m_symbolStrings; QMap m_symbolCounts; - mutable QMap> m_symbols; + mutable QMap> m_symbols; }; } // namespace Registry diff --git a/src/libs/registry/searchmodel.cpp b/src/libs/registry/searchmodel.cpp index 157cfd147..ba9990dd8 100644 --- a/src/libs/registry/searchmodel.cpp +++ b/src/libs/registry/searchmodel.cpp @@ -58,7 +58,7 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const case 0: return item->name; case 1: - return QDir(item->docset->documentPath()).absoluteFilePath(item->path); + return item->url; default: return QVariant(); } diff --git a/src/libs/registry/searchresult.h b/src/libs/registry/searchresult.h index 438fe5e4d..5ece8073b 100644 --- a/src/libs/registry/searchresult.h +++ b/src/libs/registry/searchresult.h @@ -25,6 +25,7 @@ #define SEARCHRESULT_H #include +#include namespace Zeal { namespace Registry { @@ -38,7 +39,7 @@ struct SearchResult Docset *docset; - QString path; + QUrl url; inline bool operator<(const SearchResult &other) const { diff --git a/src/libs/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp index d6781e0cf..d7766c687 100644 --- a/src/libs/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -495,18 +495,11 @@ void MainWindow::search(const Registry::SearchQuery &query) void MainWindow::openDocset(const QModelIndex &index) { - const QVariant urlStr = index.sibling(index.row(), 1).data(); - if (urlStr.isNull()) + const QVariant url = index.sibling(index.row(), 1).data(); + if (url.isNull()) return; - // TODO: Keep anchor separately from file address - QStringList urlParts = urlStr.toString().split(QLatin1Char('#')); - QUrl url = QUrl::fromLocalFile(urlParts[0]); - if (urlParts.count() > 1) - // NOTE: QUrl::DecodedMode is a fix for #121. Let's hope it doesn't break anything. - url.setFragment(urlParts[1], QUrl::DecodedMode); - - ui->webView->load(url); + ui->webView->load(url.toUrl()); // QWebEnginePage::load() always steals focus, so no need to do it twice. #ifndef USE_WEBENGINE From bdaba34a8c0bf70513040d9d9505f42c37825ede Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Sun, 18 Sep 2016 22:44:12 -0400 Subject: [PATCH 258/273] registry: Treat only //apple_ref URL fragments as decoded (fixes #513) --- src/libs/registry/docset.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index f5216d91c..bfe74c6a4 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -478,7 +478,10 @@ QUrl Docset::createPageUrl(const QString &path, const QString &fragment) const QUrl url = QUrl::fromLocalFile(QDir(documentPath()).absoluteFilePath(realPath)); if (!realFragment.isEmpty()) { - url.setFragment(realFragment, QUrl::DecodedMode); + if (realFragment.startsWith("//apple_ref")) + url.setFragment(realFragment, QUrl::DecodedMode); + else + url.setFragment(realFragment); } return url; From a59ae13b47d6e55d7c5f9fb50f9e3a527a461185 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 19 Sep 2016 02:26:03 -0400 Subject: [PATCH 259/273] registry: Return QUrl for docset index page (fixes #598) --- src/libs/registry/docset.cpp | 4 ++-- src/libs/registry/docset.h | 2 +- src/libs/registry/listmodel.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index bfe74c6a4..ebb052e1a 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -224,9 +224,9 @@ QIcon Docset::symbolTypeIcon(const QString &symbolType) const return icon.availableSizes().isEmpty() ? unknownIcon : icon; } -QString Docset::indexFilePath() const +QUrl Docset::indexFileUrl() const { - return QDir(documentPath()).absoluteFilePath(m_indexFilePath); + return QUrl::fromLocalFile(QDir(documentPath()).absoluteFilePath(m_indexFilePath)); } QMap Docset::symbolCounts() const diff --git a/src/libs/registry/docset.h b/src/libs/registry/docset.h index bb344cdcc..fb737c5bf 100644 --- a/src/libs/registry/docset.h +++ b/src/libs/registry/docset.h @@ -56,7 +56,7 @@ class Docset QString documentPath() const; QIcon icon() const; QIcon symbolTypeIcon(const QString &symbolType) const; - QString indexFilePath() const; + QUrl indexFileUrl() const; QMap symbolCounts() const; int symbolCount(const QString &symbolType) const; diff --git a/src/libs/registry/listmodel.cpp b/src/libs/registry/listmodel.cpp index e963aa381..863379994 100644 --- a/src/libs/registry/listmodel.cpp +++ b/src/libs/registry/listmodel.cpp @@ -75,7 +75,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const if (!index.column()) return m_docsetRegistry->docset(index.row())->title(); else - return m_docsetRegistry->docset(index.row())->indexFilePath(); + return m_docsetRegistry->docset(index.row())->indexFileUrl(); case Level::GroupLevel: { DocsetItem *docsetItem = reinterpret_cast(index.internalPointer()); const QString symbolType = docsetItem->groups.at(index.row())->symbolType; From ba859d0e46d0fedafa2101808df9f69a8fa05c01 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 19 Sep 2016 03:31:32 -0400 Subject: [PATCH 260/273] registry: Use LEFT JOIN instead of INNER JOIN in all queries Fixes #563 as a side effect! --- src/libs/registry/docset.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index ebb052e1a..06aef22fb 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -264,11 +264,11 @@ QList Docset::search(const QString &query, const CancellationToken } else { queryStr = QStringLiteral("SELECT ztokenname, ztypename, zpath, zanchor " " FROM ztoken " - "JOIN ztokenmetainformation " + "LEFT JOIN ztokenmetainformation " " ON ztoken.zmetainformation = ztokenmetainformation.z_pk " - "JOIN zfilepath " + "LEFT JOIN zfilepath " " ON ztokenmetainformation.zfile = zfilepath.z_pk " - "JOIN ztokentype " + "LEFT JOIN ztokentype " " ON ztoken.ztokentype = ztokentype.z_pk " "WHERE (ztokenname LIKE '%%1%' ESCAPE '\\') " "ORDER BY ztokenname COLLATE NOCASE").arg(sanitizedQuery); @@ -314,9 +314,9 @@ QList Docset::relatedLinks(const QUrl &url) const } else if (m_type == Docset::Type::ZDash) { queryStr = QStringLiteral("SELECT ztoken.ztokenname, ztokentype.ztypename, zfilepath.zpath, ztokenmetainformation.zanchor " "FROM ztoken " - "JOIN ztokenmetainformation ON ztoken.zmetainformation = ztokenmetainformation.z_pk " - "JOIN zfilepath ON ztokenmetainformation.zfile = zfilepath.z_pk " - "JOIN ztokentype ON ztoken.ztokentype = ztokentype.z_pk " + "LEFT JOIN ztokenmetainformation ON ztoken.zmetainformation = ztokenmetainformation.z_pk " + "LEFT JOIN zfilepath ON ztokenmetainformation.zfile = zfilepath.z_pk " + "LEFT JOIN ztokentype ON ztoken.ztokentype = ztokentype.z_pk " "WHERE zfilepath.zpath = \"%1\" AND ztokenmetainformation.zanchor IS NOT NULL"); } @@ -374,7 +374,7 @@ void Docset::countSymbols() if (m_type == Docset::Type::Dash) { queryStr = QStringLiteral("SELECT type, COUNT(*) FROM searchIndex GROUP BY type"); } else if (m_type == Docset::Type::ZDash) { - queryStr = QStringLiteral("SELECT ztypename, COUNT(*) FROM ztoken JOIN ztokentype" + queryStr = QStringLiteral("SELECT ztypename, COUNT(*) FROM ztoken LEFT JOIN ztokentype" " ON ztoken.ztokentype = ztokentype.z_pk GROUP BY ztypename"); } @@ -407,9 +407,9 @@ void Docset::loadSymbols(const QString &symbolType, const QString &symbolString) } else { queryStr = QStringLiteral("SELECT ztokenname, zpath, zanchor " "FROM ztoken " - "JOIN ztokenmetainformation ON ztoken.zmetainformation = ztokenmetainformation.z_pk " - "JOIN zfilepath ON ztokenmetainformation.zfile = zfilepath.z_pk " - "JOIN ztokentype ON ztoken.ztokentype = ztokentype.z_pk WHERE ztypename='%1' " + "LEFT JOIN ztokenmetainformation ON ztoken.zmetainformation = ztokenmetainformation.z_pk " + "LEFT JOIN zfilepath ON ztokenmetainformation.zfile = zfilepath.z_pk " + "LEFT JOIN ztokentype ON ztoken.ztokentype = ztokentype.z_pk WHERE ztypename='%1' " "ORDER BY ztokenname ASC"); } From 64f4f32a605e01df81cf4edee1b35c049b6723cd Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 19 Sep 2016 03:32:09 -0400 Subject: [PATCH 261/273] registry: Add some missing symbol type aliases --- src/libs/registry/docset.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index 06aef22fb..d851eddec 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -514,11 +514,14 @@ QString Docset::parseSymbolType(const QString &str) // Constant {QStringLiteral("data"), QStringLiteral("Constant")}, {QStringLiteral("econst"), QStringLiteral("Constant")}, + {QStringLiteral("enumdata"), QStringLiteral("Constant")}, {QStringLiteral("enumelt"), QStringLiteral("Constant")}, {QStringLiteral("clconst"), QStringLiteral("Constant")}, {QStringLiteral("structdata"), QStringLiteral("Constant")}, + {QStringLiteral("writerid"), QStringLiteral("Constant")}, {QStringLiteral("Notifications"), QStringLiteral("Constant")}, // Constructor + {QStringLiteral("structctr"), QStringLiteral("Constructor")}, {QStringLiteral("Public Constructors"), QStringLiteral("Constructor")}, // Enumeration {QStringLiteral("enum"), QStringLiteral("Enumeration")}, @@ -561,20 +564,34 @@ QString Docset::parseSymbolType(const QString &str) {QStringLiteral("macro"), QStringLiteral("Macro")}, // Method {QStringLiteral("clm"), QStringLiteral("Method")}, + {QStringLiteral("enumcm"), QStringLiteral("Method")}, + {QStringLiteral("enumctr"), QStringLiteral("Method")}, + {QStringLiteral("enumm"), QStringLiteral("Method")}, {QStringLiteral("intfctr"), QStringLiteral("Method")}, {QStringLiteral("intfcm"), QStringLiteral("Method")}, {QStringLiteral("intfm"), QStringLiteral("Method")}, + {QStringLiteral("intfsub"), QStringLiteral("Method")}, + {QStringLiteral("instsub"), QStringLiteral("Method")}, {QStringLiteral("instctr"), QStringLiteral("Method")}, {QStringLiteral("instm"), QStringLiteral("Method")}, + {QStringLiteral("structcm"), QStringLiteral("Method")}, + {QStringLiteral("structm"), QStringLiteral("Method")}, + {QStringLiteral("structsub"), QStringLiteral("Method")}, {QStringLiteral("Class Methods"), QStringLiteral("Method")}, {QStringLiteral("Inherited Methods"), QStringLiteral("Method")}, {QStringLiteral("Instance Methods"), QStringLiteral("Method")}, {QStringLiteral("Private Methods"), QStringLiteral("Method")}, {QStringLiteral("Protected Methods"), QStringLiteral("Method")}, {QStringLiteral("Public Methods"), QStringLiteral("Method")}, + // Operator + {QStringLiteral("intfopfunc"), QStringLiteral("Operator")}, + {QStringLiteral("opfunc"), QStringLiteral("Operator")}, // Property + {QStringLiteral("enump"), QStringLiteral("Property")}, + {QStringLiteral("intfdata"), QStringLiteral("Property")}, {QStringLiteral("intfp"), QStringLiteral("Property")}, {QStringLiteral("instp"), QStringLiteral("Property")}, + {QStringLiteral("structp"), QStringLiteral("Property")}, {QStringLiteral("Inherited Properties"), QStringLiteral("Property")}, {QStringLiteral("Private Properties"), QStringLiteral("Property")}, {QStringLiteral("Protected Properties"), QStringLiteral("Property")}, From fed639b5fb71f3a69673d167ec528991d03a4be3 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 19 Sep 2016 21:24:39 -0400 Subject: [PATCH 262/273] registry: Prefer index file path provided by docset --- src/libs/registry/docset.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index d851eddec..b21495374 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -153,11 +153,11 @@ Docset::Docset(const QString &path) : m_keywords.removeDuplicates(); - // Try to find index path if metadata is missing one - if (m_indexFilePath.isEmpty()) { - if (plist.contains(InfoPlist::DashIndexFilePath)) - m_indexFilePath = plist[InfoPlist::DashIndexFilePath].toString(); - else if (dir.exists(QStringLiteral("index.html"))) + // Prefer index path provided by the docset over metadata. + if (plist.contains(InfoPlist::DashIndexFilePath)) { + m_indexFilePath = plist[InfoPlist::DashIndexFilePath].toString(); + } else if (m_indexFilePath.isEmpty()) { + if (dir.exists(QStringLiteral("index.html"))) m_indexFilePath = QStringLiteral("index.html"); else qWarning("Cannot determine index file for docset %s", qPrintable(m_name)); From 94a37f73c3b6cd9cfa5946c6601a34b42bf81d27 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 19 Sep 2016 21:37:32 -0400 Subject: [PATCH 263/273] registry: Build index page URL only once --- src/libs/registry/docset.cpp | 10 +++++----- src/libs/registry/docset.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index b21495374..05cc1fcda 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -155,10 +155,10 @@ Docset::Docset(const QString &path) : // Prefer index path provided by the docset over metadata. if (plist.contains(InfoPlist::DashIndexFilePath)) { - m_indexFilePath = plist[InfoPlist::DashIndexFilePath].toString(); - } else if (m_indexFilePath.isEmpty()) { + m_indexFileUrl = createPageUrl(plist[InfoPlist::DashIndexFilePath].toString()); + } else if (m_indexFileUrl.isEmpty()) { if (dir.exists(QStringLiteral("index.html"))) - m_indexFilePath = QStringLiteral("index.html"); + m_indexFileUrl = createPageUrl(QStringLiteral("index.html")); else qWarning("Cannot determine index file for docset %s", qPrintable(m_name)); } @@ -226,7 +226,7 @@ QIcon Docset::symbolTypeIcon(const QString &symbolType) const QUrl Docset::indexFileUrl() const { - return QUrl::fromLocalFile(QDir(documentPath()).absoluteFilePath(m_indexFilePath)); + return m_indexFileUrl; } QMap Docset::symbolCounts() const @@ -364,7 +364,7 @@ void Docset::loadMetadata() if (jsonObject.contains(QStringLiteral("extra"))) { const QJsonObject extra = jsonObject[QStringLiteral("extra")].toObject(); - m_indexFilePath = extra[QStringLiteral("indexFilePath")].toString(); + m_indexFileUrl = createPageUrl(extra[QStringLiteral("indexFilePath")].toString()); } } diff --git a/src/libs/registry/docset.h b/src/libs/registry/docset.h index fb737c5bf..0f2960feb 100644 --- a/src/libs/registry/docset.h +++ b/src/libs/registry/docset.h @@ -96,7 +96,7 @@ class Docset QString m_path; QIcon m_icon; - QString m_indexFilePath; + QUrl m_indexFileUrl; QMap m_symbolStrings; QMap m_symbolCounts; From eb3fccee23bccc731cee74f28d2fc8af58a25a50 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Mon, 19 Sep 2016 21:54:21 -0400 Subject: [PATCH 264/273] registry: Strip out from page URLs (fixes #596) --- src/libs/registry/docset.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index 05cc1fcda..b28c48b5b 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -476,6 +477,10 @@ QUrl Docset::createPageUrl(const QString &path, const QString &fragment) const realFragment = fragment; } + static const QRegularExpression dashEntryRegExp(QLatin1String("")); + realPath.remove(dashEntryRegExp); + realFragment.remove(dashEntryRegExp); + QUrl url = QUrl::fromLocalFile(QDir(documentPath()).absoluteFilePath(realPath)); if (!realFragment.isEmpty()) { if (realFragment.startsWith("//apple_ref")) From 236eb007e4a2d8b9e83f9218d2fd4eba75c9b970 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Wed, 21 Sep 2016 21:20:55 -0400 Subject: [PATCH 265/273] registry: Do not use CFBundleName and docset name as a keyword #383 for more details. --- src/libs/registry/docset.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libs/registry/docset.cpp b/src/libs/registry/docset.cpp index b28c48b5b..c6e7395da 100644 --- a/src/libs/registry/docset.cpp +++ b/src/libs/registry/docset.cpp @@ -149,9 +149,6 @@ Docset::Docset(const QString &path) : m_keywords << kw; } - // TODO: Use 'unknown' instead of CFBundleName? (See #383) - m_keywords << plist.value(InfoPlist::CFBundleName, m_name).toString().toLower(); - m_keywords.removeDuplicates(); // Prefer index path provided by the docset over metadata. From 797cd7953bcac35067dac62d738e86e10cfe93eb Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 00:30:33 -0400 Subject: [PATCH 266/273] ui: Add ability to start a docset update by a double click --- src/libs/ui/docsetsdialog.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index d78a8b3d4..871465658 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -85,6 +85,13 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : // Installed docsets tab ui->installedDocsetList->setItemDelegate(new DocsetListItemDelegate(this)); ui->installedDocsetList->setModel(new ListModel(app->docsetRegistry(), this)); + connect(ui->installedDocsetList, &QListView::activated, this, [this](const QModelIndex &index) { + if (!index.data(ListModel::UpdateAvailableRole).toBool()) { + return; + } + + downloadDashDocset(index.data(Registry::ListModel::DocsetNameRole).toString()); + }); QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); connect(selectionModel, &QItemSelectionModel::selectionChanged, From f7ecf2920d55e4dd390847943f40050ccb43eb93 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 02:12:48 -0400 Subject: [PATCH 267/273] ui: Use model indexes instead of list items where possible --- src/libs/ui/docsetsdialog.cpp | 81 ++++++++++++++++------------------- src/libs/ui/docsetsdialog.h | 2 +- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 871465658..3eed5f37f 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -90,7 +90,7 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : return; } - downloadDashDocset(index.data(Registry::ListModel::DocsetNameRole).toString()); + downloadDashDocset(index); }); QItemSelectionModel *selectionModel = ui->installedDocsetList->selectionModel(); @@ -104,6 +104,7 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : return; } } + ui->updateSelectedDocsetsButton->setEnabled(false); }); connect(ui->updateSelectedDocsetsButton, &QPushButton::clicked, @@ -117,40 +118,31 @@ DocsetsDialog::DocsetsDialog(Core::Application *app, QWidget *parent) : // Available docsets tab ui->availableDocsetList->setItemDelegate(new ProgressItemDelegate(this)); - connect(ui->availableDocsetList, &QListWidget::itemActivated, - this, [this](QListWidgetItem *item) { - - item->setSelected(false); - - // Do nothing if download is already in progress - if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) + connect(ui->availableDocsetList, &QListView::activated, this, [this](const QModelIndex &index) { + // TODO: Cancel download if it's already in progress. + if (index.data(ProgressItemDelegate::ShowProgressRole).toBool()) return; - item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); - item->setData(ProgressItemDelegate::ValueRole, 0); - item->setData(ProgressItemDelegate::ShowProgressRole, true); + ui->availableDocsetList->selectionModel()->select(index, QItemSelectionModel::Deselect); - downloadDashDocset(item->data(Registry::ListModel::DocsetNameRole).toString()); + QAbstractItemModel *model = ui->availableDocsetList->model(); + model->setData(index, tr("Downloading: %p%"), ProgressItemDelegate::FormatRole); + model->setData(index, 0, ProgressItemDelegate::ValueRole); + model->setData(index, true, ProgressItemDelegate::ShowProgressRole); + + downloadDashDocset(index); }); selectionModel = ui->availableDocsetList->selectionModel(); - connect(selectionModel, &QItemSelectionModel::selectionChanged, - [this, selectionModel]() { - bool hasSelection = false; - + connect(selectionModel, &QItemSelectionModel::selectionChanged, [this, selectionModel]() { for (const QModelIndex &index : selectionModel->selectedIndexes()) { - const QString docsetName = index.data(Registry::ListModel::DocsetNameRole).toString(); - QListWidgetItem *item = findDocsetListItem(docsetName); - - // Do nothing if download is already in progress - if (!item || item->data(ProgressItemDelegate::ShowProgressRole).toBool()) - continue; - - hasSelection = true; - break; + if (!index.data(ProgressItemDelegate::ShowProgressRole).toBool()) { + ui->downloadDocsetsButton->setEnabled(true); + return; + } } - ui->downloadDocsetsButton->setEnabled(hasSelection); + ui->downloadDocsetsButton->setEnabled(false); }); connect(ui->downloadDocsetsButton, &QPushButton::clicked, @@ -229,17 +221,19 @@ void DocsetsDialog::updateSelectedDocsets() if (!index.data(Registry::ListModel::UpdateAvailableRole).toBool()) continue; - downloadDashDocset(index.data(Registry::ListModel::DocsetNameRole).toString()); + downloadDashDocset(index); } } void DocsetsDialog::updateAllDocsets() { - for (const Registry::Docset * const docset : m_docsetRegistry->docsets()) { - if (!docset->hasUpdate) + QAbstractItemModel *model = ui->installedDocsetList->model(); + for (int i = 0; i < model->rowCount(); ++i) { + const QModelIndex index = model->index(i, 0); + if (!index.data(Registry::ListModel::UpdateAvailableRole).toBool()) continue; - downloadDashDocset(docset->name()); + downloadDashDocset(index); } } @@ -291,23 +285,20 @@ void DocsetsDialog::updateDocsetFilter(const QString &filterString) void DocsetsDialog::downloadSelectedDocsets() { - for (const QModelIndex &index : ui->availableDocsetList->selectionModel()->selectedIndexes()) { - const QString docsetName = index.data(Registry::ListModel::DocsetNameRole).toString(); - QListWidgetItem *item = findDocsetListItem(docsetName); - if (!item) - continue; - - item->setSelected(false); + QItemSelectionModel *selectionModel = ui->availableDocsetList->selectionModel(); + for (const QModelIndex &index : selectionModel->selectedIndexes()) { + selectionModel->select(index, QItemSelectionModel::Deselect); - // Do nothing if download is already in progress - if (item->data(ProgressItemDelegate::ShowProgressRole).toBool()) + // Do nothing if a download is already in progress. + if (index.data(ProgressItemDelegate::ShowProgressRole).toBool()) continue; - item->setData(ProgressItemDelegate::FormatRole, tr("Downloading: %p%")); - item->setData(ProgressItemDelegate::ValueRole, 0); - item->setData(ProgressItemDelegate::ShowProgressRole, true); + QAbstractItemModel *model = ui->availableDocsetList->model(); + model->setData(index, tr("Downloading: %p%"), ProgressItemDelegate::FormatRole); + model->setData(index, 0, ProgressItemDelegate::ValueRole); + model->setData(index, true, ProgressItemDelegate::ShowProgressRole); - downloadDashDocset(docsetName); + downloadDashDocset(index); } } @@ -675,8 +666,10 @@ void DocsetsDialog::processDocsetList(const QJsonArray &list) ui->installedDocsetList->reset(); } -void DocsetsDialog::downloadDashDocset(const QString &name) +void DocsetsDialog::downloadDashDocset(const QModelIndex &index) { + const QString name = index.data(Registry::ListModel::DocsetNameRole).toString(); + if (!m_availableDocsets.contains(name)) return; diff --git a/src/libs/ui/docsetsdialog.h b/src/libs/ui/docsetsdialog.h index a3a62e4e8..d8a9de33a 100644 --- a/src/libs/ui/docsetsdialog.h +++ b/src/libs/ui/docsetsdialog.h @@ -107,7 +107,7 @@ private slots: void downloadDocsetList(); void processDocsetList(const QJsonArray &list); - void downloadDashDocset(const QString &name); + void downloadDashDocset(const QModelIndex &index); void removeDocset(const QString &name); void updateCombinedProgress(); From f69004ebbb40a93afa20499c191b8c333ea01cad Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 02:14:04 -0400 Subject: [PATCH 268/273] ui: Fix redundant download state resets in DocsetsDialog --- src/libs/ui/docsetsdialog.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 3eed5f37f..bd869e158 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -342,9 +342,7 @@ void DocsetsDialog::downloadCompleted() listItem->setData(ProgressItemDelegate::ShowProgressRole, false); } - if (m_replies.isEmpty()) - resetProgress(); - + resetProgress(); return; } @@ -390,7 +388,6 @@ void DocsetsDialog::downloadCompleted() } processDocsetList(jsonDoc.array()); - resetProgress(); break; } @@ -526,7 +523,6 @@ void DocsetsDialog::extractionError(const QString &filePath, const QString &erro if (listItem) listItem->setData(ProgressItemDelegate::ShowProgressRole, false); - resetProgress(); delete m_tmpFiles.take(docsetName); } @@ -621,6 +617,7 @@ void DocsetsDialog::cancelDownloads() reply->abort(); } + resetProgress(); } @@ -702,8 +699,6 @@ void DocsetsDialog::removeDocset(const QString &name) m_docsetRegistry->remove(name); - updateCombinedProgress(); - QFuture future = QtConcurrent::run([tmpPath] { return QDir(tmpPath).removeRecursively(); }); @@ -723,18 +718,13 @@ void DocsetsDialog::removeDocset(const QString &name) watcher->deleteLater(); m_docsetsBeingDeleted.removeOne(name); - - updateCombinedProgress(); }); } void DocsetsDialog::updateCombinedProgress() { - if (m_replies.isEmpty() && m_tmpFiles.isEmpty() && m_docsetsBeingDeleted.isEmpty()) { - ui->cancelButton->hide(); - ui->combinedProgressBar->hide(); - ui->combinedProgressBar->setMaximum(100); - ui->combinedProgressBar->setValue(0); + if (m_replies.isEmpty()) { + resetProgress(); return; } @@ -765,6 +755,7 @@ void DocsetsDialog::resetProgress() break; } } + ui->updateSelectedDocsetsButton->setEnabled(hasSelectedUpdates); ui->updateAllDocsetsButton->setEnabled(updatesAvailable()); ui->removeDocsetsButton->setEnabled(selectionModel->hasSelection()); From e642cb509d7f735984f9a33cbd0eee702a3b1e1d Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 02:20:26 -0400 Subject: [PATCH 269/273] ui: Use QWebView::load() instead of setUrl() --- src/libs/ui/widgets/webview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ui/widgets/webview.cpp b/src/libs/ui/widgets/webview.cpp index 224bb5c58..bcb132af9 100644 --- a/src/libs/ui/widgets/webview.cpp +++ b/src/libs/ui/widgets/webview.cpp @@ -95,7 +95,7 @@ void WebView::mouseReleaseEvent(QMouseEvent *event) case Qt::MiddleButton: if (m_clickedLink == clickedLink(event->pos()) && m_clickedLink.isValid()) { QWebView *webView = createWindow(QWebPage::WebBrowserWindow); - webView->setUrl(m_clickedLink); + webView->load(m_clickedLink); event->accept(); } break; From 380031d34a043d1f96559eb926d7d2fb85fc55c5 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 20:51:15 -0400 Subject: [PATCH 270/273] qmake: Use Qt WebKit by default --- qmake/common.pri | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/qmake/common.pri b/qmake/common.pri index d6d2af612..dd7b99d0b 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -34,15 +34,12 @@ VERSION = 0.2.1 DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" # Browser engine -CONFIG(zeal_qtwebkit) { - qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit - else: error("Qt WebKit is not available.") -} else:CONFIG(zeal_qtwebengine) { +CONFIG(zeal_qtwebengine) { qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine else: error("Qt WebEngine is not available.") } else { - qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine - else: qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit + qtHaveModule(webkitwidgets): BROWSER_ENGINE = qtwebkit + else: qtHaveModule(webenginewidgets): BROWSER_ENGINE = qtwebengine else: error("Zeal requires Qt WebEngine or Qt WebKit.") } From 14c72d38aaf88ab8f4f029880aab385ac0c4879c Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 21:39:36 -0400 Subject: [PATCH 271/273] qmake: Add Qt Network dependency for Core --- src/libs/core/core.pri | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/core/core.pri b/src/libs/core/core.pri index b9c3197c6..0f7c62ea3 100644 --- a/src/libs/core/core.pri +++ b/src/libs/core/core.pri @@ -1,5 +1,7 @@ ZEAL_LIB_NAME = Core +QT += network + unix:!macx { CONFIG += link_pkgconfig PKGCONFIG += libarchive From eb95d58cfd16831a793ed08077d54b178c970639 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 21:40:29 -0400 Subject: [PATCH 272/273] qmake: Reduce qmake log output --- qmake/common.pri | 3 --- src/libs/ui/ui.pri | 14 +++++--------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/qmake/common.pri b/qmake/common.pri index dd7b99d0b..397cbe40a 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -57,12 +57,9 @@ equals(BROWSER_ENGINE, qtwebengine) { CONFIG(zeal_portable) { message("Portable build: Yes.") DEFINES += PORTABLE_BUILD -} else { - message("Portable build: No.") } # Unix installation prefix unix:!macx { isEmpty(PREFIX): PREFIX = /usr - message("Install prefix: $$PREFIX") } diff --git a/src/libs/ui/ui.pri b/src/libs/ui/ui.pri index 037c979bd..e3933b077 100644 --- a/src/libs/ui/ui.pri +++ b/src/libs/ui/ui.pri @@ -2,15 +2,11 @@ ZEAL_LIB_NAME = Ui QT += widgets -unix:!macx { - packagesExist(appindicator-0.1) { - CONFIG += link_pkgconfig - PKGCONFIG += appindicator-0.1 gtk+-2.0 - DEFINES += USE_APPINDICATOR - message("AppIndicator support: Yes.") - } else { - message("AppIndicator support: No.") - } +unix:!macx:packagesExist(appindicator-0.1) { + CONFIG += link_pkgconfig + PKGCONFIG += appindicator-0.1 gtk+-2.0 + DEFINES += USE_APPINDICATOR + message("AppIndicator support: Yes.") } # QxtGlobalShortcut dependencies From 1b11c54bfad6407a3614832700345770858ddcfc Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Thu, 22 Sep 2016 23:52:54 -0400 Subject: [PATCH 273/273] Bump version to 0.3.0 --- qmake/common.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/common.pri b/qmake/common.pri index 397cbe40a..4e26c76b7 100644 --- a/qmake/common.pri +++ b/qmake/common.pri @@ -30,7 +30,7 @@ RCC_DIR = $$BUILD_ROOT/.rcc UI_DIR = $$BUILD_ROOT/.ui # Application version -VERSION = 0.2.1 +VERSION = 0.3.0 DEFINES += ZEAL_VERSION=\\\"$${VERSION}\\\" # Browser engine