From d842a288f7fc55cece9ef8ca2b0492a6fce69ee5 Mon Sep 17 00:00:00 2001 From: Adam Lamar Date: Mon, 26 Feb 2024 22:18:34 +0000 Subject: [PATCH] Initial Qt6 support --- .gitignore | 12 +++ README.md | 32 ++++++++ kiwix-desktop.pro | 3 +- resources/i18n/en.json | 1 + src/blobbuffer.h | 1 + src/contentmanager.cpp | 2 +- src/contentmanagerdelegate.cpp | 13 +++- src/flowlayout.h | 1 + src/fullscreenwindow.cpp | 4 +- src/fullscreenwindow.h | 3 +- src/kiwixapp.cpp | 55 ++++++++----- src/kprofile.cpp | 8 ++ src/kprofile.h | 10 +++ src/main.cpp | 4 +- src/mainwindow.cpp | 7 +- src/mainwindow.h | 2 +- src/portutils.h | 39 ++++++++++ src/settingsmanager.cpp | 15 +++- src/tabbar.cpp | 4 +- src/topwidget.cpp | 18 +++-- src/urlschemehandler.h | 1 + src/webpage.h | 1 + src/webview.cpp | 78 +++++++++++++++---- src/webview.h | 4 +- .../QtSingleApplication/src/qtlocalpeer.cpp | 22 ++++-- .../QtSingleApplication/src/qtlockedfile.h | 3 + 26 files changed, 280 insertions(+), 63 deletions(-) create mode 100644 src/portutils.h diff --git a/.gitignore b/.gitignore index c544c386..7f672be8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,18 @@ *.exe *.out *.app +/kiwix-desktop # QtCreator Environment Settings (not suitable for sharing) kiwix-desktop.pro.user + +# Qt autogenerated files +/qrc_*.cpp +/ui_*.h +/moc_*.h +/moc_*.cpp +/Makefile +/.qmake.stash + +# IDE files +/.vscode diff --git a/README.md b/README.md index dfb8c7fb..329940b1 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,38 @@ You may want to simply open the kiwix-desktop project in QtCreator and then compile the project from there (don't forget to update `PKG_CONFIG_PATH` if necessary). +Compilation with Qt6 +-------------------- + +There is initial support for Qt6. Additional packages are needed: + +```bash +sudo apt install qt6-base-dev qt6-base-dev-tools qt6-webengine-dev libqt6webenginecore6-bin libqt6svg6 +``` + +And `qmake` needs to be configured to use Qt6. First confirm `qmake` is using the right version: + +```bash +qtchooser -install qt6 $(which qmake6) # run once +export QT_SELECT=qt6 # set in environments where Qt6 builds are desired +qmake --version +``` + +produces this output: + +```bash +$ qmake --version +QMake version 3.1 +Using Qt version 6.2.4 in /usr/lib/aarch64-linux-gnu +``` + +then build as normal: + +```bash +qmake . +make +``` + Installation ------------ diff --git a/kiwix-desktop.pro b/kiwix-desktop.pro index b1e02197..74ec4677 100644 --- a/kiwix-desktop.pro +++ b/kiwix-desktop.pro @@ -30,7 +30,7 @@ DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ @@ -124,6 +124,7 @@ HEADERS += \ src/fullscreennotification.h \ src/menuproxystyle.h \ src/zimview.h \ + src/portutils.h \ FORMS += \ src/choiceitem.ui \ diff --git a/resources/i18n/en.json b/resources/i18n/en.json index d7d9ec6f..504dc0da 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -125,6 +125,7 @@ "ok":"ok", "no-filter":"no filter", "open-link-in-web-browser":"Open link in web browser", + "open-link-new-tab":"Open link in new tab", "download-dir-dialog-title":"Are you sure you want to change the download directory?", "download-dir-dialog-msg":"The new download directory path will be:\n{{DIRECTORY}}", "invalid-port":"Invalid port", diff --git a/src/blobbuffer.h b/src/blobbuffer.h index bd8df52e..72c8fe9d 100644 --- a/src/blobbuffer.h +++ b/src/blobbuffer.h @@ -6,6 +6,7 @@ class BlobBuffer : public QBuffer { + Q_OBJECT public: BlobBuffer(zim::Blob m_blob); virtual ~BlobBuffer() = default; diff --git a/src/contentmanager.cpp b/src/contentmanager.cpp index d5fb8f75..361d6480 100644 --- a/src/contentmanager.cpp +++ b/src/contentmanager.cpp @@ -316,7 +316,7 @@ ContentManager::BookInfo ContentManager::getBookInfos(QString id, const QStringL QStringList tagList = QString::fromStdString(b->getTags()).split(';'); QMap displayTagMap; for(auto tag: tagList) { - if (tag[0] == "_") { + if (tag[0] == '_') { auto splitTag = tag.split(":"); displayTagMap[splitTag[0]] = splitTag[1] == "yes" ? true:false; } diff --git a/src/contentmanagerdelegate.cpp b/src/contentmanagerdelegate.cpp index 8944026c..6f095500 100644 --- a/src/contentmanagerdelegate.cpp +++ b/src/contentmanagerdelegate.cpp @@ -2,11 +2,12 @@ #include "contentmanagerdelegate.h" #include #include -#include +#include #include "kiwixapp.h" #include #include "rownode.h" #include "descriptionnode.h" +#include "portutils.h" ContentManagerDelegate::ContentManagerDelegate(QObject *parent) : QStyledItemDelegate(parent), baseButton(new QPushButton) @@ -198,7 +199,11 @@ void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem } if (index.column() == 1) { auto bFont = painter->font(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) bFont.setWeight(60); +#else + bFont.setWeight(QFont::DemiBold); +#endif eOpt.font = bFont; } QStyledItemDelegate::paint(painter, eOpt, index); @@ -209,8 +214,8 @@ bool ContentManagerDelegate::editorEvent(QEvent *event, QAbstractItemModel *mode if(event->type() == QEvent::MouseButtonRelease ) { QMouseEvent * e = (QMouseEvent *)event; - int clickX = e->x(); - int clickY = e->y(); + int clickX = portutils::getX(*e); + int clickY = portutils::getY(*e); QRect r = option.rect; int x,y,w,h; @@ -238,7 +243,7 @@ void ContentManagerDelegate::handleLastColumnClicked(const QModelIndex& index, Q { const auto node = static_cast(index.internalPointer()); const auto id = node->getBookId(); - int clickX = mouseEvent->x(); + int clickX = portutils::getX(*mouseEvent); QRect r = option.rect; int x = r.left(); diff --git a/src/flowlayout.h b/src/flowlayout.h index d98defca..da4e7b10 100644 --- a/src/flowlayout.h +++ b/src/flowlayout.h @@ -57,6 +57,7 @@ //! [0] class FlowLayout : public QLayout { + Q_OBJECT public: explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); diff --git a/src/fullscreenwindow.cpp b/src/fullscreenwindow.cpp index 11f208ca..bff20198 100644 --- a/src/fullscreenwindow.cpp +++ b/src/fullscreenwindow.cpp @@ -1,3 +1,5 @@ +class QMenu; + #include "fullscreenwindow.h" #include @@ -41,4 +43,4 @@ void FullScreenWindow::resizeEvent(QResizeEvent *event) m_notification->setGeometry(notificationGeometry); QWidget::resizeEvent(event); -} \ No newline at end of file +} diff --git a/src/fullscreenwindow.h b/src/fullscreenwindow.h index a053005a..1d6d016e 100644 --- a/src/fullscreenwindow.h +++ b/src/fullscreenwindow.h @@ -1,6 +1,7 @@ #ifndef FULLSCREENWINDOW_H #define FULLSCREENWINDOW_H +class QMenu; #include #include #include "fullscreennotification.h" @@ -28,4 +29,4 @@ class FullScreenWindow : public QWidget QRect m_oldGeometry; }; -#endif // FULLSCREENWINDOW_H \ No newline at end of file +#endif // FULLSCREENWINDOW_H diff --git a/src/kiwixapp.cpp b/src/kiwixapp.cpp index 290358ad..1e067551 100644 --- a/src/kiwixapp.cpp +++ b/src/kiwixapp.cpp @@ -40,8 +40,13 @@ KiwixApp::KiwixApp(int& argc, char *argv[]) QMessageBox::critical(nullptr, "Translation error", e.what()); return; } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) m_qtTranslator.load(QLocale(), "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath)); +#else + m_qtTranslator.load(QLocale(), "qt", "_", + QLibraryInfo::path(QLibraryInfo::TranslationsPath)); +#endif installTranslator(&m_qtTranslator); m_appTranslator.load(QLocale(), "kiwix-desktop", "_", ":/i18n/"); @@ -201,6 +206,7 @@ void KiwixApp::printPage() { if(!getTabWidget()->currentZimView()) return; + QPrinter* printer = new QPrinter(); QPrintDialog printDialog(printer, mp_mainWindow); printDialog.setStyle(nullptr); @@ -209,12 +215,23 @@ void KiwixApp::printPage() auto webview = getTabWidget()->currentWebView(); if(!webview) return; + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) webview->page()->print(printer, [=](bool success) { if (!success) { showMessage(gt("print-page-error"), gt("error-title"), QMessageBox::Critical); } delete printer; }); +#else + webview->print(printer); + connect(webview, &QWebEngineView::printFinished, this, [=](bool success) { + if (!success) { + showMessage(gt("print-page-error"), gt("error-title"), QMessageBox::Critical); + } + delete printer; + }); +#endif } } @@ -329,25 +346,25 @@ void KiwixApp::setMonitorDir(const QString &dir) { void KiwixApp::createAction() { - CREATE_ACTION_ICON_SHORTCUT(KiwixServeAction, "share", gt("local-kiwix-server"), QKeySequence(Qt::CTRL+Qt::Key_I)); + CREATE_ACTION_ICON_SHORTCUT(KiwixServeAction, "share", gt("local-kiwix-server"), QKeySequence(Qt::CTRL | Qt::Key_I)); - CREATE_ACTION_ICON_SHORTCUT(RandomArticleAction, "random", gt("random-article"), QKeySequence(Qt::CTRL+Qt::Key_R)); + CREATE_ACTION_ICON_SHORTCUT(RandomArticleAction, "random", gt("random-article"), QKeySequence(Qt::CTRL | Qt::Key_R)); connect(mpa_actions[RandomArticleAction], &QAction::triggered, this, [=]() { this->openRandomUrl(false); }); - CREATE_ACTION_SHORTCUT(OpenHomePageAction, gt("home-page"), QKeySequence(Qt::ALT + Qt::Key_Home)); + CREATE_ACTION_SHORTCUT(OpenHomePageAction, gt("home-page"), QKeySequence(Qt::ALT | Qt::Key_Home)); if (QGuiApplication::isLeftToRight()) { - CREATE_ACTION_ICON_SHORTCUT(HistoryBackAction, "history-left", gt("back"), QKeySequence(Qt::ALT + Qt::Key_Left)); + CREATE_ACTION_ICON_SHORTCUT(HistoryBackAction, "history-left", gt("back"), QKeySequence(Qt::ALT | Qt::Key_Left)); } else { - CREATE_ACTION_ICON_SHORTCUT(HistoryBackAction, "history-right", gt("back"), QKeySequence(Qt::ALT + Qt::Key_Right)); + CREATE_ACTION_ICON_SHORTCUT(HistoryBackAction, "history-right", gt("back"), QKeySequence(Qt::ALT | Qt::Key_Right)); } DISABLE_ACTION(HistoryBackAction); if (QGuiApplication::isLeftToRight()) { - CREATE_ACTION_ICON_SHORTCUT(HistoryForwardAction, "history-right", gt("forward"), QKeySequence(Qt::ALT + Qt::Key_Right)); + CREATE_ACTION_ICON_SHORTCUT(HistoryForwardAction, "history-right", gt("forward"), QKeySequence(Qt::ALT | Qt::Key_Right)); } else { - CREATE_ACTION_ICON_SHORTCUT(HistoryForwardAction, "history-left", gt("forward"), QKeySequence(Qt::ALT + Qt::Key_Left)); + CREATE_ACTION_ICON_SHORTCUT(HistoryForwardAction, "history-left", gt("forward"), QKeySequence(Qt::ALT | Qt::Key_Left)); } DISABLE_ACTION(HistoryForwardAction); @@ -357,13 +374,13 @@ void KiwixApp::createAction() CREATE_ACTION_ICON_SHORTCUT(NewTabAction,"new-tab-icon", gt("new-tab"), QKeySequence::AddTab); - CREATE_ACTION_ICON_SHORTCUTS(CloseTabAction, "close", gt("close-tab"), QList({QKeySequence(Qt::CTRL + Qt::Key_F4), QKeySequence(Qt::CTRL + Qt::Key_W)})); + CREATE_ACTION_ICON_SHORTCUTS(CloseTabAction, "close", gt("close-tab"), QList({QKeySequence(Qt::CTRL | Qt::Key_F4), QKeySequence(Qt::CTRL | Qt::Key_W)})); mpa_actions[CloseTabAction]->setIconVisibleInMenu(false); - CREATE_ACTION_SHORTCUT(ReopenClosedTabAction, gt("reopen-closed-tab"), QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_T)); + CREATE_ACTION_SHORTCUT(ReopenClosedTabAction, gt("reopen-closed-tab"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_T)); HIDE_ACTION(ReopenClosedTabAction); - CREATE_ACTION_SHORTCUT(BrowseLibraryAction, gt("browse-library"), QKeySequence(Qt::CTRL+Qt::Key_E)); + CREATE_ACTION_SHORTCUT(BrowseLibraryAction, gt("browse-library"), QKeySequence(Qt::CTRL | Qt::Key_E)); HIDE_ACTION(BrowseLibraryAction); CREATE_ACTION_ICON_SHORTCUT(OpenFileAction, "open-file", gt("open-file"), QKeySequence::Open); @@ -379,10 +396,10 @@ void KiwixApp::createAction() HIDE_ACTION(SavePageAsAction); */ - CREATE_ACTION_SHORTCUT(SearchArticleAction, gt("search-article"), QKeySequence(Qt::CTRL+Qt::Key_L)); + CREATE_ACTION_SHORTCUT(SearchArticleAction, gt("search-article"), QKeySequence(Qt::CTRL | Qt::Key_L)); HIDE_ACTION(SearchArticleAction); - CREATE_ACTION_SHORTCUT(SearchLibraryAction, gt("search-in-library"), QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_R)); + CREATE_ACTION_SHORTCUT(SearchLibraryAction, gt("search-in-library"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_R)); HIDE_ACTION(SearchLibraryAction); CREATE_ACTION(FindInPageAction, gt("find-in-page")); @@ -400,20 +417,20 @@ void KiwixApp::createAction() }); mpa_actions[ToggleFullscreenAction]->setCheckable(true); - CREATE_ACTION_SHORTCUT(ToggleTOCAction, gt("table-of-content"), QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_1)); + CREATE_ACTION_SHORTCUT(ToggleTOCAction, gt("table-of-content"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_1)); HIDE_ACTION(ToggleTOCAction); - CREATE_ACTION_ONOFF_ICON_SHORTCUT(ToggleReadingListAction, "reading-list-active", "reading-list", gt("reading-list"), QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_2)); + CREATE_ACTION_ONOFF_ICON_SHORTCUT(ToggleReadingListAction, "reading-list-active", "reading-list", gt("reading-list"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_2)); - CREATE_ACTION_SHORTCUTS(ZoomInAction, gt("zoom-in"), QList({QKeySequence::ZoomIn, QKeySequence(Qt::CTRL+Qt::Key_Equal)})); + CREATE_ACTION_SHORTCUTS(ZoomInAction, gt("zoom-in"), QList({QKeySequence::ZoomIn, QKeySequence(Qt::CTRL | Qt::Key_Equal)})); CREATE_ACTION_SHORTCUT(ZoomOutAction, gt("zoom-out"), QKeySequence::ZoomOut); - CREATE_ACTION_SHORTCUT(ZoomResetAction, gt("zoom-reset"), QKeySequence(Qt::CTRL+Qt::Key_0)); + CREATE_ACTION_SHORTCUT(ZoomResetAction, gt("zoom-reset"), QKeySequence(Qt::CTRL | Qt::Key_0)); - CREATE_ACTION_SHORTCUT(NextTabAction, gt("next-tab"), QKeySequence(Qt::CTRL + Qt::Key_Tab)); + CREATE_ACTION_SHORTCUT(NextTabAction, gt("next-tab"), QKeySequence(Qt::CTRL | Qt::Key_Tab)); - CREATE_ACTION_SHORTCUT(PreviousTabAction, gt("previous-tab"), QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab)); + CREATE_ACTION_SHORTCUT(PreviousTabAction, gt("previous-tab"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Tab)); CREATE_ACTION_SHORTCUT(HelpAction, gt("help"), QKeySequence::HelpContents); HIDE_ACTION(HelpAction); @@ -431,7 +448,7 @@ void KiwixApp::createAction() CREATE_ACTION_ICON_SHORTCUT(SettingAction, "settings", gt("settings"), QKeySequence(Qt::Key_F12)); - CREATE_ACTION_ICON_SHORTCUT(DonateAction, "donate", gt("donate-to-support-kiwix"), QKeySequence(Qt::CTRL+Qt::Key_D)); + CREATE_ACTION_ICON_SHORTCUT(DonateAction, "donate", gt("donate-to-support-kiwix"), QKeySequence(Qt::CTRL | Qt::Key_D)); CREATE_ACTION_ICON_SHORTCUT(ExitAction, "exit", gt("exit"), QKeySequence::Quit); } diff --git a/src/kprofile.cpp b/src/kprofile.cpp index db06724a..052e4419 100644 --- a/src/kprofile.cpp +++ b/src/kprofile.cpp @@ -13,7 +13,11 @@ KProfile::KProfile(QObject *parent) : settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void KProfile::startDownload(QWebEngineDownloadItem* download) +#else +void KProfile::startDownload(QWebEngineDownloadRequest* download) +#endif { QString defaultFileName = download->url().fileName(); QString fileName = QFileDialog::getSaveFileName(KiwixApp::instance()->getMainWindow(), @@ -30,7 +34,11 @@ void KProfile::startDownload(QWebEngineDownloadItem* download) #else download->setDownloadFileName(fileName); #endif +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) connect(download, &QWebEngineDownloadItem::finished, this, &KProfile::downloadFinished); +#else + connect(download, &QWebEngineDownloadRequest::isFinished, this, &KProfile::downloadFinished); +#endif download->accept(); } diff --git a/src/kprofile.h b/src/kprofile.h index 3f5e3c4b..59c793f7 100644 --- a/src/kprofile.h +++ b/src/kprofile.h @@ -2,6 +2,11 @@ #define KPROFILE_H #include +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#include +#else +#include +#endif #include "urlschemehandler.h" @@ -16,7 +21,12 @@ class KProfile : public QWebEngineProfile signals: public slots: + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) void startDownload(QWebEngineDownloadItem*); +#else + void startDownload(QWebEngineDownloadRequest*); +#endif void downloadFinished(); }; diff --git a/src/main.cpp b/src/main.cpp index b98c54d8..5b85fff5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,8 +18,10 @@ int main(int argc, char *argv[]) } // End of hack ^^^ - +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + // High DPI Scaling is enabled by default in Qt6. This attribute no longer exists in 6.0 and later QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) QWebEngineUrlScheme scheme("zim"); QWebEngineUrlScheme::registerScheme(scheme); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 23d3b764..615288bc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,5 +1,6 @@ #include "mainwindow.h" +#include "portutils.h" #include "ui_mainwindow.h" #include "ui_about.h" @@ -108,10 +109,12 @@ bool MainWindow::eventFilter(QObject* /*object*/, QEvent* event) { const auto mouseEvent = static_cast(event); const int tabRegion = getTabBar()->height() + getTopWidget()->height() + 30; + int clickY = portutils::getY(*mouseEvent); + // We don't have to check for visibilty as calling hide() on a hidden widget, or show() on a non-hidden widget is a no-op - if (mouseEvent->y() == 0) { + if (clickY == 0) { showTabAndTop(); - } else if(mouseEvent->y() >= tabRegion) { + } else if(clickY >= tabRegion) { hideTabAndTop(); } return true; diff --git a/src/mainwindow.h b/src/mainwindow.h index 5c347056..701f4255 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -27,7 +27,7 @@ class MainWindow : public QMainWindow QWidget getMainView(); protected: - void keyPressEvent(QKeyEvent *event); + void keyPressEvent(QKeyEvent *event) override; bool eventFilter(QObject* object, QEvent* event) override; private slots: diff --git a/src/portutils.h b/src/portutils.h new file mode 100644 index 00000000..a54ec8f4 --- /dev/null +++ b/src/portutils.h @@ -0,0 +1,39 @@ +#ifndef PORTUTILS_H +#define PORTUTILS_H + +#include + +namespace portutils { + + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // Earlier than Qt6 + inline int getX(const QMouseEvent& e) { + return e.x(); + } + + inline int getY(const QMouseEvent& e) { + return e.y(); + } + + inline QPoint getGlobalPos(const QMouseEvent& e) { + return e.globalPos(); + } + +#else // Qt6 and later + inline int getX(const QMouseEvent& e) { + return e.position().x(); + } + + inline int getY(const QMouseEvent& e) { + return e.position().y(); + } + + inline QPoint getGlobalPos(const QMouseEvent& e) { + return e.globalPosition().toPoint(); + } + +#endif + +} + +#endif // PORTUTILS_H diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index b77657e6..5681d2a6 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include SettingsManager::SettingsManager(QObject *parent) : QObject(parent), @@ -147,8 +148,18 @@ void SettingsManager::initSettings() m_kiwixServerIpAddress = m_settings.value("localKiwixServer/ipAddress", QString("0.0.0.0")).toString(); m_monitorDir = m_settings.value("monitor/dir", QString("")).toString(); m_moveToTrash = m_settings.value("moveToTrash", true).toBool(); - QVariant defaultLang = QVariant::fromValue(QLocale::languageToString(QLocale().language()) + '|' + QLocale().name().split("_").at(0)); - m_langList = m_settings.value("language", {defaultLang}).toList(); + QString defaultLang = QLocale::languageToString(QLocale().language()) + '|' + QLocale().name().split("_").at(0); + + QList defaultLangList; // Qt5 QList doesn't support supplying a constructor list, so use append() for Qt5+Qt6 compat + defaultLangList.append(defaultLang); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QVariant defaultLangVariant(defaultLangList); // Qt5 requires explicit conversion from QList to QVariant + m_langList = m_settings.value("language", defaultLangVariant).toList(); +#else + m_langList = m_settings.value("language", defaultLangList).toList(); +#endif + m_categoryList = m_settings.value("category", {}).toList(); m_contentTypeList = m_settings.value("contentType", {}).toList(); } diff --git a/src/tabbar.cpp b/src/tabbar.cpp index 7027abde..6ea18e2f 100644 --- a/src/tabbar.cpp +++ b/src/tabbar.cpp @@ -1,3 +1,5 @@ +class QMenu; + #include "tabbar.h" #include "kiwixapp.h" @@ -76,7 +78,7 @@ TabBar::TabBar(QWidget *parent) : for (int i = 0 ; i <= 9 ; i++) { QAction *a = new QAction(this); a->setData(QVariant::fromValue(i)); - QKeySequence ks(Qt::ALT + (Qt::Key_0 + i)); + QKeySequence ks(Qt::ALT | (Qt::Key_0 + i)); a->setShortcut(ks); addAction(a); connect(a, &QAction::triggered, this, [=](){ diff --git a/src/topwidget.cpp b/src/topwidget.cpp index 29a448fd..f8d591fb 100644 --- a/src/topwidget.cpp +++ b/src/topwidget.cpp @@ -4,6 +4,7 @@ #include "kiwixapp.h" #include "mainmenu.h" #include "tabbar.h" +#include "portutils.h" #include #include @@ -48,12 +49,13 @@ TopWidget::TopWidget(QWidget *parent) : addAction(KiwixApp::instance()->getAction(KiwixApp::OpenFileAction)); QMenu* menu = new MainMenu(); - QAction* menuAction = new QAction(this); - menuAction->setIcon(QIcon(":/icons/more.svg")); - menuAction->setMenu(menu); - menuAction->setToolTip(gt("main-menu")); + QToolButton *toolButton = new QToolButton(menu); + toolButton->setIcon(QIcon(":/icons/more.svg")); + toolButton->setPopupMode(QToolButton::InstantPopup); + toolButton->setToolTip(gt("main-menu")); + toolButton->setMenu(menu); + addWidget(toolButton); - addAction(menuAction); setContextMenuPolicy( Qt::PreventContextMenu ); #if !SYSTEMTITLEBAR @@ -92,7 +94,8 @@ void TopWidget::mousePressEvent(QMouseEvent *event) { if (event->button() != Qt::LeftButton) return; - m_cursorPos = event->globalPos() + frameGeometry().topLeft() - parentWidget()->frameGeometry().topLeft(); + QPoint globalPos = portutils::getGlobalPos(*event); + m_cursorPos = globalPos + frameGeometry().topLeft() - parentWidget()->frameGeometry().topLeft(); m_timestamp = event->timestamp(); event->accept(); } @@ -101,8 +104,9 @@ void TopWidget::mouseMoveEvent(QMouseEvent *event) { if (event->timestamp() <= m_timestamp) return; + QPoint globalPos = portutils::getGlobalPos(*event); m_timestamp = event->timestamp(); - auto delta = event->globalPos() - m_cursorPos; + auto delta = globalPos - m_cursorPos; parentWidget()->move(delta); event->accept(); } diff --git a/src/urlschemehandler.h b/src/urlschemehandler.h index f4f3a117..e7e227ac 100644 --- a/src/urlschemehandler.h +++ b/src/urlschemehandler.h @@ -5,6 +5,7 @@ class UrlSchemeHandler : public QWebEngineUrlSchemeHandler { + Q_OBJECT public: UrlSchemeHandler(); void requestStarted(QWebEngineUrlRequestJob *request); diff --git a/src/webpage.h b/src/webpage.h index c8e64a3f..d594b0f2 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -5,6 +5,7 @@ class WebPage : public QWebEnginePage { + Q_OBJECT public: explicit WebPage(QObject *parent = nullptr); diff --git a/src/webview.cpp b/src/webview.cpp index 4104961e..9446a07b 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -1,3 +1,5 @@ +class QMenu; + #include "webview.h" #include @@ -80,11 +82,13 @@ WebView::WebView(QWidget *parent) * If the page is search results, we put the default zoom factor * If in Qt 6.x, the bug is fixed this code can be removed. */ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) connect(this, &QWebEngineView::loadFinished, this, [=] (bool ok) { if (ok) { applyCorrectZoomFactor(); } }); +#endif } WebView::~WebView() @@ -202,26 +206,70 @@ void WebView::wheelEvent(QWheelEvent *event) { void WebView::contextMenuEvent(QContextMenuEvent *event) { - auto menu = this->page()->createStandardContextMenu(); - pageAction(QWebEnginePage::OpenLinkInNewWindow)->setVisible(false); - if (!m_linkHovered.isEmpty()) { - if (!m_linkHovered.startsWith("zim://")) { - pageAction(QWebEnginePage::OpenLinkInNewTab)->setVisible(false); - auto openLinkInWebBrowserAction = new QAction(gt("open-link-in-web-browser")); - menu->insertAction(pageAction(QWebEnginePage::DownloadLinkToDisk) , openLinkInWebBrowserAction); - connect(menu, &QObject::destroyed, openLinkInWebBrowserAction, &QObject::deleteLater); - connect(openLinkInWebBrowserAction, &QAction::triggered, this, [=](bool checked) { - Q_UNUSED(checked); - QDesktopServices::openUrl(m_linkHovered); - }); - } else { - pageAction(QWebEnginePage::OpenLinkInNewTab)->setVisible(true); - } + QMenu* menu; + if (m_linkHovered.isEmpty()) { + menu = createStandardContextMenu(); + } else { + menu = createLinkContextMenu(); } menu->exec(event->globalPos()); } +QMenu* WebView::createStandardContextMenu() { + auto app = KiwixApp::instance(); + + QMenu* menu = new QMenu(this); + auto backAction = new QAction(gt("back")); + backAction->setEnabled(app->getAction(KiwixApp::HistoryBackAction)->isEnabled()); + backAction->setIcon(app->getAction(KiwixApp::HistoryBackAction)->icon()); + menu->addAction(backAction); + connect(menu, &QObject::destroyed, backAction, &QObject::deleteLater); + connect(backAction, &QAction::triggered, this, [=](bool checked) { + Q_UNUSED(checked); + KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Back); + }); + + auto forwardAction = new QAction(gt("forward")); + forwardAction->setEnabled(app->getAction(KiwixApp::HistoryForwardAction)->isEnabled()); + forwardAction->setIcon(app->getAction(KiwixApp::HistoryForwardAction)->icon()); + menu->addAction(forwardAction); + connect(menu, &QObject::destroyed, forwardAction, &QObject::deleteLater); + connect(forwardAction, &QAction::triggered, this, [=](bool checked) { + Q_UNUSED(checked); + KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Forward); + }); + + return menu; +} + + +QMenu* WebView::createLinkContextMenu() { + QMenu* menu = new QMenu(this); + + if (!m_linkHovered.startsWith("zim://")) { + auto openLinkInWebBrowserAction = new QAction(gt("open-link-in-web-browser")); + menu->addAction(openLinkInWebBrowserAction); + connect(menu, &QObject::destroyed, openLinkInWebBrowserAction, &QObject::deleteLater); + connect(openLinkInWebBrowserAction, &QAction::triggered, this, [=](bool checked) { + Q_UNUSED(checked); + QDesktopServices::openUrl(m_linkHovered); + }); + } else { + auto openLinkNewTab = new QAction(gt("open-link-new-tab")); + openLinkNewTab->setIcon(QIcon(":/icons/new-tab-icon.svg")); + menu->addAction(openLinkNewTab); + connect(menu, &QObject::destroyed, openLinkNewTab, &QObject::deleteLater); + connect(openLinkNewTab, &QAction::triggered, this, [=](bool checked) { + Q_UNUSED(checked); + KiwixApp::instance()->openUrl(m_linkHovered, true); + }); + } + + return menu; +} + + bool WebView::eventFilter(QObject *src, QEvent *e) { Q_UNUSED(src) diff --git a/src/webview.h b/src/webview.h index eaa5191e..ca1f560c 100644 --- a/src/webview.h +++ b/src/webview.h @@ -1,10 +1,10 @@ #ifndef WEBVIEW_H #define WEBVIEW_H +#include #include #include #include -#include #include "findinpagebar.h" @@ -69,6 +69,8 @@ private slots: private: void addHistoryItemAction(QMenu *menu, const QWebEngineHistoryItem &item, int n) const; void applyCorrectZoomFactor(); + QMenu* createStandardContextMenu(); + QMenu* createLinkContextMenu(); }; #endif // WEBVIEW_H diff --git a/subprojects/QtSingleApplication/src/qtlocalpeer.cpp b/subprojects/QtSingleApplication/src/qtlocalpeer.cpp index f3c4546b..25466855 100644 --- a/subprojects/QtSingleApplication/src/qtlocalpeer.cpp +++ b/subprojects/QtSingleApplication/src/qtlocalpeer.cpp @@ -38,11 +38,11 @@ ** ****************************************************************************/ - #include "qtlocalpeer.h" #include #include #include +#include #if defined(Q_OS_WIN) #include @@ -76,15 +76,25 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) #if defined(Q_OS_WIN) id = id.toLower(); #endif - prefix = id.section(QLatin1Char('/'), -1); + prefix = id.section(u'/', -1); } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) prefix.remove(QRegExp("[^a-zA-Z]")); +#else + prefix.remove(QRegularExpression("[^a-zA-Z]")); +#endif prefix.truncate(6); QByteArray idc = id.toUtf8(); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) quint16 idNum = qChecksum(idc.constData(), idc.size()); +#else + QByteArrayView v = QByteArrayView(idc); + quint16 idNum = qChecksum(v); +#endif + socketName = QLatin1String("qtsingleapp-") + prefix - + QLatin1Char('-') + QString::number(idNum, 16); + + u'-' + QString::number(idNum, 16); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { @@ -97,12 +107,12 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) socketName += QLatin1Char('-') + QString::number(sessionId, 16); } #else - socketName += QLatin1Char('-') + QString::number(::getuid(), 16); + socketName += u'-' + QString::number(::getuid(), 16); #endif server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() - + QLatin1Char('/') + socketName + + u'/' + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); @@ -122,7 +132,7 @@ bool QtLocalPeer::isClient() #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) // ### Workaround if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { - QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName); + QFile::remove(QDir::cleanPath(QDir::tempPath())+u'/'+socketName); res = server->listen(socketName); } #endif diff --git a/subprojects/QtSingleApplication/src/qtlockedfile.h b/subprojects/QtSingleApplication/src/qtlockedfile.h index 84c18e5c..0f6b2bda 100644 --- a/subprojects/QtSingleApplication/src/qtlockedfile.h +++ b/subprojects/QtSingleApplication/src/qtlockedfile.h @@ -66,6 +66,9 @@ namespace QtLP_Private { class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { + //Q_OBJECT + // TODO: Uncomment Q_OBJECT. Setting Q_OBJECT here causes this error: + // undefined reference to `vtable for QtLP_Private::QtLockedFile' public: enum LockMode { NoLock = 0, ReadLock, WriteLock };