diff --git a/.github/workflows/mac-build.yml b/.github/workflows/mac-build.yml index 0c817f7..7c44b7a 100644 --- a/.github/workflows/mac-build.yml +++ b/.github/workflows/mac-build.yml @@ -31,8 +31,8 @@ env: HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 MACOSX_DEPLOYMENT_TARGET: 11 - DOWNLOADQT: https://github.com/kevinhendricks/BuildSigilOnMac/releases/download/for_sigil_1.0.0/Qt662.tar.xz - QT: Qt662 + DOWNLOADQT: https://github.com/kevinhendricks/BuildSigilOnMac/releases/download/for_sigil_1.0.0/Qt672.tar.xz + QT: Qt672 jobs: build: diff --git a/.github/workflows/reset-mac-caches.txt b/.github/workflows/reset-mac-caches.txt index 3c7ce0b..2da7f63 100644 --- a/.github/workflows/reset-mac-caches.txt +++ b/.github/workflows/reset-mac-caches.txt @@ -6,3 +6,4 @@ cleared cache on 08 September 2023 cleared cache on 07 October 2023 cleared cache on 15 February 2024 cleared cache on 26 April 2024 +cleared cache on 25 July 2024 diff --git a/AppearanceWidget.cpp b/AppearanceWidget.cpp index e74b45e..8af3605 100644 --- a/AppearanceWidget.cpp +++ b/AppearanceWidget.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019-2020 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada ** Copyright (C) 2019-2020 Doug Massay ** Copyright (C) 2012 John Schember ** Copyright (C) 2012 Grant Drake @@ -36,15 +36,10 @@ #include "Utility.h" AppearanceWidget::AppearanceWidget() - : m_isHighDPIComboEnabled(true) + : m_isHighDPIComboEnabled(false) { - -#if defined(Q_OS_MAC) || QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - // Disable the HighDPI combobox on Mac - // Effectively an isMacOS runtime check - // Also needed if Qt >= 6.0.0 + // Disable the HighDPI combobox on all platforms under Qt6 m_isHighDPIComboEnabled = false; -#endif ui.setupUi(this); @@ -93,11 +88,7 @@ PreferencesWidget::ResultActions AppearanceWidget::saveSettings() settings.setMainMenuIconSize(double(ui.iconSizeSlider->value())/10); // WV settings can be globally changed and will take effect immediately -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - QWebEngineSettings *web_settings = QWebEngineSettings::defaultSettings(); -#else QWebEngineSettings *web_settings = QWebEngineProfile::defaultProfile()->settings(); -#endif web_settings->setFontSize(QWebEngineSettings::DefaultFontSize, WVAppearance.font_size); web_settings->setFontFamily(QWebEngineSettings::StandardFont, WVAppearance.font_family_standard); web_settings->setFontFamily(QWebEngineSettings::SerifFont, WVAppearance.font_family_serif); diff --git a/CMakeLists.txt b/CMakeLists.txt index de78d7c..2d15b24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib ) set( PAGEEDIT_MAJOR_VERSION 2 ) -set( PAGEEDIT_MINOR_VERSION 2 ) +set( PAGEEDIT_MINOR_VERSION 3 ) set( PAGEEDIT_REVISION_VERSION 0 ) set( PAGEEDIT_FULL_VERSION ${PAGEEDIT_MAJOR_VERSION}.${PAGEEDIT_MINOR_VERSION}.${PAGEEDIT_REVISION_VERSION} ) @@ -70,12 +70,5 @@ endif() add_subdirectory( gumbo_subtree/src ) -# Pull in th proper cmake file depending on whether -# a qt5 or qt6 build was requested (defaults to qt5) - -if (${USE_QT5}) - include(CMakeLists5.txt) -else() - include(CMakeLists6.txt) -endif() +include(CMakeLists6.txt) diff --git a/CMakeLists5.txt b/CMakeLists5.txt deleted file mode 100644 index ef9d3f6..0000000 --- a/CMakeLists5.txt +++ /dev/null @@ -1,515 +0,0 @@ -######################################################## -# -# This is a CMake configuration file. -# To use it you need CMake which can be -# downloaded from here: -# http://www.cmake.org/cmake/resources/software.html -# -######################################################### - - -if( UNIX AND NOT APPLE ) - # Qt5 packages minimum version 5.9 for Linux - set(QT5_NEEDED 5.9) -else() - # Qt5 packages minimum version 5.12 for Windows/Mac - set(QT5_NEEDED 5.12) -endif() -find_package(Qt5 ${QT5_NEEDED} COMPONENTS Core Network WebEngine WebEngineWidgets Svg Widgets PrintSupport Xml LinguistTools) -set(CMAKE_AUTOMOC ON) - -if (CMAKE_VERSION VERSION_GREATER "3.27.9") - cmake_policy(SET CMP0153 OLD) -endif() - -set( SOURCE_FILES - main.cpp - MainApplication.cpp - pageedit_constants.cpp - AppEventFilter.cpp - MainWindow.cpp - SelectCharacter.cpp - SelectFiles.cpp - SelectHyperlink.cpp - SelectId.cpp - SimplePage.cpp - WebPageEdit.cpp - WebViewEdit.cpp - Inspector.cpp - Preferences.cpp - AppearanceWidget.cpp - GeneralSettings.cpp - UILanguage.cpp - UIDictionary.cpp - SettingsStore.cpp - FocusSelectLineEdit.cpp - SearchToolbar.cpp - Utility.cpp - URLInterceptor.cpp - GumboInterface.cpp - HTMLEncodingResolver.cpp - OPFReader.cpp - PEDarkStyle.cpp - webviewprinter.cpp - ClipEditor.cpp - ClipEditorModel.cpp - ClipEditorTreeView.cpp - ClipsWindow.cpp - ClassInfo.cpp - WebProfileMgr.cpp - TagAtts.cpp - QuickParser.cpp - ) - -set( HEADER_FILES - MainApplication.h - pageedit_constants.h - pageedit_exception.h - AppEventFilter.h - MainWindow.h - Zoomable.h - Viewer.h - ElementIndex.h - SelectCharacter.h - SelectFiles.h - SelectHyperlink.h - SelectId.h - SimplePage.h - WebPageEdit.h - WebViewEdit.h - Inspector.h - Preferences.h - PreferencesWidget.h - AppearanceWidget.h - GeneralSettings.h - UILanguage.h - UIDictionary.h - SettingsStore.h - FocusSelectLineEdit.h - SearchToolbar.h - Utility.h - URLInterceptor.h - GumboInterface.h - HTMLEncodingResolver.h - OPFReader.h - PEDarkStyle.h - webviewprinter.h - ClipEditor.h - ClipEditorModel.h - ClipEditorTreeView.h - ClipsWindow.h - ClassInfo.h - WebProfileMgr.h - TagAtts.h - QuickParser.h - ) - -set( FORM_FILES - main.ui - SelectCharacter.ui - SelectFiles.ui - SelectHyperlink.ui - SelectId.ui - Preferences.ui - PAppearanceWidget.ui - PGeneralSettings.ui - SearchToolbar.ui - ClipEditor.ui - ) - -set( RESOURCE_FILES - icons/icons.qrc - javascript/javascript.qrc - dark/dark.qrc - ) - -if (APPLE) - LIST(APPEND SOURCE_FILES - macos_menu_and_window_fixes.mm - ) - - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit") -endif() - -file( GLOB TS_FILES ts/pageedit_*.ts ) -file( GLOB EXAMPLE_FILES examples/* ) - - -set( DICTIONARY_FILES - de_DE - en_GB - en_US - es - fr - ) - -set( LINUX_DESKTOP_FILE - platform/linux/freedesktop/pageedit.desktop - ) - -############################################################################# - -# Runs UIC on specified files -qt5_wrap_ui( UI_FILES_H ${FORM_FILES} ) -set_property( SOURCE ${UI_FILES_H} PROPERTY SKIP_AUTOMOC ON ) -# Runs RCC on specified files -qt5_add_resources( QRC_FILES_CPP ${RESOURCE_FILES} ) -set_property( SOURCE ${QRC_FILES_CPP} PROPERTY SKIP_AUTOMOC ON ) -# Runs lrelease on the specified files -qt5_add_translation( QM_FILES ${TS_FILES} ) - -# Check if platform is 64 bit -if( NOT APPLE ) - if( CMAKE_SIZEOF_VOID_P EQUAL 4 ) - set( 64_BIT_PLATFORM 0 ) - else() - set( 64_BIT_PLATFORM 1 ) - endif() -endif() - -# Define the PageEdit version string for use in source files -set_source_files_properties( Utility.cpp PROPERTIES COMPILE_DEFINITIONS PAGEEDIT_VERSION="${PAGEEDIT_FULL_VERSION}" ) -set_source_files_properties( main.cpp PROPERTIES COMPILE_DEFINITIONS PAGEEDIT_VERSION="${PAGEEDIT_FULL_VERSION}" ) - -set( ALL_SOURCES ${SOURCE_FILES} ${HEADER_FILES} ${UI_FILES_H} ${QRC_FILES_CPP} ${QM_FILES} ) - -# Adding resource (RC) files for Windows -# Grab the current year so copyright notice is updated on Windows file properties -string( TIMESTAMP BUILD_YEAR "%Y" ) -if ( WIN32 ) - configure_file( version.rc.in ${PROJECT_BINARY_DIR}/version.rc ) - set( WINDOWS_RC_FILES - icons/icon.rc - ${PROJECT_BINARY_DIR}/version.rc - ) - list( APPEND ALL_SOURCES ${WINDOWS_RC_FILES} ) -endif() - -# Apple bundle configuration -if( APPLE ) - exec_program("mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/Resources") - - # exec_program("unzip ${MATHJAX_ZIP} -d ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/polyfills") - - exec_program("cp ${PROJECT_SOURCE_DIR}/icons/PageEdit.icns ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/Resources") - exec_program("cp ${PROJECT_SOURCE_DIR}/icons/xhtml.icns ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/Resources") - - # Create translation directory. - exec_program("mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/translations") - exec_program("mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/lib") - - # Copy the PLIST file... - exec_program("cp ${PROJECT_SOURCE_DIR}/platform/mac/MacOSXBundleInfo.plist ${PROJECT_BINARY_DIR}") - - # ...and set the PageEdit version string - exec_program("sed -i -e 's/PEVERSION/${PAGEDIT_FULL_VERSION}/g' ${PROJECT_BINARY_DIR}/MacOSXBundleInfo.plist") - - # create a directory for holding spellcheck dictionaries to be found by qtwebengine - # convert them to .bdic files in the correct location - exec_program("mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/Resources/qtwebengine_dictionaries") - foreach( DICT ${DICTIONARY_FILES} ) - exec_program("qwebengine_convert_dict ${PROJECT_SOURCE_DIR}/dictionaries/${DICT}.dic ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/Resources/qtwebengine_dictionaries/${DICT}.bdic") - endforeach( DICT ) - exec_program("mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PageEdit.app/Contents/examples") - -endif() - -############################################################################# - -# We need to pick up the ui*.h files, -# and the headers for the linked-to libraries. -# The directories are in reverse order because we're using before to -# put our include dirs before any system ones. -include_directories( BEFORE - ${GUMBO_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} ) - -############################################################################# - -# We make bundles for Mac OS X -if ( APPLE ) - add_executable( ${PROJECT_NAME} MACOSX_BUNDLE ${ALL_SOURCES} ) - set_target_properties( ${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_BINARY_DIR}/MacOSXBundleInfo.plist ) - set_target_properties(${PROJECT_NAME} PROPERTIES CMAKE_SKIP_BUILD_RPATH TRUE) -# ...and a normal executable for everything else. -else() - add_executable( ${PROJECT_NAME} WIN32 ${ALL_SOURCES} ) -endif() - -# No need to explicity link Qt5::WinMain or to use the qt5_use_modules macro since CMAKE 2.8.11. We require CMAKE 3.0.0 -target_link_libraries( ${PROJECT_NAME} ${GUMBO_LIBRARIES} Qt5::Widgets Qt5::Xml Qt5::PrintSupport - Qt5::WebEngine Qt5::WebEngineWidgets Qt5::Svg Qt5::Network ) - -############################################################################# - -# "Link time code generation" flags for MSVC -if( MSVC ) - add_definitions( /DUNICODE /D_UNICODE /DHAVE_ROUND ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") - set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi /GL" ) - set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG" ) - -# "Print all warnings" flag for GCC -elseif( CMAKE_COMPILER_IS_GNUCXX ) - add_definitions( -Wall ) -endif() - -get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION) -function(QUERY_QMAKE VAR RESULT) - exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output ) - if(NOT return_code) - file(TO_CMAKE_PATH "${output}" output) - set(${RESULT} ${output} PARENT_SCOPE) - endif(NOT return_code) -endfunction(QUERY_QMAKE) - -############################################################################### - -if( UNIX AND NOT APPLE ) - if ( NOT SHARE_INSTALL_PREFIX ) - set ( SHARE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} ) - endif() - - set ( PAGEEDIT_SHARE_ROOT "${SHARE_INSTALL_PREFIX}/share/${PROJECT_NAME}" ) - - # Set some defines that pageedit_constants.cpp can then access - set_property ( - SOURCE pageedit_constants.cpp - PROPERTY COMPILE_DEFINITIONS - PAGEEDIT_SHARE_ROOT="${PAGEEDIT_SHARE_ROOT}" - ) - - query_qmake( QT_INSTALL_BINS QT_INSTALL_BINS_DIR ) - query_qmake( QT_INSTALL_DATA QT_INSTALL_DATA_DIR ) - - # Bundled dictionaries will be coverted to qtwebengine spellcheck dicts with qwebengine_convert_dict - # by default and installed to qmake -query QT_INSTALL_DATA + ./qtwebengine_dictionaries. - # Use -DINSTALL_BUNDLED_DICTS=0 to prevent this. - set( CONVERTDICT ${QT_INSTALL_BINS_DIR}/qwebengine_convert_dict ) - if ( NOT DEFINED INSTALL_BUNDLED_DICTS ) - set ( INSTALL_BUNDLED_DICTS 1 ) - endif() - - set( SPELLCHECK_DICTS_SRC ${PROJECT_SOURCE_DIR}/dictionaries ) - # Create converted dics in bin folder so spellcheck can work in the build directory - set( CONVERTED_DICTS_DEST ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qtwebengine_dictionaries ) - # Remove previous directories - if ( EXISTS ${CONVERTED_DICTS_DEST} ) - file( REMOVE_RECURSE ${CONVERTED_DICTS_DEST} ) - endif() - # Create convert the spellcheck dictionaries into the newly created destination folder - if ( INSTALL_BUNDLED_DICTS ) - file( MAKE_DIRECTORY ${CONVERTED_DICTS_DEST} ) - foreach( DICT ${DICTIONARY_FILES} ) - execute_process( COMMAND ${CONVERTDICT} ${SPELLCHECK_DICTS_SRC}/${DICT}.dic ${CONVERTED_DICTS_DEST}/${DICT}.bdic ) - endforeach( DICT ) - endif() - - # Standard Linux 'make install' - install( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} ) - install( FILES ${LINUX_DESKTOP_FILE} DESTINATION ${SHARE_INSTALL_PREFIX}/share/applications/ ) - set( ICON_SIZE 32 48 128 256) - foreach( SIZE ${ICON_SIZE} ) - install( FILES ${PROJECT_SOURCE_DIR}/icons/app_icon_${SIZE}.png DESTINATION - ${SHARE_INSTALL_PREFIX}/share/icons/hicolor/${SIZE}x${SIZE}/apps RENAME pageedit.png ) - endforeach( SIZE ) - install( FILES ${PROJECT_SOURCE_DIR}/icons/app_icon_scalable.svg DESTINATION - ${SHARE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps RENAME pageedit.svg ) - install( FILES ${QM_FILES} DESTINATION ${PAGEEDIT_SHARE_ROOT}/translations/ ) - # Install converted dicts to qmake -query QT_INSTALL_DATA + ./qtwebengine_dictionaries - if ( INSTALL_BUNDLED_DICTS ) - install( DIRECTORY ${CONVERTED_DICTS_DEST} DESTINATION ${QT_INSTALL_DATA_DIR} ) - endif() - install( FILES ${EXAMPLE_FILES} DESTINATION ${PAGEEDIT_SHARE_ROOT}/examples/ ) -endif() - -# For Mac, add frameworks and make a DMG -if( APPLE ) - query_qmake(QT_INSTALL_TRANSLATIONS QT_TRANSLATIONS_DIR) - set( WORK_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" ) - set( MAIN_PACKAGE_DIR ${WORK_DIR}/PageEdit.app ) - - if ("${CODE_SIGN_ID}" STREQUAL "") - add_custom_target( addframeworks - COMMAND macdeployqt PageEdit.app - WORKING_DIRECTORY ${WORK_DIR} - DEPENDS ${PROJECT_NAME} ) - ELSE () - add_custom_target( addframeworks - COMMAND macdeployqt PageEdit.app -codesign="${CODE_SIGN_ID}" - WORKING_DIRECTORY ${WORK_DIR} - DEPENDS ${PROJECT_NAME} ) - ENDIF () - - add_custom_target( makedmg - COMMAND macdeployqt PageEdit.app -dmg - WORKING_DIRECTORY ${WORK_DIR}) - - add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND cp ${PROJECT_BINARY_DIR}/*.qm ${WORK_DIR}/PageEdit.app/Contents/translations/ ) - foreach( QM ${QM_FILES} ) - # Copy Qt's qm files that coincide with the above - # message( "QM = ${QM}") - string( REGEX REPLACE "(.*)(pageedit_)(.*)(\\.qm)" "\\1;\\2;\\3;\\4" PATH_ELEMENTS "${QM}" ) - list( GET PATH_ELEMENTS 2 LANG_ID ) - # message( "LANG_ID = ${LANG_ID}") - set( QTBASE_QM ${QT_TRANSLATIONS_DIR}/qtbase_${LANG_ID}.qm ) - # message( "QTBASE_QM = ${QTBASE_QM}" ) - if ( EXISTS ${QTBASE_QM} ) - add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND cp ${QTBASE_QM} ${WORK_DIR}/PageEdit.app/Contents/translations/ ) - endif() - endforeach( QM ) - # add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND cp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../lib/*.dylib ${WORK_DIR}/PageEdit.app/Contents/lib/ ) - # add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND install_name_tool -rpath ${CMAKE_BINARY_DIR}/lib "@executable_path/../lib" ${WORK_DIR}/PageEdit.app/Contents/MacOS/PageEdit ) - add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND cp ${CMAKE_SOURCE_DIR}/examples/* ${WORK_DIR}/PageEdit.app/Contents/examples ) -endif() - -if ( MSVC ) - query_qmake( QT_INSTALL_BINS QT_INSTALL_BINS ) - query_qmake( QT_INSTALL_TRANSLATIONS QT_TRANSLATIONS_DIR ) - - set( TEMP_PACKAGE_DIR ${CMAKE_BINARY_DIR}/temp_folder ) - set( MAIN_PACKAGE_DIR ${TEMP_PACKAGE_DIR}/PageEdit ) - set( OUTPUT_PACKAGE_DIR ${CMAKE_BINARY_DIR}/deploy ) - set( WINDEPLOYQT ${QT_INSTALL_BINS}/windeployqt.exe ) - set( CONVERTDICT ${QT_INSTALL_BINS}/qwebengine_convert_dict.exe ) - - # ISS conf file for the Inno Setup compiler - # We first create a CMake configured version of the ISS file, - # and then we copy it to the temp folder every time we need to build the installer. - set( ISS_MAIN_LOCATION ${CMAKE_SOURCE_DIR}/installer/PageEdit.iss ) - set( ISS_CONFIGURED_LOCATION ${CMAKE_BINARY_DIR}/PageEdit_configured.iss ) - set( ISS_TEMP_LOCATION ${CMAKE_BINARY_DIR}/temp_folder/PageEdit_configured.iss ) - - # Specify platform var for Inno - if ( 64_BIT_PLATFORM ) - # Used in the ISS CMake configuration - set( ISS_ARCH "x64" ) - set( ISS_SETUP_FILENAME_PLATFORM "-x64" ) - endif() - - # Creates a copy of the ISS file in ${ISS_CONFIGURED_LOCATION} and then configures it - # Used in the ISS CMake configuration - set( LICENSE_LOCATION ${CMAKE_SOURCE_DIR}/installer/win_installer_note.txt ) - configure_file( ${ISS_MAIN_LOCATION} ${ISS_CONFIGURED_LOCATION} ) - - set( pf_x86 "ProgramFiles(x86)" ) - find_program(SEVENZIP_BIN - NAMES 7z 7za - HINTS "$ENV{${pf_x86}}/7-zip" "$ENV{ProgramFiles}/7-zip" "$ENV{ProgramW6432}/7-zip" - PATH_SUFFIXES bin - DOC "7zip executable" - ) - message( "\n7zip location: ${SEVENZIP_BIN}\n" ) - - if( DEPLOY_SFX ) - set( SEVENZIP_ARGS a -t7z -sfx -mx9 -xr!bearer ) - set( SEVENZIP_OUTPUT "${PROJECT_NAME}_${PAGEEDIT_FULL_VERSION}.exe" ) - else() - set( SEVENZIP_ARGS a -tzip -xr!bearer ) - set( SEVENZIP_OUTPUT "${PROJECT_NAME}_${PAGEEDIT_FULL_VERSION}.zip" ) - endif() - - # Run Inno Setup's iscc compiler (*AFTER* all the PRE_BUILD custom commands execute) - add_custom_target( deployinstaller - COMMAND cmake -E echo "For this to work, Inno Setup's iscc compiler needs to be installed and on the system path." - COMMAND iscc ${ISS_TEMP_LOCATION} ) - - # Create zip archive (or self-extracting zip) instead of Windows installer - add_custom_target( deployzip - COMMAND ${CMAKE_COMMAND} -E echo "For this to work, 7zip needs to be installed (and possibly on the system path)." - COMMAND del ${SEVENZIP_OUTPUT} - COMMAND ${SEVENZIP_BIN} ${SEVENZIP_ARGS} ${SEVENZIP_OUTPUT} ${MAIN_PACKAGE_DIR} - WORKING_DIRECTORY ${OUTPUT_PACKAGE_DIR} ) - - # Intermediate step to create folders and copy files - set( TARGET_FOR_COPY copyfiles ) - add_custom_target( ${TARGET_FOR_COPY} - COMMENT "Copying files to temporary location..." - DEPENDS ${PROJECT_NAME} ) - - add_dependencies( deployzip ${TARGET_FOR_COPY} ) - add_dependencies( deployinstaller ${TARGET_FOR_COPY} ) - - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory ${MAIN_PACKAGE_DIR} - COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_PACKAGE_DIR} ) - - # Set the path of the application executable - set( EXE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX} ) - - # Copy the application executable - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${EXE_PATH} ${MAIN_PACKAGE_DIR} ) - - set( VCREDIST_VER "2022" ) - # We need to copy the CRT dlls - # Add -DWIN_INSTALLER_USE_64BIT_CRT=1 to the cmake call if you want to build - # an installer for the x64 verison of PageEdit. This will make sure that the - # correct CRT libs are included in the installer. - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD COMMAND cmake -E make_directory ${TEMP_PACKAGE_DIR}/vendor/ ) - if ( WIN_INSTALLER_USE_64BIT_CRT ) - message( STATUS "Using the 64 bit CRT in the PageEdit Windows installer" ) - message( STATUS "Ensure vcredist_x64.exe for VS${VCREDIST_VER} has been placed in installer/ if you plan on running makeinstaller" ) - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD - COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/installer/vcredist_x64.exe ${TEMP_PACKAGE_DIR}/vendor/vcredist.exe ) - else() - message( STATUS "Using the 32 bit CRT in the PageEdit Windows installer" ) - message( STATUS "Ensure vcredist_x86.exe for VS${VCREDIST_VER} has been placed in installer/ if you plan on running makeinstaller" ) - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD - COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/installer/vcredist_x86.exe ${TEMP_PACKAGE_DIR}/vendor/vcredist.exe ) - endif() - - # Copy ISS file to temp folder location - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD - COMMAND cmake -E copy ${ISS_CONFIGURED_LOCATION} ${ISS_TEMP_LOCATION} ) - - add_custom_command( TARGET ${TARGET_FOR_COPY} POST_BUILD - COMMAND ${WINDEPLOYQT} --release --no-translations --no-compiler-runtime --dir ${MAIN_PACKAGE_DIR} - --libdir ${MAIN_PACKAGE_DIR} ${MAIN_PACKAGE_DIR}/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX} ) - - # Copy the translation qm files - if( NOT EXISTS ${MAIN_PACKAGE_DIR}/translations ) - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${MAIN_PACKAGE_DIR}/translations/ ) - endif() - foreach( QM ${QM_FILES} ) - # Copy PageEdit's qm files - add_custom_command( TARGET ${TARGET_FOR_COPY} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${QM} ${MAIN_PACKAGE_DIR}/translations/ ) - # Copy Qt's qm files that coincide with the above - # message( "QM = ${QM}") - string( REGEX REPLACE "(.*)(pageedit_)(.*)(\\.qm)" "\\1;\\2;\\3;\\4" PATH_ELEMENTS "${QM}" ) - list( GET PATH_ELEMENTS 2 LANG_ID ) - # message( "LANG_ID = ${LANG_ID}") - set( QTBASE_QM ${QT_TRANSLATIONS_DIR}/qtbase_${LANG_ID}.qm ) - # message( "QTBASE_QM = ${QTBASE_QM}" ) - if ( EXISTS ${QTBASE_QM} ) - add_custom_command( TARGET ${TARGET_FOR_COPY} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${QTBASE_QM} ${MAIN_PACKAGE_DIR}/translations/ ) - endif() - endforeach( QM ) - - # Convert and copy the spellcheck dictionaries - if( NOT EXISTS ${MAIN_PACKAGE_DIR}/qtwebengine_dictionaries ) - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${MAIN_PACKAGE_DIR}/qtwebengine_dictionaries/ ) - endif() - foreach( DICT ${DICTIONARY_FILES} ) - add_custom_command( TARGET ${TARGET_FOR_COPY} POST_BUILD - COMMAND ${CONVERTDICT} ${PROJECT_SOURCE_DIR}/dictionaries/${DICT}.dic ${MAIN_PACKAGE_DIR}/qtwebengine_dictionaries/${DICT}.bdic ) - endforeach( DICT ) - - # Copy Examples - if( NOT EXISTS ${MAIN_PACKAGE_DIR}/examples ) - add_custom_command( TARGET ${TARGET_FOR_COPY} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${MAIN_PACKAGE_DIR}/examples/ ) - endif() - foreach( EXAMPLE ${EXAMPLE_FILES} ) - add_custom_command( TARGET ${TARGET_FOR_COPY} POST_BUILD COMMAND cmake -E copy ${EXAMPLE} ${MAIN_PACKAGE_DIR}/examples/ ) - endforeach( EXAMPLE ) - - # Remove the temp directory used for building the installer - add_custom_command( TARGET deployzip POST_BUILD - COMMAND ${CMAKE_COMMAND} -E remove_directory ${TEMP_PACKAGE_DIR} - COMMENT "Removing temporary directory..." ) - add_custom_command( TARGET deployinstaller POST_BUILD - COMMAND ${CMAKE_COMMAND} -E remove_directory ${TEMP_PACKAGE_DIR} - COMMENT "Removing temporary directory..." ) - -endif( MSVC ) diff --git a/CMakeLists6.txt b/CMakeLists6.txt index c981376..a3a8531 100644 --- a/CMakeLists6.txt +++ b/CMakeLists6.txt @@ -21,12 +21,12 @@ endif() if( UNIX AND NOT APPLE ) # Qt6 packages minimum version 6.2 for Linux - set(QT6_NEEDED 6.2) + set(QT6_NEEDED 6.4) else() - # Qt6 packages minimum version 5.12 for Windows/Mac - set(QT6_NEEDED 6.2) + # Qt6 packages + set(QT6_NEEDED 6.4) endif() -find_package(Qt6 ${QT6_NEEDED} COMPONENTS Core5Compat Network WebEngineCore WebEngineWidgets Svg Widgets Xml PrintSupport LinguistTools) +find_package(Qt6 ${QT6_NEEDED} COMPONENTS Network WebEngineCore WebEngineWidgets Svg Widgets Xml PrintSupport LinguistTools) set(CMAKE_AUTOMOC ON) set( SOURCE_FILES @@ -244,7 +244,7 @@ else() endif() # No need to explicity link Qt6::WinMain or to use the qt6_use_modules macro since CMAKE 2.8.11. We require CMAKE 3.0.0 -target_link_libraries( ${PROJECT_NAME} ${GUMBO_LIBRARIES} Qt6::Core5Compat Qt6::Widgets Qt6::PrintSupport +target_link_libraries( ${PROJECT_NAME} ${GUMBO_LIBRARIES} Qt6::Widgets Qt6::PrintSupport Qt6::WebEngineCore Qt6::WebEngineWidgets Qt6::Svg Qt6::Network) ############################################################################# diff --git a/ClassInfo.cpp b/ClassInfo.cpp index eca89b4..ce76653 100644 --- a/ClassInfo.cpp +++ b/ClassInfo.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2023 Kevin B. Hendricks, Stratford, ON Canada +** Copyright (C) 2023-2024 Kevin B. Hendricks, Stratford, ON Canada ** ** This file is part of PageEdit. ** @@ -27,14 +27,6 @@ const int TAB_SPACES_WIDTH = 4; static const QString DELIMITERS = "}{;"; -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - #define QT_ENUM_SKIPEMPTYPARTS Qt::SkipEmptyParts - #define QT_ENUM_KEEPEMPTYPARTS Qt::KeepEmptyParts -#else - #define QT_ENUM_SKIPEMPTYPARTS QString::SkipEmptyParts - #define QT_ENUM_KEEPEMPTYPARTS QString::KeepEmptyParts -#endif - // Note: CSSProperties and CSSSelectors are simple struct that this code // created with new and so need to be manually cleaned up to prevent // large memory leaks @@ -120,7 +112,7 @@ void ClassInfo::parseCSSSelectors(const QString &text, const int &offsetLines, c int line = search_text.left(pos + 1).count(QChar('\n')) + 1; QString selector_text = search_text.mid(pos, open_brace_pos - pos).trimmed(); // Handle case of a selector group containing multiple declarations - QStringList matches = selector_text.split(QChar(','), QT_ENUM_SKIPEMPTYPARTS); + QStringList matches = selector_text.split(QChar(','), Qt::SkipEmptyParts); foreach(QString match, matches) { CSSSelector *selector = new CSSSelector(); selector->text = selector_text; @@ -137,7 +129,7 @@ void ClassInfo::parseCSSSelectors(const QString &text, const int &offsetLines, c // Also replace any other characters like > or + not of interest match.replace(strip_non_name_chars_regex, QChar(' ')); // Now break it down into the element components - QStringList elements = match.trimmed().split(QChar(' '), QT_ENUM_SKIPEMPTYPARTS); + QStringList elements = match.trimmed().split(QChar(' '), Qt::SkipEmptyParts); foreach(QString element, elements) { if (element.contains(QChar('.'))) { QStringList parts = element.split('.'); diff --git a/ClipEditorModel.cpp b/ClipEditorModel.cpp index 40b041b..282f13b 100644 --- a/ClipEditorModel.cpp +++ b/ClipEditorModel.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2023 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2023-2024 Kevin B. Hendricks, Stratford Ontario Canada ** Copyright (C) 2012 John Schember ** Copyright (C) 2012 Dave Heiland ** Copyright (C) 2012 Grant Drake @@ -33,14 +33,6 @@ #include "Utility.h" #include "pageedit_constants.h" -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - #define QT_ENUM_SKIPEMPTYPARTS Qt::SkipEmptyParts - #define QT_ENUM_KEEPEMPTYPARTS Qt::KeepEmptyParts -#else - #define QT_ENUM_SKIPEMPTYPARTS QString::SkipEmptyParts - #define QT_ENUM_KEEPEMPTYPARTS QString::KeepEmptyParts -#endif - static const QString SETTINGS_FILE = "clips.ini"; static const QString SETTINGS_GROUP = "clip_entries"; @@ -383,7 +375,7 @@ void ClipEditorModel::AddFullNameEntry(ClipEditorModel::clipEntry *entry, QStand QString entry_name = entry->name; if (entry->name.contains("/")) { - QStringList group_names = entry->name.split("/", QT_ENUM_SKIPEMPTYPARTS); + QStringList group_names = entry->name.split("/", Qt::SkipEmptyParts); entry_name = group_names.last(); if (!entry->is_group) { diff --git a/GumboInterface.cpp b/GumboInterface.cpp index 24224fb..1b6546c 100644 --- a/GumboInterface.cpp +++ b/GumboInterface.cpp @@ -33,12 +33,6 @@ #include "string_buffer.h" #include "error.h" -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - #define QT_ENUM_SKIPEMPTYPARTS Qt::SkipEmptyParts -#else - #define QT_ENUM_SKIPEMPTYPARTS QString::SkipEmptyParts -#endif - static std::unordered_set nonbreaking_inline = { "a","abbr","acronym","b","bdo","big","br","button","cite","code","del", "dfn","em","font","i","image","img","input","ins","kbd","label","map", @@ -475,7 +469,7 @@ QString GumboInterface::get_qwebpath_to_node(GumboNode* node) GumboNode* GumboInterface::get_node_from_qwebpath(QString webpath) { - QStringList path_pieces = webpath.split(",", QT_ENUM_SKIPEMPTYPARTS); + QStringList path_pieces = webpath.split(",", Qt::SkipEmptyParts); GumboNode* node = get_root_node(); GumboNode* end_node = node; for (int i=0; i < path_pieces.count() - 1 ; ++i) { diff --git a/HTMLEncodingResolver.cpp b/HTMLEncodingResolver.cpp index 5440ecc..2a66524 100644 --- a/HTMLEncodingResolver.cpp +++ b/HTMLEncodingResolver.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2016-2020 Kevin B. Hendricks Stratford, Ontario, Canada +** Copyright (C) 2016-2024 Kevin B. Hendricks Stratford, Ontario, Canada ** Copyright (C) 2013 John Schember ** Copyright (C) 2009-2011 Strahinja Markovic ** @@ -25,20 +25,18 @@ #include #include -#include #include - +#include +#include "HTMLEncodingResolver.h" #include "Utility.h" +#include "pageedit_constants.h" #include "pageedit_exception.h" -#include "HTMLEncodingResolver.h" - const QString ENCODING_ATTRIBUTE = "encoding\\s*=\\s*(?:\"|')([^\"']+)(?:\"|')"; const QString CHARSET_ATTRIBUTE = "charset\\s*=\\s*(?:\"|')([^\"']+)(?:\"|')"; const QString STANDALONE_ATTRIBUTE = "standalone\\s*=\\s*(?:\"|')([^\"']+)(?:\"|')"; const QString VERSION_ATTRIBUTE = "<\\?xml[^>]*version\\s*=\\s*(?:\"|')([^\"']+)(?:\"|')[^>]*>"; - // Accepts a full path to an HTML file. // Reads the file, detects the encoding // and returns the text converted to Unicode. @@ -54,7 +52,7 @@ QString HTMLEncodingResolver::ReadHTMLFile(const QString &fullfilepath) QByteArray data = file.readAll(); - return Utility::ConvertLineEndings(GetCodecForHTML(data)->toUnicode(data)); + return Utility::ConvertLineEndingsAndNormalize(GetDecoderForHTML(data).decode(data)); } @@ -62,17 +60,17 @@ QString HTMLEncodingResolver::ReadHTMLFile(const QString &fullfilepath) // if no encoding is detected, the default codec for this locale is returned. // We use this function because Qt's QTextCodec::codecForHtml() function // leaves a *lot* to be desired. -const QTextCodec *HTMLEncodingResolver::GetCodecForHTML(const QByteArray &raw_text) +QStringDecoder HTMLEncodingResolver::GetDecoderForHTML(const QByteArray &raw_text) { unsigned char c1; unsigned char c2; unsigned char c3; unsigned char c4; QString text; - QTextCodec *codec; + QStringDecoder decoder; if (raw_text.length() < 4) { - return QTextCodec::codecForName("UTF-8"); + return QStringDecoder("UTF-8"); } // Check the BOM if present. @@ -81,20 +79,20 @@ const QTextCodec *HTMLEncodingResolver::GetCodecForHTML(const QByteArray &raw_te c3 = raw_text.at(2); c4 = raw_text.at(3); if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) { - return QTextCodec::codecForName("UTF-8"); + return QStringDecoder("UTF-8"); } else if (c1 == 0xFF && c2 == 0xFE && c3 == 0 && c4 == 0) { - return QTextCodec::codecForName("UTF-32LE"); + return QStringDecoder("UTF-32LE"); } else if (c1 == 0 && c2 == 0 && c3 == 0xFE && c4 == 0xFF) { - return QTextCodec::codecForName("UTF-32BE"); + return QStringDecoder("UTF-32BE"); } else if (c1 == 0xFE && c2 == 0xFF) { - return QTextCodec::codecForName("UTF-16BE"); + return QStringDecoder("UTF-16BE"); } else if (c1 == 0xFF && c2 == 0xFE) { - return QTextCodec::codecForName("UTF-16LE"); + return QStringDecoder("UTF-16LE"); } // Alternating char followed by 0 is typical of utf 16 le without BOM. if (c1 != 0 && c2 == 0 && c3 != 0 && c4 == 0) { - return QTextCodec::codecForName("UTF-16LE"); + return QStringDecoder("UTF-16LE"); } // Try to find an ecoding specified in the file itself. @@ -104,9 +102,11 @@ const QTextCodec *HTMLEncodingResolver::GetCodecForHTML(const QByteArray &raw_te QRegularExpression enc_re(ENCODING_ATTRIBUTE); QRegularExpressionMatch enc_mo = enc_re.match(text); if (enc_mo.hasMatch()) { - codec = QTextCodec::codecForName(enc_mo.captured(1).toLatin1().toUpper()); - if (codec) { - return codec; + QByteArray ba(enc_mo.captured(1).toLatin1()); + ba = FixupCodePageMapping(ba); + QStringDecoder decoder = QStringDecoder(ba); + if (decoder.isValid()) { + return decoder; } } @@ -114,21 +114,21 @@ const QTextCodec *HTMLEncodingResolver::GetCodecForHTML(const QByteArray &raw_te QRegularExpression char_re(CHARSET_ATTRIBUTE); QRegularExpressionMatch char_mo = char_re.match(text); if (char_mo.hasMatch()) { - codec = QTextCodec::codecForName(char_mo.captured(1).toLatin1().toUpper()); - if (codec) { - return codec; + QByteArray ba(char_mo.captured(1).toLatin1()); + ba = FixupCodePageMapping(ba); + QStringDecoder decoder = QStringDecoder(ba); + if (decoder.isValid()) { + return decoder; } } // See if all characters within this document are utf-8. if (IsValidUtf8(raw_text)) { - return QTextCodec::codecForName("UTF-8"); + return QStringDecoder("UTF-8"); } - // Finally, let Qt guess and if it doesn't know it will return the codec - // for the current locale. - text = raw_text; - return QTextCodec::codecForHtml(raw_text, QTextCodec::codecForLocale()); + // Finally, let Qt guess + return QStringDecoder::decoderForHtml(raw_text); } @@ -207,3 +207,17 @@ bool HTMLEncodingResolver::IsValidUtf8(const QByteArray &string) return true; } + +QByteArray HTMLEncodingResolver::FixupCodePageMapping(const QByteArray& ba) +{ + if (ba == "cp1250" || ba == "CP1250" || ba == "cp-1250" || ba == "CP-1250") return QByteArray("windows-1250"); + if (ba == "cp1251" || ba == "CP1251" || ba == "cp-1251" || ba == "CP-1251") return QByteArray("windows-1251"); + if (ba == "cp1252" || ba == "CP1252" || ba == "cp-1252" || ba == "CP-1252") return QByteArray("windows-1252"); + if (ba == "cp1253" || ba == "CP1253" || ba == "cp-1253" || ba == "CP-1253") return QByteArray("windows-1253"); + if (ba == "cp1254" || ba == "CP1254" || ba == "cp-1254" || ba == "CP-1254") return QByteArray("windows-1254"); + if (ba == "cp1255" || ba == "CP1255" || ba == "cp-1255" || ba == "CP-1255") return QByteArray("windows-1255"); + if (ba == "cp1256" || ba == "CP1256" || ba == "cp-1256" || ba == "CP-1256") return QByteArray("windows-1256"); + if (ba == "cp1257" || ba == "CP1257" || ba == "cp-1257" || ba == "CP-1257") return QByteArray("windows-1257"); + if (ba == "cp1258" || ba == "CP1258" || ba == "cp-1258" || ba == "CP-1258") return QByteArray("windows-1258"); + return QByteArray(ba); +} diff --git a/HTMLEncodingResolver.h b/HTMLEncodingResolver.h index d9e635e..95797f1 100644 --- a/HTMLEncodingResolver.h +++ b/HTMLEncodingResolver.h @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2016-2020 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2016-2024 Kevin B. Hendricks, Stratford Ontario Canada ** Copyright (C) 2009-2011 Strahinja Markovic ** ** This file is part of PageEdit. @@ -24,7 +24,7 @@ #ifndef HTMLEncodingResolver_H #define HTMLEncodingResolver_H -#include +#include class QString; @@ -44,12 +44,14 @@ class HTMLEncodingResolver // if no encoding is detected, the default codec for this locale is returned. // We use this function because Qt's QTextCodec::codecForHtml() function // leaves a *lot* to be desired. - static const QTextCodec *GetCodecForHTML(const QByteArray &raw_text); + static QStringDecoder GetDecoderForHTML(const QByteArray &raw_text); // This function goes through the entire byte array // and tries to see whether this is a valid UTF-8 sequence. // If it's valid, this is probably a UTF-8 string. static bool IsValidUtf8(const QByteArray &string); + + static QByteArray FixupCodePageMapping(const QByteArray& ba); }; diff --git a/Inspector.cpp b/Inspector.cpp index cb97085..661eb8d 100644 --- a/Inspector.cpp +++ b/Inspector.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** - ** Copyright (C) 2019-2020 Kevin B. Hendricks, Stratford Ontario Canada + ** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada ** ** This file is part of PageEdit. ** @@ -86,9 +86,7 @@ Inspector::~Inspector() if (m_inspectView) { m_inspectView->close(); m_view = nullptr; -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) m_inspectView->page()->setInspectedPage(nullptr); -#endif delete m_inspectView; m_inspectView = nullptr; } @@ -148,31 +146,16 @@ void Inspector::UpdateFinishedState(bool okay) void Inspector::InspectPageofView(QWebEngineView* view) { m_view = view; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) if (m_view) { m_inspectView->page()->setInspectedPage(m_view->page()); } -#else - if (m_view) { - QString not_supported = tr("The Inspector functionality is not supported before Qt 5.11"); - QString response = "Warning

