From 635a7d77ddc94c63d52494dc4d68a930faccf45f Mon Sep 17 00:00:00 2001 From: Enrico Forestieri Date: Mon, 15 Mar 2021 17:09:09 +0100 Subject: [PATCH] Allow compiling with Qt6 This commit allows compiling LyX with Qt6 when using autotools. For a successful compilation the following 2 conditions must be met. 1) The Qt6 qmake has to come first in PATH, so that the command "qmake -v | grep -o 'Qt version .'" returns "Qt version 6". 2) The --enable-qt6 switch has to be passed to the configure command. If --enable-qt6 is used but Qt6 is not found, Qt5 is tried as a fallback. If also Qt5 is not found, configuring for Qt4 is attempted. If --enable-qt6 is not used, then things go as usual. This means that Qt5 is tried first and then Qt4, unless --disable-qt5 is used, in which case Qt4 is directly attempted. This means that existing scripts should continue working unmodified. LyX should compile with Qt6 on windows and linux, and possibly also on mac, but I could not test that. However, it is not guaranteed that it works as it should. In particular I am not sure that I got right the conversion from QRegExp to QRegularExpression. For sure, the syntax highlighting seems to not work right. Someone in the know should take a look at that. I am able to load documents and compile them but some thourough testing is needed. However, when compiling for Qt5 or Qt4, I tried to make sure that the functionality is preserved. --- config/lyxinclude.m4 | 13 ++- config/qt.m4 | 138 ++++++++++++++++++++++++-- configure.ac | 3 + src/frontends/qt/CategorizedCombo.cpp | 11 ++ src/frontends/qt/GuiAbout.cpp | 9 ++ src/frontends/qt/GuiApplication.cpp | 27 ++++- src/frontends/qt/GuiClipboard.cpp | 4 + src/frontends/qt/GuiCommandBuffer.cpp | 8 ++ src/frontends/qt/GuiFontLoader.cpp | 20 ++-- src/frontends/qt/GuiListings.cpp | 8 ++ src/frontends/qt/GuiLog.cpp | 47 +++++++++ src/frontends/qt/GuiLog.h | 7 ++ src/frontends/qt/GuiPrefs.cpp | 15 ++- src/frontends/qt/GuiTabular.cpp | 4 + src/frontends/qt/GuiThesaurus.cpp | 28 ++++++ src/frontends/qt/GuiView.cpp | 2 +- src/frontends/qt/IconPalette.cpp | 16 +++ src/frontends/qt/IconPalette.h | 4 + src/frontends/qt/LaTeXHighlighter.cpp | 97 ++++++++++++++++++ src/frontends/qt/LayoutBox.cpp | 8 ++ src/frontends/qt/Validator.cpp | 4 + src/support/mutex.cpp | 8 ++ 22 files changed, 453 insertions(+), 28 deletions(-) diff --git a/config/lyxinclude.m4 b/config/lyxinclude.m4 index 4fb2a8d44e..5d6bb1da86 100644 --- a/config/lyxinclude.m4 +++ b/config/lyxinclude.m4 @@ -63,7 +63,16 @@ AC_MSG_RESULT([$withval]) ]) -dnl Check whether to configure for Qt4 or Qt5. Default is Qt5. +dnl Check whether to configure for Qt4, Qt5, or Qt6. Default is Qt5. +dnl +AC_DEFUN([LYX_CHECK_QT6],[ +AC_MSG_CHECKING([whether Qt6 is requested]) +AC_ARG_ENABLE([qt6], + [AS_HELP_STRING([--enable-qt6],[use Qt6 for building])], + USE_QT6=$enableval, USE_QT6=no) +AC_MSG_RESULT([$USE_QT6]) +AC_SUBST([USE_QT6]) +]) dnl AC_DEFUN([LYX_CHECK_QT5],[ AC_MSG_CHECKING([whether Qt5 is disabled]) @@ -372,7 +381,7 @@ if test x$GXX = xyes; then AM_CXXFLAGS="$AM_CXXFLAGS -fno-omit-frame-pointer" fi - if test x$USE_QT5 = xyes ; then + if test x$USE_QT5 = xyes -o x$USE_QT6 = xyes; then AS_CASE([$host], [*mingw*|*cygwin*], [], [AM_CXXFLAGS="-fPIC $AM_CXXFLAGS"]) fi dnl Warnings are for preprocessor too diff --git a/config/qt.m4 b/config/qt.m4 index 6e2d6bcd3f..4b1bfc4068 100644 --- a/config/qt.m4 +++ b/config/qt.m4 @@ -26,7 +26,10 @@ AC_DEFUN([QT_CHECK_COMPILE], CXXFLAGS="$CXXFLAGS $QT_INCLUDES $QT_LDFLAGS" qt_corelibs="-lQtCore -lQtCore4" qt_guilibs="'-lQtCore -lQtGui' '-lQtCore4 -lQtGui4'" - if test $USE_QT5 = "yes" ; then + if test $USE_QT6 = "yes" ; then + qt_corelibs="-lQt6Core -lQt6Core5Compat" + qt_guilibs="-lQt6Core -lQt6Core5Compat -lQt6Concurrent -lQt6Gui -lQt6Svg -lQt6Widgets" + elif test $USE_QT5 = "yes" ; then qt_corelibs="-lQt5Core" qt_guilibs="-lQt5Core -lQt5Concurrent -lQt5Gui -lQt5Svg -lQt5Widgets" fi @@ -52,7 +55,9 @@ AC_DEFUN([QT_CHECK_COMPILE], ]) if test -z "$qt_cv_libname"; then - if test x$USE_QT5 = xyes ; then + if test x$USE_QT6 = xyes ; then + AC_MSG_RESULT([failed, retrying with Qt5]) + elif test x$USE_QT5 = xyes ; then AC_MSG_RESULT([failed, retrying with Qt4]) else AC_MSG_RESULT([failed]) @@ -68,7 +73,9 @@ AC_DEFUN([QT_FIND_TOOL], [ $1= qt_ext=qt4 - if test "x$USE_QT5" != "xno" ; then + if test "x$USE_QT6" != "xno" ; then + qt_ext=qt6 + elif test "x$USE_QT5" != "xno" ; then qt_ext=qt5 fi @@ -161,17 +168,41 @@ AC_DEFUN([QT_DO_IT_ALL], dnl Check if it possible to do a pkg-config PKG_PROG_PKG_CONFIG - if test -n "$PKG_CONFIG" ; then - QT_DO_PKG_CONFIG - fi - if test "$pkg_failed" != "no" ; then - QT_DO_MANUAL_CONFIG + dnl Not possible with Qt6 (QTBUG-86080) + if test x$USE_QT6 = xno ; then + if test -n "$PKG_CONFIG" ; then + QT_DO_PKG_CONFIG + fi + if test "$pkg_failed" != "no" ; then + QT_DO_MANUAL_CONFIG + fi + else + QT6_QMAKE_CONFIG + if test -z "$QT_LIB"; then + QT_DO_MANUAL_CONFIG + fi fi if test -z "$QT_LIB"; then - dnl Try again with Qt4 if configuring for Qt5 fails - if test x$USE_QT5 = xyes ; then + dnl Try again with Qt5 and then Qt4 if configuring for Qt6/5 fails + if test x$USE_QT6 = xyes ; then + USE_QT6=no + USE_QT5=yes + AC_SUBST([USE_QT6]) + AC_SUBST([USE_QT5]) + if test -n "$PKG_CONFIG" ; then + QT_DO_PKG_CONFIG + fi + if test "$pkg_failed" != "no" ; then + QT_DO_MANUAL_CONFIG + fi + if test -z "$QT_LIB"; then + AC_MSG_ERROR([cannot find qt libraries.]) + fi + elif test x$USE_QT5 = xyes ; then + USE_QT6=no USE_QT5=no + AC_SUBST([USE_QT6]) AC_SUBST([USE_QT5]) if test -n "$PKG_CONFIG" ; then QT_DO_PKG_CONFIG @@ -197,8 +228,21 @@ AC_DEFUN([QT_DO_IT_ALL], AC_CHECK_HEADER(QtGui/qtgui-config.h, [lyx_qt5_config=QtGui/qtgui-config.h], [lyx_qt5_config=qconfig.h],[-]) + AC_CHECK_HEADER(QtGui/private/qtgui-config_p.h, + [lyx_qt6_config=QtGui/private/qtgui-config_p.h], + [lyx_qt6_config=qconfig.h],[-]) AC_MSG_CHECKING([whether Qt uses the X Window system]) - if test x$USE_QT5 = xyes ; then + if test x$USE_QT6 = xyes ; then + dnl FIXME: Check whether defining QPA_XCB makes sense with Qt6 + AC_PREPROC_IFELSE([AC_LANG_SOURCE([ + [#include <$lyx_qt6_config>] + [#if !defined(QT_FEATURE_xcb) || QT_FEATURE_xcb < 0] + [#error Fail] + [#endif]])], + [AC_MSG_RESULT(yes) + AC_DEFINE(QPA_XCB, 1, [Define if Qt uses the X Window System])], + [AC_MSG_RESULT(no)]) + elif test x$USE_QT5 = xyes ; then AC_EGREP_CPP(xcb, [#include <$lyx_qt5_config> QT_QPA_DEFAULT_PLATFORM_NAME], @@ -351,3 +395,75 @@ AC_DEFUN([QT_DO_MANUAL_CONFIG], QT_GET_VERSION fi ]) + +AC_DEFUN([QT6_QMAKE_CONFIG], +[ + AC_MSG_CHECKING([for Qt6]) + dnl Use first qmake in PATH + ver=`qmake -v | grep -o "Qt version ."` + if test "$ver" = "Qt version 6"; then + dnl Use a .pro file for getting qmake's variables + lyx_test_qt_dir=`mktemp -d` + lyx_test_qt_pro="$lyx_test_qt_dir/test.pro" + lyx_test_qt_mak="$lyx_test_qt_dir/Makefile" + cat > $lyx_test_qt_pro << EOF1 +qtHaveModule(core): QT += core +qtHaveModule(core5compat): QT += core5compat +percent.target = % +percent.commands = @echo -n "\$(\$(@))\ " +QMAKE_EXTRA_TARGETS += percent +EOF1 + qmake $lyx_test_qt_pro -o $lyx_test_qt_mak 1>/dev/null 2>&1 + QT_CORE_INCLUDES=`cd $lyx_test_qt_dir; make -s -f $lyx_test_qt_mak INCPATH | sed 's/-I\. //g'` + qt_corelibs=`cd $lyx_test_qt_dir; make -s -f $lyx_test_qt_mak LIBS` + QT_CORE_LDFLAGS=`echo $qt_corelibs | tr ' ' '\n' | grep -e "^-L" | tr '\n' ' '` + if test -z "$QT_CORE_LDFLAGS"; then + QT_CORE_LDFLAGS="-L`qmake -query QT_INSTALL_LIBS`" + QT_CORE_LIB="$qt_corelibs" + else + QT_CORE_LIB=`echo $qt_corelibs | tr ' ' '\n' | grep -e "^-l" | tr '\n' ' '` + fi + if test -z "$QT_CORE_LIB"; then + AC_MSG_RESULT(no) + else + AC_SUBST(QT_CORE_INCLUDES) + AC_SUBST(QT_CORE_LDFLAGS) + AC_SUBST(QT_CORE_LIB) + cat > $lyx_test_qt_pro << EOF2 +qtHaveModule(core): QT += core +qtHaveModule(core5compat): QT += core5compat +qtHaveModule(concurrent): QT += concurrent +qtHaveModule(gui): QT += gui +qtHaveModule(svg): QT += svg +qtHaveModule(widgets): QT += widgets +percent.target = % +percent.commands = @echo -n "\$(\$(@))\ " +QMAKE_EXTRA_TARGETS += percent +EOF2 + qmake $lyx_test_qt_pro -o $lyx_test_qt_mak 1>/dev/null 2>&1 + QT_INCLUDES=`cd $lyx_test_qt_dir; make -s -f $lyx_test_qt_mak INCPATH | sed 's/-I\. //g'` + qt_guilibs=`cd $lyx_test_qt_dir; make -s -f $lyx_test_qt_mak LIBS` + QT_LDFLAGS=`echo $qt_guilibs | tr ' ' '\n' | grep -e "^-L" | tr '\n' ' '` + if test -z "$QT_LDFLAGS"; then + QT_LDFLAGS="-L`qmake -query QT_INSTALL_LIBS`" + QT_LIB="$qt_guilibs" + else + QT_LIB=`echo $qt_guilibs | tr ' ' '\n' | grep -e "^-l" | tr '\n' ' '` + fi + QTLIB_VERSION=`qmake -v | grep "Qt version" | sed -e 's/.*\([[0-9]]\.[[0-9]]*\.[[0-9]]\).*/\1/'` + if test -z "$QT_LIB"; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + AC_SUBST(QT_INCLUDES) + AC_SUBST(QT_LDFLAGS) + AC_SUBST(QT_LIB) + AC_SUBST(QTLIB_VERSION) + fi + fi + rm $lyx_test_qt_pro $lyx_test_qt_mak $lyx_test_qt_dir/.qmake.stash + rmdir $lyx_test_qt_dir + else + AC_MSG_RESULT(no) + fi +]) diff --git a/configure.ac b/configure.ac index f7d52fa669..f258db9adf 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,10 @@ AC_CONFIG_AUX_DIR(config) # First check the version LYX_CHECK_VERSION LYX_VERSION_SUFFIX +LYX_CHECK_QT6 +if test x$USE_QT6 = xno ; then LYX_CHECK_QT5 +fi # Check how the files should be packaged AC_CANONICAL_TARGET LYX_USE_PACKAGING diff --git a/src/frontends/qt/CategorizedCombo.cpp b/src/frontends/qt/CategorizedCombo.cpp index 4aebcf6a91..1548ecf7e8 100644 --- a/src/frontends/qt/CategorizedCombo.cpp +++ b/src/frontends/qt/CategorizedCombo.cpp @@ -34,6 +34,9 @@ #include #include #include +#if QT_VERSION >= 0x060000 +#include +#endif using namespace lyx::support; @@ -270,7 +273,11 @@ QString CCItemDelegate::underlineFilter(QString const & s) const if (f.isEmpty()) return s; QString r(s); +#if QT_VERSION < 0x060000 QRegExp pattern(charFilterRegExpC(f)); +#else + QRegularExpression pattern(charFilterRegExpC(f)); +#endif r.replace(pattern, "\\1"); return r; } @@ -287,7 +294,11 @@ void CategorizedCombo::Private::setFilter(QString const & s) lastSel_ = filterModel_->mapToSource(filterModel_->index(sel, 0)).row(); filter_ = s; +#if QT_VERSION < 0x060000 filterModel_->setFilterRegExp(charFilterRegExp(filter_)); +#else + filterModel_->setFilterRegularExpression(charFilterRegExp(filter_)); +#endif countCategories(); // restore old selection diff --git a/src/frontends/qt/GuiAbout.cpp b/src/frontends/qt/GuiAbout.cpp index b066106ad8..d4173fae8b 100644 --- a/src/frontends/qt/GuiAbout.cpp +++ b/src/frontends/qt/GuiAbout.cpp @@ -59,7 +59,9 @@ static QString credits() out << qt_("Please install correctly to estimate the great\namount of work other people have done for the LyX project."); } else { QTextStream ts(&file); +#if QT_VERSION < 0x060000 ts.setCodec("UTF-8"); +#endif QString line; do { line = ts.readLine(); @@ -101,7 +103,9 @@ static QString release_notes() out << qt_("Please install correctly to see what has changed\nfor this version of LyX."); } else { QTextStream ts(&file); +#if QT_VERSION < 0x060000 ts.setCodec("UTF-8"); +#endif QString line; bool incomment = false; bool inlist = false; @@ -123,8 +127,13 @@ static QString release_notes() continue; // detect links to the tracker +#if QT_VERSION < 0x060000 line.replace(QRegExp("(bug )(\\#)(\\d+)*"), "\\1\\3"); +#else + line.replace(QRegularExpression("(bug )(\\#)(\\d+)*"), + "\\1\\3"); +#endif // headings if (line.startsWith("!!!")) { diff --git a/src/frontends/qt/GuiApplication.cpp b/src/frontends/qt/GuiApplication.cpp index e500fa003c..a5cb3c8db8 100644 --- a/src/frontends/qt/GuiApplication.cpp +++ b/src/frontends/qt/GuiApplication.cpp @@ -89,7 +89,9 @@ #include #include #include +#if QT_VERSION < 0x060000 #include +#endif #include #include #include @@ -135,6 +137,7 @@ #if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400) #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) +#if (QT_VERSION < 0x060000) #if (QT_VERSION < 0x050000) #include #define QWINDOWSMIME QWindowsMime @@ -142,6 +145,7 @@ #include #define QWINDOWSMIME QWinMime #endif +#endif #ifdef Q_CC_GNU #include #endif @@ -808,7 +812,7 @@ public: //////////////////////////////////////////////////////////////////////// // Windows specific stuff goes here... -#if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400) +#if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400 && QT_VERSION < 0x060000) #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) // QWindowsMimeMetafile can only be compiled on Windows. @@ -974,7 +978,7 @@ struct GuiApplication::Private , last_state_(Qt::ApplicationInactive) #endif { - #if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400) + #if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400 && QT_VERSION < 0x060000) #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) /// WMF Mime handler for Windows clipboard. wmf_mime_ = new QWindowsMimeMetafile; @@ -1049,7 +1053,7 @@ struct GuiApplication::Private QMacPasteboardMimeGraphics mac_pasteboard_mime_; #endif -#if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400) +#if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400 && QT_VERSION < 0x060000) #if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN) /// WMF Mime handler for Windows clipboard. QWindowsMimeMetafile * wmf_mime_; @@ -1080,7 +1084,7 @@ GuiApplication::GuiApplication(int & argc, char ** argv) QCoreApplication::setOrganizationName(app_name); QCoreApplication::setOrganizationDomain("lyx.org"); QCoreApplication::setApplicationName(lyx_package); -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= 0x050000 && QT_VERSION < 0x060000 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif @@ -2567,6 +2571,7 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow, int x, y; int w, h; QChar sx, sy; +#if QT_VERSION < 0x060000 QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)){0,1}(?:([+-][0-9]*)){0,1}" ); re.indexIn(geometry_arg); w = re.cap(1).toInt(); @@ -2575,6 +2580,16 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow, y = re.cap(4).toInt(); sx = re.cap(3).isEmpty() ? '+' : re.cap(3).at(0); sy = re.cap(4).isEmpty() ? '+' : re.cap(4).at(0); +#else + QRegularExpression re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)){0,1}(?:([+-][0-9]*)){0,1}" ); + QRegularExpressionMatch match = re.match(geometry_arg); + w = match.captured(1).toInt(); + h = match.captured(2).toInt(); + x = match.captured(3).toInt(); + y = match.captured(4).toInt(); + sx = match.captured(3).isEmpty() ? '+' : match.captured(3).at(0); + sy = match.captured(4).isEmpty() ? '+' : match.captured(4).at(0); +#endif // Set initial geometry such that we can get the frame size. view->setGeometry(x, y, w, h); int framewidth = view->geometry().x() - view->x(); @@ -2582,7 +2597,11 @@ void GuiApplication::createView(QString const & geometry_arg, bool autoShow, // Negative displacements must be interpreted as distances // from the right or bottom screen borders. if (sx == '-' || sy == '-') { +#if QT_VERSION < 0x060000 QRect rec = QApplication::desktop()->screenGeometry(); +#else + QRect rec = QGuiApplication::primaryScreen()->geometry(); +#endif if (sx == '-') x += rec.width() - w - framewidth; if (sy == '-') diff --git a/src/frontends/qt/GuiClipboard.cpp b/src/frontends/qt/GuiClipboard.cpp index 6c1d9816c4..37cda23a15 100644 --- a/src/frontends/qt/GuiClipboard.cpp +++ b/src/frontends/qt/GuiClipboard.cpp @@ -361,7 +361,11 @@ QString tidyHtml(QString const & input) // clutter. QTextDocument converter; converter.setHtml(input); +#if QT_VERSION < 0x060000 return converter.toHtml("utf-8"); +#else + return converter.toHtml(); +#endif } } // namespace diff --git a/src/frontends/qt/GuiCommandBuffer.cpp b/src/frontends/qt/GuiCommandBuffer.cpp index d6334280ff..80e57c048c 100644 --- a/src/frontends/qt/GuiCommandBuffer.cpp +++ b/src/frontends/qt/GuiCommandBuffer.cpp @@ -123,9 +123,17 @@ GuiCommandBuffer::GuiCommandBuffer(GuiView * view) layout->addWidget(upPB, 0); layout->addWidget(downPB, 0); layout->addWidget(edit_, 10); +#if QT_VERSION < 0x060000 layout->setMargin(0); +#else + layout->setContentsMargins(0, 0, 0, 0); +#endif top->addLayout(layout); +#if QT_VERSION < 0x060000 top->setMargin(0); +#else + top->setContentsMargins(0, 0, 0, 0); +#endif setFocusProxy(edit_); LastCommandsSection::LastCommands last_commands diff --git a/src/frontends/qt/GuiFontLoader.cpp b/src/frontends/qt/GuiFontLoader.cpp index a2d6d989aa..a47e555092 100644 --- a/src/frontends/qt/GuiFontLoader.cpp +++ b/src/frontends/qt/GuiFontLoader.cpp @@ -29,6 +29,8 @@ #include "support/Package.h" #include "support/os.h" +#include "GuiApplication.h" + #include #include @@ -207,14 +209,16 @@ QFont symbolFont(QString const & family, bool * ok) upper[0] = family[0].toUpper(); QFont font; -#if defined Q_WS_X11 || defined(QPA_XCB) - // On *nix we have to also specify the foundry to be able to - // discriminate our fonts when the texlive fonts are managed by - // fontconfig. Unfortunately, doing the same on Windows breaks things. - font.setFamily(family + QLatin1String(" [LyEd]")); -#else - font.setFamily(family); -#endif + if (guiApp->platformName() == "qt4x11" + || guiApp->platformName() == "xcb" + || guiApp->platformName().contains("wayland")) { + // On *nix we have to also specify the foundry to be able to + // discriminate our fonts when the texlive fonts are managed by + // fontconfig. Unfortunately, doing the same on Windows breaks things. + font.setFamily(family + QLatin1String(" [LyEd]")); + } else { + font.setFamily(family); + } font.setStyleStrategy(QFont::NoFontMerging); #if QT_VERSION >= 0x040800 font.setStyleName("LyX"); diff --git a/src/frontends/qt/GuiListings.cpp b/src/frontends/qt/GuiListings.cpp index 0b3cb24b3b..b1a1e8cac2 100644 --- a/src/frontends/qt/GuiListings.cpp +++ b/src/frontends/qt/GuiListings.cpp @@ -30,7 +30,11 @@ #include #include #include +#if QT_VERSION < 0x060000 #include +#else +#include +#endif using namespace std; using namespace lyx::support; @@ -232,7 +236,11 @@ GuiListings::GuiListings(GuiView & lv) numberStepLE->setValidator(new QIntValidator(0, 1000000, this)); firstlineLE->setValidator(new QIntValidator(0, 1000000, this)); lastlineLE->setValidator(new QIntValidator(0, 1000000, this)); +#if QT_VERSION < 0x060000 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this)); +#else + placementLE->setValidator(new QRegularExpressionValidator(QRegularExpression("[\\*tbph]*"), this)); +#endif bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy); bc().setOK(buttonBox->button(QDialogButtonBox::Ok)); diff --git a/src/frontends/qt/GuiLog.cpp b/src/frontends/qt/GuiLog.cpp index aab671a91e..6fac3603e7 100644 --- a/src/frontends/qt/GuiLog.cpp +++ b/src/frontends/qt/GuiLog.cpp @@ -41,12 +41,21 @@ namespace frontend { // Regular expressions needed at several places // FIXME: These regexes are incomplete. It would be good if we could collect those used in LaTeX::scanLogFile // and LaTeX::scanBlgFile and re-use them here!(spitz, 2013-05-27) +#if QT_VERSION < 0x060000 // Information QRegExp exprInfo("^(Document Class:|LaTeX Font Info:|File:|Package:|Language:|.*> INFO - |\\(|\\\\).*$"); // Warnings QRegExp exprWarning("^(## Warning|LaTeX Warning|LaTeX Font Warning|Package [\\w\\.]+ Warning|Class \\w+ Warning|Warning--|Underfull|Overfull|.*> WARN - ).*$"); // Errors QRegExp exprError("^(ERROR: |!|.*---line [0-9]+ of file|.*> FATAL - |.*> ERROR - |Missing character: There is no ).*$"); +#else +// Information +QRegularExpression exprInfo("^(Document Class:|LaTeX Font Info:|File:|Package:|Language:|.*> INFO - |\\(|\\\\).*$"); +// Warnings +QRegularExpression exprWarning("^(## Warning|LaTeX Warning|LaTeX Font Warning|Package [\\w\\.]+ Warning|Class \\w+ Warning|Warning--|Underfull|Overfull|.*> WARN - ).*$"); +// Errors +QRegularExpression exprError("^(ERROR: |!|.*---line [0-9]+ of file|.*> FATAL - |.*> ERROR - |Missing character: There is no ).*$"); +#endif ///////////////////////////////////////////////////////////////////// @@ -82,6 +91,7 @@ LogHighlighter::LogHighlighter(QTextDocument * parent) void LogHighlighter::highlightBlock(QString const & text) { +#if QT_VERSION < 0x060000 // Info int index = exprInfo.indexIn(text); while (index >= 0) { @@ -103,6 +113,35 @@ void LogHighlighter::highlightBlock(QString const & text) setFormat(index, length, errorFormat); index = exprError.indexIn(text, index + length); } +#else + // Info + QRegularExpressionMatch match = exprInfo.match(text); + int index = match.capturedStart(1); + while (index >= 0) { + int length = match.capturedEnd(1) - index; + setFormat(index, length, infoFormat); + match = exprInfo.match(text, index + length); + index = match.capturedStart(1); + } + // LaTeX Warning: + match = exprWarning.match(text); + index = match.capturedStart(1); + while (index >= 0) { + int length = match.capturedEnd(1) - index; + setFormat(index, length, warningFormat); + match = exprWarning.match(text, index + length); + index = match.capturedStart(1); + } + // ! error + match = exprError.match(text); + index = match.capturedStart(1); + while (index >= 0) { + int length = match.capturedEnd(1) - index; + setFormat(index, length, errorFormat); + match = exprError.match(text, index + length); + index = match.capturedStart(1); + } +#endif } @@ -195,7 +234,11 @@ void GuiLog::on_openDirPB_clicked() } +#if QT_VERSION < 0x060000 void GuiLog::goTo(QRegExp const & exp) const +#else +void GuiLog::goTo(QRegularExpression const & exp) const +#endif { QTextCursor const newc = logTB->document()->find(exp, logTB->textCursor()); @@ -203,7 +246,11 @@ void GuiLog::goTo(QRegExp const & exp) const } +#if QT_VERSION < 0x060000 bool GuiLog::contains(QRegExp const & exp) const +#else +bool GuiLog::contains(QRegularExpression const & exp) const +#endif { return !logTB->document()->find(exp, logTB->textCursor()).isNull(); } diff --git a/src/frontends/qt/GuiLog.h b/src/frontends/qt/GuiLog.h index dc143f1ea7..cd62390fc2 100644 --- a/src/frontends/qt/GuiLog.h +++ b/src/frontends/qt/GuiLog.h @@ -66,10 +66,17 @@ private: docstring title() const; /// put the log file into the ostream void getContents(std::ostream & ss) const; +#if QT_VERSION < 0x060000 /// go to the next occurrence of the RegExp void goTo(QRegExp const & exp) const; /// does the document after cursor position contain the RegExp? bool contains(QRegExp const & exp) const; +#else + /// go to the next occurrence of the RegExp + void goTo(QRegularExpression const & exp) const; + /// does the document after cursor position contain the RegExp? + bool contains(QRegularExpression const & exp) const; +#endif private: /// Recognized log file-types diff --git a/src/frontends/qt/GuiPrefs.cpp b/src/frontends/qt/GuiPrefs.cpp index c04ef83413..7537ead048 100644 --- a/src/frontends/qt/GuiPrefs.cpp +++ b/src/frontends/qt/GuiPrefs.cpp @@ -188,7 +188,11 @@ QString browseRelToSub(QString const & filename, QString const & relpath, toqstr(makeRelPath(qstring_to_ucs4(outname), qstring_to_ucs4(relpath))); QString testname = reloutname; +#if QT_VERSION < 0x060000 testname.remove(QRegExp("^(\\.\\./)+")); +#else + testname.remove(QRegularExpression("^(\\.\\./)+")); +#endif if (testname.contains("/")) return outname; @@ -2424,7 +2428,11 @@ PrefLanguage::PrefLanguage(GuiPreferences * form) startCommandED->setValidator(new NoNewLineValidator(startCommandED)); endCommandED->setValidator(new NoNewLineValidator(endCommandED)); +#if QT_VERSION < 0x060000 defaultDecimalSepED->setValidator(new QRegExpValidator(QRegExp("\\S"), this)); +#else + defaultDecimalSepED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this)); +#endif defaultDecimalSepED->setMaxLength(1); defaultLengthUnitCO->addItem(lyx::qt_(unit_name_gui[Length::CM]), Length::CM); @@ -2584,9 +2592,12 @@ PrefUserInterface::PrefUserInterface(GuiPreferences * form) iconSetCO->addItem(qt_("Classic"), "classic"); iconSetCO->addItem(qt_("Oxygen"), "oxygen"); -#if (!(defined Q_WS_X11 || defined(QPA_XCB)) || QT_VERSION < 0x040600) - useSystemThemeIconsCB->hide(); +#if QT_VERSION >= 0x040600 + if (guiApp->platformName() != "qt4x11" + && guiApp->platformName() != "xcb" + && !guiApp->platformName().contains("wayland")) #endif + useSystemThemeIconsCB->hide(); } diff --git a/src/frontends/qt/GuiTabular.cpp b/src/frontends/qt/GuiTabular.cpp index 138296fa3f..9526e9a0e9 100644 --- a/src/frontends/qt/GuiTabular.cpp +++ b/src/frontends/qt/GuiTabular.cpp @@ -176,7 +176,11 @@ GuiTabular::GuiTabular(QWidget * parent) connect(tabularWidthED, SIGNAL(textEdited(const QString &)), this, SLOT(checkEnabled())); +#if QT_VERSION < 0x060000 decimalPointED->setValidator(new QRegExpValidator(QRegExp("\\S"), this)); +#else + decimalPointED->setValidator(new QRegularExpressionValidator(QRegularExpression("\\S"), this)); +#endif decimalPointED->setMaxLength(1); // initialize the length validator diff --git a/src/frontends/qt/GuiThesaurus.cpp b/src/frontends/qt/GuiThesaurus.cpp index 81b3cf5504..f3219563b7 100644 --- a/src/frontends/qt/GuiThesaurus.cpp +++ b/src/frontends/qt/GuiThesaurus.cpp @@ -124,9 +124,14 @@ void GuiThesaurus::selectionChanged() QString item = meaningsTV->currentItem()->text(col); // cut out the classification in brackets: // "hominid (generic term)" -> "hominid" +#if QT_VERSION < 0x060000 QRegExp re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$"); +#else + QRegularExpression re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$"); +#endif // This is for items with classifications at the beginning: // "(noun) man" -> "man"; "(noun) male (generic term)" -> "male" +#if QT_VERSION < 0x060000 QRegExp rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$"); int pos = re.indexIn(item); if (pos > -1) @@ -134,6 +139,15 @@ void GuiThesaurus::selectionChanged() pos = rex.indexIn(item); if (pos > -1) item = rex.cap(2).trimmed(); +#else + QRegularExpression rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$"); + QRegularExpressionMatch match = re.match(item); + if (match.hasMatch()) + item = match.captured(1).trimmed(); + match = rex.match(item); + if (match.hasMatch()) + item = match.captured(2).trimmed(); +#endif replaceED->setText(item); replacePB->setEnabled(!isBufferReadonly()); changed(); @@ -151,9 +165,14 @@ void GuiThesaurus::selectionClicked(QTreeWidgetItem * item, int col) QString str = item->text(col); // cut out the classification in brackets: // "hominid (generic term)" -> "hominid" +#if QT_VERSION < 0x060000 QRegExp re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$"); +#else + QRegularExpression re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$"); +#endif // This is for items with classifications at the beginning: // "(noun) man" -> "man"; "(noun) male (generic term)" -> "male" +#if QT_VERSION < 0x060000 QRegExp rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$"); int pos = re.indexIn(str); if (pos > -1) @@ -161,6 +180,15 @@ void GuiThesaurus::selectionClicked(QTreeWidgetItem * item, int col) pos = rex.indexIn(str); if (pos > -1) str = rex.cap(2).trimmed(); +#else + QRegularExpression rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$"); + QRegularExpressionMatch match = re.match(str); + if (match.hasMatch()) + str = match.captured(1).trimmed(); + match = rex.match(str); + if (match.hasMatch()) + str = match.captured(2).trimmed(); +#endif entryCO->insertItem(0, str); entryCO->setCurrentIndex(0); diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp index 7f2860f029..a5925f0c55 100644 --- a/src/frontends/qt/GuiView.cpp +++ b/src/frontends/qt/GuiView.cpp @@ -655,7 +655,7 @@ GuiView::GuiView(int id) zoom_in_->setFlat(true); zoom_in_->setFixedSize(QSize(fm.height(), fm.height())); zoom_out_ = new QPushButton(statusBar()); - zoom_out_->setText(QString(0x2212)); + zoom_out_->setText(QString(QChar(0x2212))); zoom_out_->setFixedSize(QSize(fm.height(), fm.height())); zoom_out_->setFlat(true); diff --git a/src/frontends/qt/IconPalette.cpp b/src/frontends/qt/IconPalette.cpp index 325a96e881..3c5eb7a546 100644 --- a/src/frontends/qt/IconPalette.cpp +++ b/src/frontends/qt/IconPalette.cpp @@ -19,7 +19,9 @@ #include #include #include +#if QT_VERSION < 0x060000 #include +#endif #include #include #include @@ -76,7 +78,9 @@ void TearOff::paintEvent(QPaintEvent * /*event*/) menuOpt.checkType = QStyleOptionMenuItem::NotCheckable; menuOpt.menuRect = rect(); menuOpt.maxIconWidth = 0; +#if QT_VERSION < 0x060000 menuOpt.tabWidth = 0; +#endif menuOpt.menuItemType = QStyleOptionMenuItem::TearOff; menuOpt.rect.setRect(fw, fw, width() - (fw * 2), style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this)); @@ -92,12 +96,20 @@ IconPalette::IconPalette(QWidget * parent) : QWidget(parent, Qt::Popup), tornoff_(false) { QVBoxLayout * v = new QVBoxLayout(this); +#if QT_VERSION < 0x060000 v->setMargin(0); +#else + v->setContentsMargins(0, 0, 0, 0); +#endif v->setSpacing(0); layout_ = new QGridLayout; layout_->setSpacing(0); const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this); +#if QT_VERSION < 0x060000 layout_->setMargin(fw); +#else + layout_->setContentsMargins(0, 0, 0, 0); +#endif tearoffwidget_ = new TearOff(this); connect(tearoffwidget_, SIGNAL(tearOff()), this, SLOT(tearOff())); v->addWidget(tearoffwidget_); @@ -166,7 +178,11 @@ void IconPalette::showEvent(QShowEvent * /*event*/) voffset -= parheight; } +#if QT_VERSION < 0x060000 QRect const screen = qApp->desktop()->availableGeometry(this); +#else + QRect const screen = qApp->primaryScreen()->availableGeometry(); +#endif QPoint const gpos = parentWidget()->mapToGlobal( parentWidget()->geometry().bottomLeft()); diff --git a/src/frontends/qt/IconPalette.h b/src/frontends/qt/IconPalette.h index 5e78ff6698..50c68a3583 100644 --- a/src/frontends/qt/IconPalette.h +++ b/src/frontends/qt/IconPalette.h @@ -27,7 +27,11 @@ class TearOff : public QWidget { Q_OBJECT public: TearOff(QWidget * parent); +#if QT_VERSION < 0x060000 void enterEvent(QEvent *) override; +#else + void enterEvent(QEvent *); +#endif void leaveEvent(QEvent *) override; void mouseReleaseEvent (QMouseEvent *) override; Q_SIGNALS: diff --git a/src/frontends/qt/LaTeXHighlighter.cpp b/src/frontends/qt/LaTeXHighlighter.cpp index 5ab349e485..d199fb19a2 100644 --- a/src/frontends/qt/LaTeXHighlighter.cpp +++ b/src/frontends/qt/LaTeXHighlighter.cpp @@ -43,6 +43,7 @@ LaTeXHighlighter::LaTeXHighlighter(QTextDocument * parent, bool at_letter) void LaTeXHighlighter::highlightBlock(QString const & text) { +#if QT_VERSION < 0x060000 // $ $ static const QRegExp exprMath("\\$[^\\$]*\\$"); int index = exprMath.indexIn(text); @@ -127,6 +128,102 @@ void LaTeXHighlighter::highlightBlock(QString const & text) setFormat(index, length, warningFormat); index = exprWarning.indexIn(text, index + length); } +#else + // $ $ + static const QRegularExpression exprMath("\\$[^\\$]*\\$"); + QRegularExpressionMatch match = exprMath.match(text); + int index = match.capturedStart(1); + while (index >= 0) { + int length = match.capturedEnd(1) - index; + setFormat(index, length, mathFormat); + match = exprMath.match(text, index + length); + int index = match.capturedStart(1); + } + // [ ] + static const QRegularExpression exprStartDispMath("(\\\\\\[|" + "\\\\begin\\{equation\\**\\}|" + "\\\\begin\\{eqnarray\\**\\}|" + "\\\\begin\\{align(ed|at)*\\**\\}|" + "\\\\begin\\{flalign\\**\\}|" + "\\\\begin\\{gather\\**\\}|" + "\\\\begin\\{multline\\**\\}|" + "\\\\begin\\{array\\**\\}|" + "\\\\begin\\{cases\\**\\}" + ")"); + static const QRegularExpression exprEndDispMath("(\\\\\\]|" + "\\\\end\\{equation\\**\\}|" + "\\\\end\\{eqnarray\\**\\}|" + "\\\\end\\{align(ed|at)*\\**\\}|" + "\\\\end\\{flalign\\**\\}|" + "\\\\end\\{gather\\**\\}|" + "\\\\end\\{multline\\**\\}|" + "\\\\end\\{array\\**\\}|" + "\\\\end\\{cases\\**\\}" + ")"); + int startIndex = 0; + // if previous block was in 'disp math' + // start search from 0 (for end disp math) + // otherwise, start search from 'begin disp math' + if (previousBlockState() != 1) { + match = exprStartDispMath.match(text); + startIndex = match.capturedStart(1); + } + while (startIndex >= 0) { + match = exprEndDispMath.match(text, startIndex); + int endIndex = match.capturedStart(1); + int length; + if (endIndex == -1) { + setCurrentBlockState(1); + length = text.length() - startIndex; + } else { + length = match.capturedEnd(1) - startIndex; + } + setFormat(startIndex, length, mathFormat); + match = exprStartDispMath.match(text, startIndex + length); + startIndex = match.capturedStart(1); + } + // \whatever + static const QRegularExpression exprKeywordAtOther("\\\\[A-Za-z]+"); + // \wh@tever + static const QRegularExpression exprKeywordAtLetter("\\\\[A-Za-z@]+"); + QRegularExpression const & exprKeyword = at_letter_ + ? exprKeywordAtLetter : exprKeywordAtOther; + match = exprKeyword.match(text); + index = match.capturedStart(1); + while (index >= 0) { + int length = match.capturedEnd(1) - index; + setFormat(index, length, keywordFormat); + match = exprKeyword.match(text, index + length); + index = match.capturedStart(1); + } + // %comment + // Treat a line as a comment starting at a percent sign + // * that is the first character in a line + // * that is preceded by + // ** an even number of backslashes + // ** any character other than a backslash + QRegularExpression exprComment("(?:^|[^\\\\])(?:\\\\\\\\)*(%).*$"); + match = exprComment.match(text); + index = match.capturedStart(1); + while (index >= 0) { + int const length = match.capturedEnd(1) - index + - (index - match.capturedStart(0)); + setFormat(index, length, commentFormat); + match = exprComment.match(text, index + length); + index = match.capturedStart(1); + } + // + QString lyxwarn = qt_("LyX Warning: "); + QRegularExpression exprWarning("<" + lyxwarn + "[^<]*>"); + match = exprWarning.match(text); + index = match.capturedStart(1); + while (index >= 0) { + int length = match.capturedEnd(1) - index; + setFormat(index, length, warningFormat); + match = exprWarning.match(text, index + length); + index = match.capturedStart(1); + } +#endif } } // namespace frontend diff --git a/src/frontends/qt/LayoutBox.cpp b/src/frontends/qt/LayoutBox.cpp index 719a2d324d..49d3086415 100644 --- a/src/frontends/qt/LayoutBox.cpp +++ b/src/frontends/qt/LayoutBox.cpp @@ -300,7 +300,11 @@ QString LayoutItemDelegate::underlineFilter(QString const & s) const if (f.isEmpty()) return s; QString r(s); +#if QT_VERSION < 0x060000 QRegExp pattern(charFilterRegExpC(f)); +#else + QRegularExpression pattern(charFilterRegExpC(f)); +#endif r.replace(pattern, "\\1"); return r; } @@ -321,7 +325,11 @@ void LayoutBox::Private::setFilter(QString const & s) lastSel_ = filterModel_->mapToSource(filterModel_->index(sel, 0)).row(); filter_ = s; +#if QT_VERSION < 0x060000 filterModel_->setFilterRegExp(charFilterRegExp(filter_)); +#else + filterModel_->setFilterRegularExpression(charFilterRegExp(filter_)); +#endif countCategories(); // restore old selection diff --git a/src/frontends/qt/Validator.cpp b/src/frontends/qt/Validator.cpp index c938f0ed5a..0d3b672f12 100644 --- a/src/frontends/qt/Validator.cpp +++ b/src/frontends/qt/Validator.cpp @@ -182,7 +182,11 @@ NoNewLineValidator::NoNewLineValidator(QWidget * parent) QValidator::State NoNewLineValidator::validate(QString & qtext, int &) const { +#if QT_VERSION < 0x060000 qtext.remove(QRegExp("[\\n\\r]")); +#else + qtext.remove(QRegularExpression("[\\n\\r]")); +#endif return QValidator::Acceptable; } diff --git a/src/support/mutex.cpp b/src/support/mutex.cpp index 481f0f9552..89ee2b8e23 100644 --- a/src/support/mutex.cpp +++ b/src/support/mutex.cpp @@ -20,12 +20,20 @@ namespace lyx { struct Mutex::Private { +#if QT_VERSION < 0x060000 // QMutex::Recursive: less risks for dead-locks Private() : qmutex_(QMutex::Recursive) { } QMutex qmutex_; +#else + Private() : qmutex_() + { + } + + QRecursiveMutex qmutex_; +#endif };