" + - not_supported + "

"; - m_inspectView->setHtml(response); - show(); - } -#endif } void Inspector::StopInspection() { SaveSettings(); m_view = nullptr; -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) m_inspectView->page()->setInspectedPage(nullptr); -#else - m_inspectView->setHtml(""); -#endif } diff --git a/MainApplication.cpp b/MainApplication.cpp index d6c08cd..8427109 100644 --- a/MainApplication.cpp +++ b/MainApplication.cpp @@ -1,6 +1,7 @@ /************************************************************************ ** -** Copyright (C) 2019-2021 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Doug Massay ** Copyright (C) 2012 John Schember ** Copyright (C) 2012 Grant Drake ** Copyright (C) 2012 Dave Heiland @@ -26,50 +27,55 @@ #include #include #include + +#if QT_VERSION >= QT_VERSION_CHECK(6,5,0) +#include +#endif + #include #include #include "MainApplication.h" +#define DBG if(0) + MainApplication::MainApplication(int &argc, char **argv) : QApplication(argc, argv), - m_Style(nullptr), - m_isDark(false) -{ -#ifdef Q_OS_MAC - // on macOS the application palette actual text colors never seem to change when DarkMode is enabled - // so use a mac style standardPalette -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - m_Style = QStyleFactory::create("macintosh"); -#else - m_Style = QStyleFactory::create("macos"); -#endif - QPalette app_palette = m_Style->standardPalette(); - m_isDark = app_palette.color(QPalette::Active,QPalette::WindowText).lightness() > 128; - fixMacDarkModePalette(app_palette); - // set the initial app palette - setPalette(app_palette); -#endif -} - -void MainApplication::fixMacDarkModePalette(QPalette &pal) + m_isDark(false), + m_PaletteChangeTimer(new QTimer()), + m_AlwaysUseNFC(true) { -# ifdef Q_OS_MAC - // See QTBUG-75321 and follow Kovid's workaround for broken ButtonText always being dark - pal.setColor(QPalette::ButtonText, pal.color(QPalette::WindowText)); - if (m_isDark) { - // make alternating base color change not so sharp - pal.setColor(QPalette::AlternateBase, pal.color(QPalette::Base).lighter(150)); - // make link color better for dark mode (try to match calibre for consistency) - pal.setColor(QPalette::Link, QColor("#6cb4ee")); - } -#endif -} - + // Do this only once early on in the PageEdit startup + if (qEnvironmentVariableIsSet("PAGEEDIT_DISABLE_NFC_NORMALIZATION")) m_AlwaysUseNFC = false; + // Keep track on our own of dark or light + m_isDark = qApp->palette().color(QPalette::Active,QPalette::WindowText).lightness() > 128; + // Set up PaletteChangeTimer to absorb multiple QEvents + // We need this for older < Qt 6.5 and as a backup mechanism for Linux + // Whose ability to detect theme changes is not in a good state + m_PaletteChangeTimer->setSingleShot(true); + m_PaletteChangeTimer->setInterval(50); + connect(m_PaletteChangeTimer, SIGNAL(timeout()),this, SLOT(systemColorChanged())); + m_PaletteChangeTimer->stop(); + // Connect system color scheme change signal to reporting mechanism + // Note: This mechanism is very very unreliable on Linux (across many distributions and desktops) + // So fall back to the QApplication:Palette change event instead for all of Linux for now +#if QT_VERSION >= QT_VERSION_CHECK(6,5,0) + DBG qDebug() << "initial styleHints colorScheme: " << styleHints()->colorScheme(); + if (styleHints()->colorScheme() == Qt::ColorScheme::Unknown) { + m_isDark = qApp->palette().color(QPalette::Active,QPalette::WindowText).lightness() > 128; + } else { + m_isDark = styleHints()->colorScheme() == Qt::ColorScheme::Dark; + } + connect(styleHints(), &QStyleHints::colorSchemeChanged, this, [this]() { + MainApplication::systemColorChanged(); + }); +#endif +} + bool MainApplication::event(QEvent *pEvent) { @@ -78,30 +84,141 @@ bool MainApplication::event(QEvent *pEvent) } else if (pEvent->type() == QEvent::ApplicationDeactivate) { emit applicationDeactivated(); } -#ifdef Q_OS_MAC if (pEvent->type() == QEvent::ApplicationPaletteChange) { - // qDebug() << "Application Palette Changed"; - QTimer::singleShot(0, this, SLOT(EmitPaletteChanged())); - } + // can be generated multiple times + DBG qDebug() << "Application Palette Changed"; + +#if QT_VERSION < QT_VERSION_CHECK(6,5,0) || (!defined(Q_OS_WIN32) && !defined(Q_OS_MAC)) + // Use this approach as a backup for Linux currently + if (m_PaletteChangeTimer->isActive()) m_PaletteChangeTimer->stop(); + m_PaletteChangeTimer->start(); #endif + + } return QApplication::event(pEvent); } void MainApplication::EmitPaletteChanged() { -#ifdef Q_OS_MAC - // on macOS the application palette actual colors never seem to change after launch - // even when DarkMode is enabled. So we use a mac style standardPalette to determine - // if a drak vs light mode transition has been made and then use it to set the - // Application palette - QPalette app_palette = m_Style->standardPalette(); - bool isdark = app_palette.color(QPalette::Active,QPalette::WindowText).lightness() > 128; - if (m_isDark != isdark) { - // qDebug() << "Theme changed " << "was isDark:" << m_isDark << "now isDark:" << isdark; + DBG qDebug() << "emitting applicationPaletteChanged"; + emit applicationPaletteChanged(); +} + +void MainApplication::systemColorChanged() +{ + // intential race on Linux so that both approaches work (typically won by styleHint() signal + // if it ever gets properly generated + m_PaletteChangeTimer->stop(); + bool theme_changed = false; + bool isdark = qApp->palette().color(QPalette::Active,QPalette::WindowText).lightness() > 128; + DBG qDebug() << "reached systemColorChanged"; + +#if QT_VERSION < QT_VERSION_CHECK(6,5,0) + // in reality we really should not care if light or dark, just that theme changed + // but this is where we are at now + if (isdark != m_isDark) { m_isDark = isdark; - fixMacDarkModePalette(app_palette); - setPalette(app_palette); - emit applicationPaletteChanged(); + theme_changed = true; + } + +#else // Qt >= 6.5 and not Linux till it gets more robust + + switch (styleHints()->colorScheme()) + { + case Qt::ColorScheme::Light: + DBG qDebug() << "System Changed to Light Theme"; + m_isDark = false; + theme_changed = true; + +#ifdef Q_OS_WIN32 + windowsLightThemeChange(); +#endif // Q_OS_WIN32 + + break; + + case Qt::ColorScheme::Unknown: + DBG qDebug() << "System Changed to Unknown Theme"; + // This is typical needed for all linux where Qt can not properly + // identify the theme being used + if (isdark != m_isDark) { + m_isDark = isdark; + theme_changed = true; + } + break; + + case Qt::ColorScheme::Dark: + DBG qDebug() << "System Changed to Dark Theme"; + m_isDark = true; + theme_changed = true; + +#ifdef Q_OS_WIN32 + windowsDarkThemeChange(); +#endif // Q_OS_WIN32 + + break; + } + +#endif // Qt Version Check + + if (theme_changed) QTimer::singleShot(0, this, SLOT(EmitPaletteChanged())); + +} + +void MainApplication::windowsDarkThemeChange() +{ +#if 0 // FIXME: Is any of this needed on PageEdit? + SettingsStore settings; + if (settings.uiUseCustomSigilDarkTheme()) { + QStyle* astyle = QStyleFactory::create("Fusion"); + setStyle(astyle); + //Handle the new CaretStyle (double width cursor) + bool isbstyle = false; + QStyle* bstyle; + if (settings.uiDoubleWidthTextCursor()) { + bstyle = new CaretStyle(astyle); + setStyle(bstyle); + isbstyle = true; + } + // modify windows sigil palette to our dark + QStyle* cstyle; + if (isbstyle) { + cstyle = new SigilDarkStyle(bstyle); + } else { + cstyle = new SigilDarkStyle(astyle); + } + setStyle(cstyle); + setPalette(style()->standardPalette()); + + // Add back stylesheet changes added after MainApplication started + if (!m_accumulatedQss.isEmpty()) { + setStyleSheet(styleSheet().append(m_accumulatedQss)); + DBG qDebug() << styleSheet(); + } + } +#endif +} + +void MainApplication::windowsLightThemeChange() +{ +#if 0 // FIXME: Is any of this needed on PageEdit? + SettingsStore settings; + if (settings.uiUseCustomSigilDarkTheme()) { + // Windows Fusion light mode + QStyle* astyle = QStyleFactory::create("Fusion"); + setStyle(astyle); + // Handle the new CaretStyle (double width cursor) + if (settings.uiDoubleWidthTextCursor()) { + QStyle* bstyle = new CaretStyle(astyle); + setStyle(bstyle); + } + setPalette(style()->standardPalette()); + // Add back stylesheet changes added after MainApplication started + if (!m_accumulatedQss.isEmpty()) { + setStyleSheet(m_accumulatedQss); + DBG qDebug() << styleSheet(); + } else { + setStyleSheet(""); + } } #endif } diff --git a/MainApplication.h b/MainApplication.h index 8c7b320..6c4dca6 100644 --- a/MainApplication.h +++ b/MainApplication.h @@ -1,24 +1,25 @@ /************************************************************************ ** -** Copyright (C) 2019 Kevin B. Hendricks, Stratford, Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford, Ontario Canada +** Copyright (C) 2019-2024 Doug Massay ** Copyright (C) 2012 John Schember ** Copyright (C) 2012 Grant Drake ** Copyright (C) 2012 Dave Heiland ** -** This file is part of Sigil. +** This file is part of PageEdit. ** -** Sigil is free software: you can redistribute it and/or modify +** PageEdit 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. ** -** Sigil is distributed in the hope that it will be useful, +** PageEdit 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 Sigil. If not, see . +** along with PageEdit. If not, see . ** *************************************************************************/ @@ -30,7 +31,7 @@ #include #include -class QStyle; +class QTimer; class MainApplication : public QApplication { @@ -40,7 +41,7 @@ class MainApplication : public QApplication MainApplication(int &argc, char **argv); bool isDarkMode() { return m_isDark; } - void fixMacDarkModePalette(QPalette & pal); + bool AlwaysUseNFC(){ return m_AlwaysUseNFC; }; signals: void applicationActivated(); @@ -49,13 +50,17 @@ class MainApplication : public QApplication public slots: void EmitPaletteChanged(); + void systemColorChanged(); protected: bool event(QEvent *pEvent); private: - QStyle * m_Style; + void windowsDarkThemeChange(); + void windowsLightThemeChange(); bool m_isDark; + QTimer * m_PaletteChangeTimer; + bool m_AlwaysUseNFC = true; }; #endif // MAINAPPLICATION_H diff --git a/MainWindow.cpp b/MainWindow.cpp index 770076c..2aeb196 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019-2023 Kevin Hendricks, Doug Massay +** Copyright (C) 2019-2024 Kevin Hendricks, Doug Massay ** ** This file is part of PageEdit. ** @@ -1599,7 +1599,6 @@ bool MainWindow::Save() void MainWindow::printRendered() { -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) // Refresh skipflags from Prefs SettingsStore settings; m_skipPrintWarnings = settings.skipPrintWarnings(); @@ -1632,18 +1631,6 @@ void MainWindow::printRendered() settings.setSkipPrintWarnings(m_skipPrintWarnings); m_WebViewPrinter->setPage(m_WebView->url(), m_skipPrintPreview); -#else - QMessageBox msgbox; - QString text = tr("Feature not available before Qt5.12.x"); - msgbox.setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint); - msgbox.setModal(true); - msgbox.setWindowTitle("PageEdit"); - msgbox.setText("

" + text + "


"); - msgbox.setIcon(QMessageBox::Icon::Warning); - msgbox.setStandardButtons(QMessageBox::Close); - msgbox.exec(); -#endif - } void MainWindow::Open() @@ -1943,7 +1930,6 @@ void MainWindow::Superscript() } -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) void MainWindow::Bold() { m_WebView->triggerPageAction(QWebEnginePage::ToggleBold); } void MainWindow::Italic() { m_WebView->triggerPageAction(QWebEnginePage::ToggleItalic); } void MainWindow::Underline() { m_WebView->triggerPageAction(QWebEnginePage::ToggleUnderline); } @@ -1956,20 +1942,6 @@ void MainWindow::DecreaseIndent() { m_WebView->triggerPageAction(QWebEngineP void MainWindow::IncreaseIndent() { m_WebView->triggerPageAction(QWebEnginePage::Indent); } void MainWindow::InsertBulletedList() { m_WebView->triggerPageAction(QWebEnginePage::InsertUnorderedList); } void MainWindow::InsertNumberedList() { m_WebView->triggerPageAction(QWebEnginePage::InsertOrderedList); } -#else -void MainWindow::Bold() { m_WebView->ExecCommand("bold"); } -void MainWindow::Italic() { m_WebView->ExecCommand("italic"); } -void MainWindow::Underline() { m_WebView->ExecCommand("underline"); } -void MainWindow::Strikethrough() { m_WebView->ExecCommand("strikeThrough"); } -void MainWindow::AlignLeft() { m_WebView->ExecCommand("justifyLeft"); } -void MainWindow::AlignCenter() { m_WebView->ExecCommand("justifyCenter"); } -void MainWindow::AlignRight() { m_WebView->ExecCommand("justifyRight"); } -void MainWindow::AlignJustify() { m_WebView->ExecCommand("justifyFull"); } -void MainWindow::DecreaseIndent() { m_WebView->ExecCommand("outdent"); } -void MainWindow::IncreaseIndent() { m_WebView->ExecCommand("indent"); } -void MainWindow::InsertBulletedList() { m_WebView->ExecCommand("insertUnorderedList"); } -void MainWindow::InsertNumberedList() { m_WebView->ExecCommand("insertOrderedList"); } -#endif void MainWindow::ShowMessageOnStatusBar(const QString &message, int millisecond_duration) @@ -2140,11 +2112,7 @@ void MainWindow::ConnectSignalsToSlots() connect(ui.actionHeadingNormal, SIGNAL(triggered()), m_headingMapper, SLOT(map())); m_headingMapper->setMapping(ui.actionHeadingNormal, "Normal"); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - connect(m_headingMapper, SIGNAL(mapped(const QString &)), this, SLOT(ApplyHeadingToSelection(const QString &))); -#else connect(m_headingMapper, SIGNAL(mappedString(const QString &)), this, SLOT(ApplyHeadingToSelection(const QString &))); -#endif connect(ui.actionHeadingPreserveAttributes,SIGNAL(triggered(bool)),this,SLOT(SetPreserveHeadingAttributes(bool))); @@ -2207,11 +2175,7 @@ void MainWindow::ConnectSignalsToSlots() m_casingChangeMapper->setMapping(ui.actionCasingUppercase, Utility::Casing_Uppercase); m_casingChangeMapper->setMapping(ui.actionCasingTitlecase, Utility::Casing_Titlecase); m_casingChangeMapper->setMapping(ui.actionCasingCapitalize, Utility::Casing_Capitalize); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - connect(m_casingChangeMapper, SIGNAL(mapped(int)), this, SLOT(ChangeCasing(int))); -#else connect(m_casingChangeMapper, SIGNAL(mappedInt(int)), this, SLOT(ChangeCasing(int))); -#endif // View/Zoom Related connect(ui.actionZoomIn, SIGNAL(triggered()), this, SLOT(ZoomIn())); diff --git a/QuickParser.cpp b/QuickParser.cpp index 8e50181..66f08b7 100644 --- a/QuickParser.cpp +++ b/QuickParser.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2024 Kevin B. Hendricks, Stratford Ontario +** Copyright (C) 2020-2024 Kevin B. Hendricks, Stratford Ontario ** ** This file is part of PageEdit. ** @@ -22,12 +22,13 @@ #include #include #include -#include +#include #include #include "TagAtts.h" #include "Utility.h" #include "QuickParser.h" +#include "pageedit_constants.h" const QString WHITESPACE_CHARS=" \v\t\n\r\f"; @@ -59,7 +60,7 @@ QuickParser::MarkupInfo QuickParser::parse_next() { MarkupInfo mi; mi.pos = -1; - QStringRef markup = parseML(); + QStringView markup = parseML(); if (!markup.isNull()) { if ((markup.at(0) == '<') && (markup.at(markup.size() - 1) == '>')) { parseTag(markup, mi); @@ -137,15 +138,15 @@ QString QuickParser::serialize_markup(const QuickParser::MarkupInfo& mi) // private routines -QStringRef QuickParser::parseML() +QStringView QuickParser::parseML() { int p = m_next; m_pos = p; - if (p >= m_source.length()) return QStringRef(); + if (p >= m_source.length()) return QStringView(); if (m_source.at(p) != '<') { // we have text leading up to a tag start m_next = findTarget("<", p+1); - return Utility::SubstringRef(m_pos, m_next, m_source); + return Utility::SubstringView(m_pos, m_next, m_source); } // we have a tag or special case // handle special cases first @@ -153,12 +154,12 @@ QStringRef QuickParser::parseML() if (tstart.startsWith("", p+4, true); - return Utility::SubstringRef(m_pos, m_next, m_source); + return Utility::SubstringView(m_pos, m_next, m_source); } if (tstart.startsWith(" as part of the string m_next = findTarget("]]>", p+9, true); - return Utility::SubstringRef(m_pos, m_next, m_source); + return Utility::SubstringView(m_pos, m_next, m_source); } // include ending > as part of the string m_next = findTarget(">", p+1, true); @@ -167,11 +168,11 @@ QStringRef QuickParser::parseML() if ((ntb != -1) && (ntb < m_next)) { m_next = ntb; } - return Utility::SubstringRef(m_pos, m_next, m_source); + return Utility::SubstringView(m_pos, m_next, m_source); } -void QuickParser::parseTag(const QStringRef& tagstring, QuickParser::MarkupInfo& mi) +void QuickParser::parseTag(const QStringView tagstring, QuickParser::MarkupInfo& mi) { Q_ASSERT(tagstring.at(0) == '<'); Q_ASSERT(tagstring.at(tagstring.size() - 1) == '>'); @@ -181,7 +182,7 @@ void QuickParser::parseTag(const QStringRef& tagstring, QuickParser::MarkupInfo& // first handle special cases if (c == '?') { - if (tagstring.startsWith("= 0) mi.ttype = "single"; + if (tagstring.indexOf(QChar('/'), p) >= 0) mi.ttype = "single"; } return; } @@ -261,14 +262,14 @@ int QuickParser::findTarget(const QString &tgt, int p, bool after) } -int QuickParser::skipAnyBlanks(const QStringRef &tgt, int p) +int QuickParser::skipAnyBlanks(const QStringView tgt, int p) { while((p < tgt.length()) && (WHITESPACE_CHARS.contains(tgt.at(p)))) p++; return p; } -int QuickParser::stopWhenContains(const QStringRef &tgt, const QString& stopchars, int p) +int QuickParser::stopWhenContains(const QStringView tgt, const QString& stopchars, int p) { while((p < tgt.length()) && !stopchars.contains(tgt.at(p))) p++; return p; diff --git a/QuickParser.h b/QuickParser.h index 9b2eb40..e91a906 100644 --- a/QuickParser.h +++ b/QuickParser.h @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2024 Kevin B. Hendricks Stratford, ON, Canada +** Copyright (C) 2020-2024 Kevin B. Hendricks Stratford, ON, Canada ** ** This file is part of PageEdit. ** @@ -23,7 +23,7 @@ #define QUICK_PARSER #include -#include +#include #include "TagAtts.h" @@ -51,11 +51,11 @@ class QuickParser QString serialize_markup(const MarkupInfo &mi); private: - QStringRef parseML(); - void parseTag(const QStringRef &tagstring, MarkupInfo &mi); + QStringView parseML(); + void parseTag(const QStringView tagstring, MarkupInfo &mi); int findTarget(const QString &tgt, int p, bool after=false); - int skipAnyBlanks(const QStringRef &segment, int p); - int stopWhenContains(const QStringRef &segment, const QString& stopchars, int p); + int skipAnyBlanks(const QStringView segment, int p); + int stopWhenContains(const QStringView segment, const QString& stopchars, int p); QString m_source; int m_pos; diff --git a/README.md b/README.md index 7e091bf..5c5cdaa 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This app is working and fundamentally complete. ![PageEdit](screencaps/add-links.png?raw=true) Add Links -It prefers Qt 6.6.2 or later but can still be built with Qt 5.15.9. +It prefers Qt 6.7.2 or later but can still be built with Qt 6.4.2. Building on macOS Ventura ------------------------- @@ -29,7 +29,7 @@ After checking out the PageEdit github repo into a PageEdit directory `export MACOSX_DEPLOYMENT_TARGET=11.0`
-`export MYQTHOME=~/Qt653`
+`export MYQTHOME=~/Qt672`
`export PATH=${PATH}:${MYQTHOME}/bin`
`mkdir build`
`cd build`
@@ -49,10 +49,10 @@ After checking out the PageEdit github repo into a PageEdit directory On Linux -------- -Make sure a minimum of Qt5.9.4(ish) is installed (with the WebEngine package) as well as cmake.
+Make sure a minimum of Qt6.4.2(ish) is installed (with the WebEngine package) as well as cmake.
You build in a separate directory and not in the source directory. -Qt 6.6.2 or later is preferred but Qt5.13+ is probably a more realistic minimum to be able enjoy all of PageEdit's features. +Qt 6.7.2 or later is preferred. Get the PageEdit Source: @@ -64,7 +64,7 @@ __Ubuntu__ `sudo apt-get install build-essential`
`sudo apt-get install cmake`
-`sudo apt-get install qt6-webengine-dev qt6-webengine-dev-tools qt6-base-dev-tools qt6-tools-dev qt6-tools-dev-tools qt6-5compat-dev libqt6svg6` +`sudo apt-get install qt6-webengine-dev qt6-webengine-dev-tools qt6-base-dev-tools qt6-tools-dev qt6-tools-dev-tools libqt6svg6` `mkdir build`
`cd build`
@@ -88,16 +88,12 @@ To test `make install` (defaults to the /usr/local prefix, so use sudo if required). -__NOTE__: certain features, like Inspector, will require a minimum of Qt5.11.x to function on Linux. - -__NOTE__: If you want to build with Qt5, you'll obviously need to add -DUSE_Qt5=1 and change -DQt6_DIR to -DQt5_DIR and point it to your Qt5 installation. - By default, bundled hunspell dictionaries are converted to webengine spell check dictionaries (with qt tools) and installed to the QT_INSTALL_DATA/qtwebengine_dictionaries location. This location can be found using the qmake binary (of the Qt you're building PageEdit with) with the following command `-qmake -query QT_INSTALL_DATA` . If using the system Qt, this will typically be /usr/share/qt/qtwebengine_dictionaries. To disable the conversion/installation of these bundled dictionaries, use -DNSTALL_BUNDLED_DICTS=0 when configuring PageEdit with cmake. Arch Linux already includes these dictionaries with the corresponding hunspell language dictionaries. So you'll want to skip their conversion/installation on Arch and make sure you have the correct hunspell languages installed instead. On Windows: ----------- -Qt6.6.2 or higher is preferred, but you'll want to maintain a minimum of Qt5.13.x (with the WebEngine component) if you want to take advantage of all features. A minimum of Visual Studio 2022 is required if you want to use Qt6.6.2. Install cmake 3.18+ and make sure its bin directory is added to your path. +Qt6.7.2 or higher is preferred, but you'll want to maintain a minimum of Qt6.4.2 (with the WebEngine component) if you want to take advantage of all features. A minimum of Visual Studio 2022 is required if you want to use Qt6.7.2. Install cmake 3.18+ and make sure its bin directory is added to your path. Make sure that Qt's bin directory is also added to your PATH. Take note of the path for your Qt's prefix (the directory right above the bin directory). Open an "x64 Native Tools Command Prompt for VS2022" from the Start menu and cd to wherever you want to build. @@ -116,9 +112,7 @@ Use `nmake deployinstaller` to package PageEdit and all of its dependencies into __NOTE__: if you configure PageEdit with the -DDEPLOY_SFX=1 cmake option before compiling, 'nmake deploy` will attempt to create a 7-Zip self-extracting archive. So naturally, make sure 7-Zip is installed before trying to use it. -__NOTE__: as of this writing, the Official PageEdit release are built using Qt6.6.2 - -__NOTE__: If you want to build with Qt5, you'll obviously need to add -DUSE_Qt5=1 and change -DQt6_DIR to -DQt5_DIR and point it to your Qt5 installation. +__NOTE__: as of this writing, the Official PageEdit release are built using Qt6.7.2 ## For Github repository maintainers (who am I kidding, this is to keep myself from forgetting/messing up): diff --git a/SearchToolbar.cpp b/SearchToolbar.cpp index 468a124..46abb1d 100644 --- a/SearchToolbar.cpp +++ b/SearchToolbar.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** - ** Copyright (C) 2019-2021 Kevin B. Hendricks, Stratford Ontario Canada + ** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada ** ** This file is part of PageEdit. ** @@ -35,10 +35,7 @@ #include #include -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include -#endif - #include "SearchToolbar.h" #include "WebViewEdit.h" @@ -134,12 +131,8 @@ void SearchToolbar::setText(const QString &text) void SearchToolbar::searchText(const QString &text) { QPointer guard = this; -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - m_view->findText(text, m_findFlags, [=](bool found) { -#else m_view->findText(text, m_findFlags, [=](const QWebEngineFindTextResult& result) { bool found = result.numberOfMatches() > 0; -#endif if (!guard) { return; } diff --git a/SelectCharacter.cpp b/SelectCharacter.cpp index 76a1f3e..3617066 100644 --- a/SelectCharacter.cpp +++ b/SelectCharacter.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2018-2021 Kevin B. Hendricks, Stratford, ON Canada +** Copyright (C) 2018-2024 Kevin B. Hendricks, Stratford, ON Canada ** Copyright (C) 2012 John Schember ** Copyright (C) 2012 Dave Heiland ** @@ -437,9 +437,5 @@ void SelectCharacter::WriteSettings() void SelectCharacter::connectSignalsSlots() { -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - connect(m_buttonMapper, SIGNAL(mapped(const QString &)), this, SLOT(SetSelectedCharacter(const QString &))); -#else connect(m_buttonMapper, SIGNAL(mappedString(const QString &)), this, SLOT(SetSelectedCharacter(const QString &))); -#endif } diff --git a/SelectFiles.cpp b/SelectFiles.cpp index 9e54a44..2ec9a74 100644 --- a/SelectFiles.cpp +++ b/SelectFiles.cpp @@ -109,9 +109,7 @@ SelectFiles::SelectFiles(QString title, m_WebView->setPage(new SimplePage(profile, m_WebView)); m_WebView->setContextMenuPolicy(Qt::NoContextMenu); m_WebView->setAcceptDrops(false); -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) m_WebView->page()->settings()->setAttribute(QWebEngineSettings::ShowScrollBars,false); -#endif ui.avLayout->addWidget(m_WebView); ui.Details->setFocusPolicy(Qt::NoFocus); m_WebView->setFocusPolicy(Qt::NoFocus); diff --git a/SettingsStore.cpp b/SettingsStore.cpp index 4c00363..734a595 100644 --- a/SettingsStore.cpp +++ b/SettingsStore.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2016-2023 Kevin B. Hendricks, Stratford, ON +** Copyright (C) 2016-2024 Kevin B. Hendricks, Stratford, ON ** Copyright (C) 2011-2013 John Schember ** Copyright (C) 2012-2013 Dave Heiland ** @@ -65,11 +65,7 @@ static QString KEY_USE_WSPREWRAP = SETTINGS_GROUP + "/" + "use_white_space_pre_w static QString KEY_SKIP_PRINT_WARNINGS = SETTINGS_GROUP + "/" + "skipprintwarnings"; static QString KEY_SKIP_PRINT_PREVIEW = SETTINGS_GROUP + "/" + "skipprintpreview"; -#if QT_VERSION < QT_VERSION_CHECK(6,0,0) -static const QString SETTINGS_FILE = PAGEEDIT_SETTINGS_FILE; -#else static const QString SETTINGS_FILE = PAGEEDIT_V6_SETTINGS_FILE; -#endif SettingsStore::SettingsStore() : QSettings(Utility::DefinePrefsDir() + "/" + SETTINGS_FILE, QSettings::IniFormat) diff --git a/SimplePage.cpp b/SimplePage.cpp index 89eaa48..01f4576 100644 --- a/SimplePage.cpp +++ b/SimplePage.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019-2023 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada ** ** This file is part of PageEdit. ** @@ -32,7 +32,5 @@ SimplePage::SimplePage(QWebEngineProfile* profile, QObject *parent) : QWebEnginePage(profile, parent) { setBackgroundColor(Utility::WebViewBackgroundColor()); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) || QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) setUrl(QUrl("about:blank")); -#endif } diff --git a/UIDictionary.cpp b/UIDictionary.cpp index 17d21e1..a69213a 100644 --- a/UIDictionary.cpp +++ b/UIDictionary.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019 Kevin B. Hendricks, Stratford, Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford, Ontario Canada ** Copyright (C) 2019 Doug Massay ** ** This file is part of PageEdit. @@ -57,11 +57,7 @@ QString UIDictionary::GetDictionaryPath() // finally look inside the installed Qt directories #ifndef Q_OS_MAC -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - dict_path = QLibraryInfo::location(QLibraryInfo::DataPath) + "/qtwebengine_dictionaries"; -#else dict_path = QLibraryInfo::path(QLibraryInfo::DataPath) + "/qtwebengine_dictionaries"; -#endif #else dict_path = QCoreApplication::applicationDirPath() + "/../Frameworks/QtWebEngineCore.framework/Resources/qtwebengine_dictionaries"; diff --git a/UILanguage.cpp b/UILanguage.cpp index e8e5555..4409042 100644 --- a/UILanguage.cpp +++ b/UILanguage.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019 Kevin B. Hendricks, Stratford, Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford, Ontario Canada ** Copyright (C) 2011 John Schember ** ** This file is part of PageEdit. @@ -43,12 +43,7 @@ QStringList UILanguage::GetPossibleTranslationPaths() possible_qm_locations.append(pageedit_share_root + "/translations/"); #endif -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - possible_qm_locations.append(QLibraryInfo::location(QLibraryInfo::TranslationsPath)); -#else possible_qm_locations.append(QLibraryInfo::path(QLibraryInfo::TranslationsPath)); -#endif - #ifdef Q_OS_MAC possible_qm_locations.append(QCoreApplication::applicationDirPath() + "/../translations"); diff --git a/Utility.cpp b/Utility.cpp index e3e9884..09ceaa4 100644 --- a/Utility.cpp +++ b/Utility.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,27 +63,16 @@ // This is the same read buffer size used by Java and Perl. #define BUFF_SIZE 8192 -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - #define QT_ENUM_KEEPEMPTYPARTS Qt::KeepEmptyParts -#else - #define QT_ENUM_KEEPEMPTYPARTS QString::KeepEmptyParts -#endif - // Subclass QMessageBox for our StdWarningDialog to make any Details Resizable class PageEditMessageBox: public QMessageBox { public: PageEditMessageBox(QWidget* parent) : QMessageBox(parent) { - setSizeGripEnabled(true); } private: virtual void resizeEvent(QResizeEvent * e) { QMessageBox::resizeEvent(e); - setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); - if (QWidget *textEdit = findChild()) { - textEdit->setMaximumHeight(QWIDGETSIZE_MAX); - } } }; @@ -104,11 +93,7 @@ static const QString DARK_STYLE = // Define the user preferences location to be used QString Utility::DefinePrefsDir() { -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - return QStandardPaths::writableLocation(QStandardPaths::DataLocation); -#else return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); -#endif } @@ -200,30 +185,26 @@ bool Utility::IsMixedCase(const QString &string) return false; } - +// Returns a substring from a specified QStringView as a real QString; +// the characters included are in the interval: // [ start_index, end_index > -QString Utility::Substring(int start_index, int end_index, const QStringRef &string) +QString Utility::Substring(int start_index, int end_index, const QStringView string) { - return string.mid(start_index, end_index - start_index).toString(); + return string.sliced(start_index, end_index - start_index).toString(); } - // [ start_index, end_index > QString Utility::Substring(int start_index, int end_index, const QString &string) { return string.mid(start_index, end_index - start_index); } -// Returns a substring of a specified string; +// Returns a substring of a specified string as a QStringView // the characters included are in the interval: // [ start_index, end_index > -QStringRef Utility::SubstringRef(int start_index, int end_index, const QString &string) +QStringView Utility::SubstringView(int start_index, int end_index, const QString &string) { -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - return string.midRef(start_index, end_index - start_index); -#else - return QStringRef(&string, start_index, end_index - start_index); -#endif + return QStringView(string).sliced(start_index, end_index - start_index); } // Replace the first occurrence of string "before" @@ -428,13 +409,10 @@ QString Utility::ReadUnicodeTextFile(const QString &fullfilepath) QTextStream in(&file); // Input should be UTF-8 -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif // This will automatically switch reading from // UTF-8 to UTF-16 if a BOM is detected in.setAutoDetectUnicode(true); - return ConvertLineEndings(in.readAll()); + return ConvertLineEndingsAndNormalize(in.readAll()); } @@ -442,6 +420,7 @@ QString Utility::ReadUnicodeTextFile(const QString &fullfilepath) // file; if the file exists, it is truncated void Utility::WriteUnicodeTextFile(const QString &text, const QString &fullfilepath) { + QString newtext = Utility::UseNFC(text); QFile file(fullfilepath); if (!file.open(QIODevice::WriteOnly | @@ -455,18 +434,15 @@ void Utility::WriteUnicodeTextFile(const QString &text, const QString &fullfilep QTextStream out(&file); // We ALWAYS output in UTF-8 -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - out.setCodec("UTF-8"); -#endif out << text; } // Converts Mac and Windows style line endings to Unix style // line endings that are expected throughout the Qt framework -QString Utility::ConvertLineEndings(const QString &text) +QString Utility::ConvertLineEndingsAndNormalize(const QString &text) { - QString newtext(text); + QString newtext = Utility::UseNFC(text); return newtext.replace("\x0D\x0A", "\x0A").replace("\x0D", "\x0A"); } @@ -534,6 +510,10 @@ QString Utility::URLEncodePath(const QString &path) // url encoding them QString newpath = DecodeXML(path); + // The epub spec says all paths must use Unicode Normalization Form C (NFC) + // So do NOT Use Utility::UseNFC which conditionalizes things + newpath = newpath.normalized(QString::NormalizationForm_C); + // then undo any existing url encoding newpath = URLDecodePath(newpath); @@ -541,11 +521,7 @@ QString Utility::URLEncodePath(const QString &path) QVector codepoints = newpath.toUcs4(); for (int i = 0; i < codepoints.size(); i++) { uint32_t cp = codepoints.at(i); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - QString s = QString::fromUcs4(&cp, 1); -#else QString s = QString::fromUcs4(reinterpret_cast(&cp), 1); -#endif if (NeedToPercentEncode(cp)) { QByteArray b = s.toUtf8(); for (int j = 0; j < b.size(); j++) { @@ -570,13 +546,17 @@ QString Utility::URLEncodePath(const QString &path) QString Utility::URLDecodePath(const QString &path) { - QString apath(path); - // some very poorly written software uses xml-escape on hrefs - // instead of properly url encoding them, so look for the - // the "&" character which should *not* exist if properly - // url encoded and if found try to xml decode them first - apath = DecodeXML(apath); - return QUrl::fromPercentEncoding(apath.toUtf8()); + QString apath(path); + // some very poorly written software uses xml-escape on hrefs + // instead of properly url encoding them, so look for the + // the "&" character which should *not* exist if properly + // url encoded and if found try to xml decode them first + apath = DecodeXML(apath); + QString newpath = QUrl::fromPercentEncoding(apath.toUtf8()); + // epub spec says all paths must use Normalization Form C (NFC) + // Do Not use Utility::UseNFC as it conditionalizes it + newpath = newpath.normalized(QString::NormalizationForm_C); + return newpath; } @@ -655,15 +635,10 @@ void Utility::DisplayStdWarningDialog(const QString &warning_message, const QStr // if the env var isn't set, it returns an empty string QString Utility::GetEnvironmentVar(const QString &variable_name) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // The only time this might fall down is on Linux when an // environment variable holds bytedata. Don't use this // utility function for retrieval if that's the case. return qEnvironmentVariable(variable_name.toUtf8().constData(), "").trimmed(); -#else - // This will typically only be used on older Qts on Linux - return QProcessEnvironment::systemEnvironment().value(variable_name, "").trimmed(); -#endif } @@ -847,8 +822,8 @@ QString Utility::relativePath(const QString & destination, const QString & start while (dest.endsWith(sep)) dest.chop(1); while (start.endsWith(sep)) start.chop(1); - QStringList dsegs = dest.split(sep, QT_ENUM_KEEPEMPTYPARTS); - QStringList ssegs = start.split(sep, QT_ENUM_KEEPEMPTYPARTS); + QStringList dsegs = dest.split(sep, Qt::KeepEmptyParts); + QStringList ssegs = start.split(sep, Qt::KeepEmptyParts); QStringList res; int i = 0; int nd = dsegs.size(); @@ -1093,3 +1068,15 @@ QImage Utility::RenderSvgToImage(const QString& filepath) return svgimage; } + +QString Utility::UseNFC(const QString& text) +{ + QString txt; + MainApplication *mainApplication = qobject_cast(qApp); + if (mainApplication->AlwaysUseNFC()) { + txt = text.normalized(QString::NormalizationForm_C); + } else { + txt = text; + } + return txt; +} diff --git a/Utility.h b/Utility.h index 381bbb8..dc82895 100644 --- a/Utility.h +++ b/Utility.h @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019-2023 Kevin B. Hendricks, Stratford, Ontario, Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford, Ontario, Canada ** Copyright (C) 2009-2011 Strahinja Markovic ** ** This file is part of PageEdit. @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include class QWidget; @@ -60,10 +60,10 @@ class Utility // For instance, "test" and "TEST" return false, "teSt" returns true. static bool IsMixedCase(const QString &string); - // Returns a substring of a specified QStringRef; + // Returns a substring of a QStringView as a real string // the characters included are in the interval: // [ start_index, end_index > - static QString Substring(int start_index, int end_index, const QStringRef &string); + static QString Substring(int start_index, int end_index, const QStringView string); // Returns a substring of a specified QString; // the characters included are in the interval: @@ -73,7 +73,7 @@ class Utility // Returns a substring of a specified string; // the characters included are in the interval: // [ start_index, end_index > - static QStringRef SubstringRef(int start_index, int end_index, const QString &string); + static QStringView SubstringView(int start_index, int end_index, const QString &string); // Replace the first occurrence of string "before" // with string "after" in string "string" @@ -112,7 +112,7 @@ class Utility // Converts Mac and Windows style line endings to Unix style // line endings that are expected throughout the Qt framework - static QString ConvertLineEndings(const QString &text); + static QString ConvertLineEndingsAndNormalize(const QString &text); // Decodes XML escaped string to normal text // & -> & ' -> ' " -> " < -> < > -> > @@ -213,6 +213,8 @@ class Utility static QString FixupSvgForRendering(const QString& data); static QImage RenderSvgToImage(const QString& filepath); + + static QString UseNFC(const QString& text); }; #endif // UTILITY_H diff --git a/WebPageEdit.cpp b/WebPageEdit.cpp index b03a685..25fbb21 100644 --- a/WebPageEdit.cpp +++ b/WebPageEdit.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019-2023 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada ** Copyright (C) 2020 Doug Massay ** ** This file is part of PageEdit. @@ -38,19 +38,7 @@ WebPageEdit::WebPageEdit(QWebEngineProfile *profile, QObject *parent) { setBackgroundColor(Utility::WebViewBackgroundColor(true)); - -#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) - #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - // Qt 5.14 seems to have broken setBackgroundColor completely - // Linux is the only one there now but this may be needed for all platforms - // in the future unless Qt is fixed - setHtml(BASIC_HTML.arg(backgroundColor().name())); - #endif -#else - #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) || QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) setUrl(QUrl("about:blank")); - #endif -#endif } // Because you can not delegate all links in QtWebEngine we must override @@ -81,12 +69,10 @@ bool WebPageEdit::acceptNavigationRequest(const QUrl & url, QWebEnginePage::Navi DBG qDebug() << "acceptNavigationRequest from scheme handler load" << url.toString(); return true; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) if (type == QWebEnginePage::NavigationTypeRedirect) { DBG qDebug() << "acceptNavigationRequest from scheme handler redirect" << url.toString(); return true; } -#endif qDebug() << " Unhandled acceptNavigationRequest with type: " << type; return true; } diff --git a/WebProfileMgr.cpp b/WebProfileMgr.cpp index 3fb3d39..7517ee8 100644 --- a/WebProfileMgr.cpp +++ b/WebProfileMgr.cpp @@ -76,20 +76,12 @@ void WebProfileMgr::InitializeDefaultSettings(QWebEngineSettings* web_settings) web_settings->setAttribute(QWebEngineSettings::AllowGeolocationOnInsecureOrigins, false); web_settings->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, false); web_settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) web_settings->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, false); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) web_settings->setUnknownUrlSchemePolicy(QWebEngineSettings::DisallowUnknownUrlSchemes); web_settings->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, true); web_settings->setAttribute(QWebEngineSettings::JavascriptCanPaste, false); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) web_settings->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, false); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) web_settings->setAttribute(QWebEngineSettings::PdfViewerEnabled, false); -#endif } @@ -98,18 +90,10 @@ WebProfileMgr::WebProfileMgr() m_URLint = new URLInterceptor(); // initialize the defaultProfile to be restrictive for security -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - QWebEngineSettings *web_settings = QWebEngineSettings::defaultSettings(); -#else QWebEngineSettings *web_settings = QWebEngineProfile::defaultProfile()->settings(); -#endif InitializeDefaultSettings(web_settings); // Use URLInterceptor for protection -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QWebEngineProfile::defaultProfile()->setUrlRequestInterceptor(m_URLint); -#else - QWebEngineProfile::defaultProfile()->setRequestInterceptor(m_URLint); -#endif // create the profile for Preview / Edit SettingsStore ss; @@ -118,9 +102,7 @@ WebProfileMgr::WebProfileMgr() m_preview_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); m_preview_profile->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); m_preview_profile->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) m_preview_profile->settings()->setAttribute(QWebEngineSettings::PdfViewerEnabled, true); -#endif m_preview_profile->settings()->setDefaultTextEncoding("UTF-8"); m_preview_profile->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, (ss.javascriptOn() == 1)); m_preview_profile->settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, (ss.javascriptOn() == 1)); @@ -135,11 +117,7 @@ WebProfileMgr::WebProfileMgr() } m_preview_profile->setPersistentStoragePath(localStorePath); // Use our URLInterceptor -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) m_preview_profile->setUrlRequestInterceptor(m_URLint); -#else - m_preview_profile->setRequestInterceptor(m_URLint); -#endif // create the profile for OneTime m_onetime_profile = new QWebEngineProfile(); @@ -147,15 +125,8 @@ WebProfileMgr::WebProfileMgr() m_onetime_profile->settings()->setDefaultTextEncoding("UTF-8"); m_onetime_profile->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); m_onetime_profile->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) m_onetime_profile->settings()->setAttribute(QWebEngineSettings::PdfViewerEnabled, true); -#endif // Use URLInterceptor for protection -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) m_onetime_profile->setUrlRequestInterceptor(m_URLint); -#else - m_onetime_profile->setRequestInterceptor(m_URLint); -#endif - } diff --git a/WebViewEdit.cpp b/WebViewEdit.cpp index 296e6bc..3e7a42c 100644 --- a/WebViewEdit.cpp +++ b/WebViewEdit.cpp @@ -1,6 +1,6 @@ /************************************************************************ ** -** Copyright (C) 2019-2023 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada ** ** This file is part of PageEdit. ** @@ -35,11 +35,7 @@ #include #include #include -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include -#else -#include -#endif #include #include "Utility.h" @@ -50,13 +46,6 @@ #include "WebPageEdit.h" #include "WebViewEdit.h" -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - #define QT_ENUM_SKIPEMPTYPARTS Qt::SkipEmptyParts -#else - #define QT_ENUM_SKIPEMPTYPARTS QString::SkipEmptyParts -#endif - - #define DBG if(0) const QString SET_CURSOR_JS2 = @@ -142,38 +131,21 @@ WebViewEdit::~WebViewEdit() void WebViewEdit::contextMenuEvent(QContextMenuEvent *event) { -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - const QWebEngineContextMenuData &data = page()->contextMenuData(); - Q_ASSERT(data.isValid()); -#else const QWebEngineContextMenuRequest* request = lastContextMenuRequest(); -#endif QWebEngineProfile *profile = page()->profile(); m_menu->clear(); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - if (data.isContentEditable()) { -#else if (request->isContentEditable()) { -#endif // Used for edit mode const QStringList &dictionaries = profile->spellCheckLanguages(); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - if (!data.misspelledWord().isEmpty()) { -#else if (!request->misspelledWord().isEmpty()) { -#endif QFont boldFont = m_menu->font(); boldFont.setBold(true); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - for (const QString &suggestion : data.spellCheckerSuggestions()) { -#else for (const QString &suggestion : request->spellCheckerSuggestions()) { -#endif QAction *action = m_menu->addAction(suggestion); action->setFont(boldFont); @@ -730,7 +702,7 @@ QList WebViewEdit::ConvertQWebPathToHierarchy(const QString & webp { // The location element hierarchy encoded in a string QString location_string = webpath; - QStringList elements = location_string.split(",", QT_ENUM_SKIPEMPTYPARTS); + QStringList elements = location_string.split(",", Qt::SkipEmptyParts); QList location; foreach(QString element, elements) { ElementIndex new_element; diff --git a/main.cpp b/main.cpp index 05eff3b..779ee77 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,7 @@ /************************************************************************ ** -** Copyright (C) 2019-2022 Kevin B. Hendricks, Stratford, Ontario, Canada -** Copyright (C) 2019-2022 Doug Massay +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford, Ontario, Canada +** Copyright (C) 2019-2024 Doug Massay ** ** This file is part of PageEdit. ** @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -117,36 +116,6 @@ static QIcon GetApplicationIcon() } #endif -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -void setupHighDPI() -{ - bool has_env_setting = false; - QStringList env_vars; - env_vars << "QT_ENABLE_HIGHDPI_SCALING" << "QT_SCALE_FACTOR_ROUNDING_POLICY" - << "QT_AUTO_SCREEN_SCALE_FACTOR" << "QT_SCALE_FACTOR" - << "QT_SCREEN_SCALE_FACTORS" << "QT_DEVICE_PIXEL_RATIO"; - foreach(QString v, env_vars) { - if (!Utility::GetEnvironmentVar(v).isEmpty()) { - has_env_setting = true; - break; - } - } - - SettingsStore ss; - int highdpi = ss.highDPI(); - if (highdpi == 1 || (highdpi == 0 && !has_env_setting)) { - // Turning on Automatic High DPI scaling - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); - } else if (highdpi == 2) { - // Turning off Automatic High DPI scaling - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, false); - foreach(QString v, env_vars) { - bool irrel = qunsetenv(v.toUtf8().constData()); - } - } -} -#endif - // The message handler installed to handle Qt messages void MessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) { @@ -188,11 +157,7 @@ void MessageHandler(QtMsgType type, const QMessageLogContext &context, const QSt QFile outFile(pageedit_log_file); outFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); QTextStream ts(&outFile); -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - ts << qt_log_entry << endl; -#else ts << qt_log_entry << Qt::endl; -#endif } } @@ -210,26 +175,6 @@ void update_ini_file_if_needed(const QString oldfile, const QString newfile) // Application entry point int main(int argc, char *argv[]) { -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - #if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) - QT_REQUIRE_VERSION(argc, argv, "5.9.0"); - #else - QT_REQUIRE_VERSION(argc, argv, "5.12.3"); - #endif -#endif - -#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) - // Unset platform theme plugins/styles environment variables immediately - // when forcing Sigil's own darkmode palette on Linux - if (!force_sigil_darkmode_palette.isEmpty() || - !force_pageedit_darkmode_palette.isEmpty()) { - QStringList env_vars = {"QT_QPA_PLATFORMTHEME", "QT_STYLE_OVERRIDE"}; - foreach(QString v, env_vars) { - bool irrel = qunsetenv(v.toUtf8().constData()); - Q_UNUSED(irrel); - } - } -#endif #ifndef QT_DEBUG qInstallMessageHandler(MessageHandler); @@ -241,19 +186,11 @@ int main(int argc, char *argv[]) QCoreApplication::setApplicationName("pageedit"); QCoreApplication::setApplicationVersion(QString(PAGEEDIT_VERSION)); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // Qt6 forced move to utf-8 settings values but Qt5 settings are broken for utf-8 codec // See QTBUG-40796 and QTBUG-54510 which never got fixed update_ini_file_if_needed(Utility::DefinePrefsDir() + "/" + PAGEEDIT_SETTINGS_FILE, Utility::DefinePrefsDir() + "/" + PAGEEDIT_V6_SETTINGS_FILE); -#endif -#ifndef Q_OS_MAC - #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - setupHighDPI(); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - #endif -#endif QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache); // enable disabling of gpu acceleration for QtWebEngine. @@ -270,6 +207,9 @@ int main(int argc, char *argv[]) qputenv("QTWEBENGINE_CHROMIUM_FLAGS", current_flags.toUtf8()); } + // disable thread unsafe use of broken PCRE2 JIT (version 10.43) in QRegularExpression + qputenv("QT_ENABLE_REGEXP_JIT","0"); + MainApplication app(argc, argv); #ifdef Q_OS_MAC @@ -282,8 +222,6 @@ int main(int argc, char *argv[]) AppEventFilter *filter = new AppEventFilter(&app); app.installEventFilter(filter); - QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf8")); - // set up for translations SettingsStore settings; @@ -315,63 +253,40 @@ int main(int argc, char *argv[]) } app.installTranslator(&pageeditTranslator); +#ifdef Q_OS_MAC + // QApplication::setStyle("macOS"); + QStyle* astyle = QStyleFactory::create("macOS"); + app.setStyle(astyle); +#endif // Q_OS_MAC + +#ifdef Q_OS_WIN32 + QStyle* astyle = QStyleFactory::create("fusion"); + app.setStyle(astyle); +#endif // Q_OS_WIN32 + +#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN32) // *nix + // QStyle* astyle = QStyleFactory::create("fusion"); + QStyle* astyle = app.style(); + app.setStyle(astyle); +#endif // *nix + #ifndef Q_OS_MAC - // Custom dark style/palette for Windows and Linux -#ifndef Q_OS_WIN32 - // Use platform themes/styles on Linux unless either Sigil or PageEdit's FORCE variable is set - if (!force_pageedit_darkmode_palette.isEmpty() || !force_sigil_darkmode_palette.isEmpty()) { - // Apply custom dark style - app.setStyle(new PEDarkStyle); -#if QT_VERSION == QT_VERSION_CHECK(5, 15, 0) - // Qt keeps breaking my custom dark theme. - // This was apparently only necessary for Qt5.15.0!! - app.setPalette(QApplication::style()->standardPalette()); -#endif - } -#else if (Utility::WindowsShouldUseDarkMode()) { // Apply custom dark style app.setStyle(new PEDarkStyle); app.setPalette(QApplication::style()->standardPalette()); } -#endif #endif - // Set ui font from preferences after dark theming - QFont f = QFont(QApplication::font()); -#ifdef Q_OS_WIN32 - if (f.family() == "MS Shell Dlg 2" && f.pointSize() == 8) { - // Microsoft's recommended UI defaults - f.setFamily("Segoe UI"); - f.setPointSize(9); - QApplication::setFont(f); - } -#elif defined(Q_OS_MAC) - // Just in case -#else - if (f.family() == "Sans Serif" && f.pointSize() == 9) { - f.setPointSize(10); - QApplication::setFont(f); - } -#endif - settings.setOriginalUIFont(f.toString()); - if (!settings.uiFont().isEmpty()) { - QFont font; - if (font.fromString(settings.uiFont())) - QApplication::setFont(font); - } -#ifndef Q_OS_MAC - // redo on a timer to ensure in all cases - if (!settings.uiFont().isEmpty()) { - QFont font; - if (font.fromString(settings.uiFont())) { - QTimer::singleShot(0, [=]() { - QApplication::setFont(font); - } ); - } - } -#endif - // End of UI font stuff + // it seems that any time there is stylesheet used, system dark-light palette + // changes are not propagated to widgets with stylesheets (See QTBUG-124268). + // This in turn prevents some widgets from properly geting repainted with the new + // dark or light theme palette (See paintEvent in BookBrowser.cpp for example.) + // Because our style changes are not palette dependent they should be + // properly propagated to all widgets including those with stylesheets + // This is how to tell Qt to do that. Perhaps any platforms need this as well. + app.setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + // Check for existing qt_styles.qss in Prefs dir and load it if present QString qt_stylesheet_path = Utility::DefinePrefsDir() + "/qt_styles.qss"; @@ -395,10 +310,8 @@ int main(int argc, char *argv[]) // application icons linuxicons #if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) app.setWindowIcon(GetApplicationIcon()); -#if QT_VERSION >= 0x050700 // Wayland needs this clarified in order to propery assign the icon app.setDesktopFileName(QStringLiteral("pageedit.desktop")); -#endif #endif // initialize our QWebEngineProfiles and URL Interceptor @@ -466,6 +379,50 @@ int main(int argc, char *argv[]) basemw->show(); #endif + // Set ui font from preferences + // This needs to happen as late as possible (before + // MainWindow) on Linux to work consistently. + + QFont f = QFont(QApplication::font()); + +#ifdef Q_OS_WIN32 + if (f.family() == "MS Shell Dlg 2" && f.pointSize() == 8) { + // Microsoft's recommended UI defaults + f.setFamily("Segoe UI"); + f.setPointSize(9); + QApplication::setFont(f); + } + +#elif defined(Q_OS_MAC) + // Just in case + +#else + if (f.family() == "Sans Serif" && f.pointSize() == 9) { + f.setPointSize(10); + QApplication::setFont(f); + } +#endif + + settings.setOriginalUIFont(f.toString()); + if (!settings.uiFont().isEmpty()) { + QFont font; + if (font.fromString(settings.uiFont())) + QApplication::setFont(font); + } + +#ifndef Q_OS_MAC + // redo on a timer to ensure in all cases + if (!settings.uiFont().isEmpty()) { + QFont font; + if (font.fromString(settings.uiFont())) { + QTimer::singleShot(0, [=]() { + QApplication::setFont(font); + } ); + } + } +#endif + // End of UI font stuff + MainWindow *widget = GetMainWindow(arguments); widget->show(); return app.exec(); diff --git a/pageedit_constants.h b/pageedit_constants.h index 8bf6a3d..eccbcf6 100644 --- a/pageedit_constants.h +++ b/pageedit_constants.h @@ -1,7 +1,7 @@ /************************************************************************ ** -** Copyright (C) 2019-2022 Kevin B. Hendricks, Stratford Ontario Canada -** Copyright (C) 2019-2022 Doug Massay +** Copyright (C) 2019-2024 Kevin B. Hendricks, Stratford Ontario Canada +** Copyright (C) 2019-2024 Doug Massay ** ** This file is part of PageEdit. ** @@ -26,6 +26,10 @@ class QString; +// QL1SV() Macro to handle renaming of QLatin1String to QLatin1StringView in Qt6.4+ +#include +#define QL1SV(t) QLatin1StringView(t) + // Workaround LTO issues with static initializers when initailized // from const qstrings from a different compilation unit #define PAGEEDIT_SETTINGS_FILE "pageedit.ini" diff --git a/webviewprinter.cpp b/webviewprinter.cpp index 4adee43..94514e8 100644 --- a/webviewprinter.cpp +++ b/webviewprinter.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021-2023 Doug Massay +** Copyright (C) 2021-2024 Doug Massay ** ** This file is part of PageEdit. ** @@ -107,12 +107,8 @@ void WebViewPrinter::printDocument(QPrinter *printer) QEventLoop loop; bool result; auto printCallback = [&](bool success) { result = success; loop.quit(); }; -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - m_view->page()->print(printer, std::move(printCallback)); -#else connect(m_view, &QWebEngineView::printFinished, std::move(printCallback)); m_view->print(printer); -#endif loop.exec(); if (!result) { DBG qDebug() << "Could not print document.";