diff --git a/CMakeLists.txt b/CMakeLists.txt index e86afb3..9109898 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "Required macOS version") endif() -project(AusweisApp2 VERSION 1.26.4 LANGUAGES ${LANGUAGES}) +project(AusweisApp2 VERSION 1.26.5 LANGUAGES ${LANGUAGES}) # Set TWEAK if not defined in PROJECT_VERSION above to # have a valid tweak version without propagating it diff --git a/Dockerfile b/Dockerfile index 932b382..ab32e67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG ALPINE_VERSION=3.17 +ARG ALPINE_VERSION=3.18 FROM alpine:$ALPINE_VERSION as builder # Install development stuff diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 79998b2..73dea88 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -84,13 +84,16 @@ endif() if (QT6) - # Workaround for QTBUG-94066 - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake") - include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") + if(QT_VERSION VERSION_LESS "6.4") + # Workaround for QTBUG-94066 + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake") + include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake") + endif() + FETCH_TARGET_LOCATION(openSslBackend "${Qt}::QTlsBackendOpenSSLPlugin") install(FILES ${openSslBackend} DESTINATION tls COMPONENT Runtime) list(APPEND LIBS ${openSslBackend}) @@ -247,6 +250,7 @@ foreach(entry ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/background_npa.png DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_background.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/foreground_${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_foreground.png) + install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/monochrome_${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_monochrome.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa.png) install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_SPLASH_SCREEN_ICON_NAME} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/drawable-${entry} COMPONENT Runtime RENAME splash_npa.png) endforeach() @@ -269,6 +273,8 @@ set(QML_ROOT_PATH [\"${RESOURCES_DIR}/qml\"]) set(ANDROID_ROOT_LOGGER "") configure_file(${PACKAGING_DIR}/android/fileprovider.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/fileprovider.xml COPYONLY) + configure_file(${PACKAGING_DIR}/android/full_backup_content.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/full_backup_content.xml COPYONLY) + configure_file(${PACKAGING_DIR}/android/data_extraction_rules.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/data_extraction_rules.xml COPYONLY) endif() set(ANDROID_SO_NAME libAusweisApp2_${CMAKE_ANDROID_ARCH_ABI}.so) diff --git a/cmake/Libraries.cmake b/cmake/Libraries.cmake index 6ece9e5..8e47744 100644 --- a/cmake/Libraries.cmake +++ b/cmake/Libraries.cmake @@ -49,11 +49,8 @@ endif() if(NOT INTEGRATED_SDK) - list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2) + list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2 QmlWorkerScript) - if(QT_VERSION VERSION_GREATER_EQUAL "5.14") - list(APPEND QT_COMPONENTS QmlWorkerScript) - endif() if(NOT DESKTOP AND NOT QT6) list(APPEND QT_COMPONENTS QuickShapes) endif() diff --git a/cmake/Messages.cmake b/cmake/Messages.cmake index 0a5e4ec..e3c6319 100644 --- a/cmake/Messages.cmake +++ b/cmake/Messages.cmake @@ -25,7 +25,6 @@ message(STATUS "ANDROID_BUILD_TOOLS_REVISION: ${ANDROID_BUILD_TOOLS_REVISION}") message(STATUS "ANDROID_NDK_REVISION: ${ANDROID_NDK_REVISION}") - message(STATUS "ANDROID_SDK_REVISION: ${ANDROID_SDK_REVISION}") endif() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 461c3b2..f2dfbe9 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -171,7 +171,11 @@ file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") - if(USE_SMARTEID AND NOT INTEGRATED_SDK) + if(INTEGRATED_SDK) + set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.aar") + file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) + file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") + elseif(USE_SMARTEID) set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.smarteid") file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE) file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}") diff --git a/cmake/Tools.Libraries.cmake b/cmake/Tools.Libraries.cmake index 7f37aa4..9237c91 100644 --- a/cmake/Tools.Libraries.cmake +++ b/cmake/Tools.Libraries.cmake @@ -2,7 +2,7 @@ # So this file will be called two times and the check needs to respect that # with a "VALIDATOR function" or "if(NOT VARIABLE)". -if(NOT QMLFORMAT) +if(NOT TARGET format.qml) set(QMLFORMAT_MIN_VERSION 6) function(qmlformat_validator validator_result binary) execute_process(COMMAND ${binary} --version OUTPUT_VARIABLE QMLFORMAT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/cmake/Tools.cmake b/cmake/Tools.cmake index 2ee0c3e..132bfdd 100644 --- a/cmake/Tools.cmake +++ b/cmake/Tools.cmake @@ -226,6 +226,33 @@ COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 320 -y 0 -o xhdpi/foreground_npa_preview.png COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 480 -y 0 -o xxhdpi/foreground_npa_preview.png COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 640 -y 0 -o xxxhdpi/foreground_npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 120 -y 0 -o ldpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 160 -y 0 -o mdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 240 -y 0 -o hdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 320 -y 0 -o xhdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 480 -y 0 -o xxhdpi/monochrome_npa.png + COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome.beta + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 120 -y 0 -o ldpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 160 -y 0 -o mdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 240 -y 0 -o hdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 320 -y 0 -o xhdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_beta.png + COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(npaicons.android.adaptive.monochrome.preview + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 120 -y 0 -o ldpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 160 -y 0 -o mdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 240 -y 0 -o hdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 320 -y 0 -o xhdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_preview.png + COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) add_custom_target(npaicons.android.launchimage @@ -313,6 +340,9 @@ npaicons.android.adaptive.foreground npaicons.android.adaptive.foreground.beta npaicons.android.adaptive.foreground.preview + npaicons.android.adaptive.monochrome + npaicons.android.adaptive.monochrome.beta + npaicons.android.adaptive.monochrome.preview npaicons.android.launchimage npaicons.android.launchimage.beta npaicons.android.launchimage.preview @@ -405,6 +435,33 @@ COMMAND ${PNGQUANT_CMD} xhdpi/foreground_npa_preview.png -- xhdpi/foreground_npa_preview.png COMMAND ${PNGQUANT_CMD} xxhdpi/foreground_npa_preview.png -- xxhdpi/foreground_npa_preview.png COMMAND ${PNGQUANT_CMD} xxxhdpi/foreground_npa_preview.png -- xxxhdpi/foreground_npa_preview.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa.png -- ldpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa.png -- mdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa.png -- hdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa.png -- xhdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa.png -- xxhdpi/monochrome_npa.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa.png -- xxxhdpi/monochrome_npa.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome.beta + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_beta.png -- ldpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_beta.png -- mdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_beta.png -- hdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_beta.png -- xhdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_beta.png -- xxhdpi/monochrome_npa_beta.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_beta.png -- xxxhdpi/monochrome_npa_beta.png + WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) + + add_custom_target(pngquant.android.adaptive.monochrome.preview + COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_preview.png -- ldpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_preview.png -- mdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_preview.png -- hdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_preview.png -- xhdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_preview.png -- xxhdpi/monochrome_npa_preview.png + COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_preview.png -- xxxhdpi/monochrome_npa_preview.png WORKING_DIRECTORY ${RESOURCES_DIR}/images/android) add_custom_target(pngquant.android.launchimage @@ -491,6 +548,9 @@ pngquant.android.adaptive.foreground pngquant.android.adaptive.foreground.beta pngquant.android.adaptive.foreground.preview + pngquant.android.adaptive.monochrome + pngquant.android.adaptive.monochrome.beta + pngquant.android.adaptive.monochrome.preview pngquant.android.launchimage pngquant.android.launchimage.beta pngquant.android.launchimage.preview diff --git a/cmake/android.toolchain.cmake b/cmake/android.toolchain.cmake index c21ea16..a509852 100644 --- a/cmake/android.toolchain.cmake +++ b/cmake/android.toolchain.cmake @@ -52,7 +52,6 @@ endif() READ_REVISION(ANDROID_NDK_REVISION ".*Revision = ([0-9|\\.]+)" "${CMAKE_ANDROID_NDK}/source.properties") -READ_REVISION(ANDROID_SDK_REVISION ".*Revision=([0-9|\\.]+)" "${ANDROID_SDK}/cmdline-tools/latest/source.properties;${ANDROID_SDK}/tools/source.properties") set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(CMAKE_SYSTEM_NAME Android) @@ -73,10 +72,6 @@ set(CMAKE_ANDROID_ARM_NEON ON) endif() -# Emulate NDK CMake-Variable as Qt 5.14 needs this (Multi-ABI) -set(ANDROID_ABI ${CMAKE_ANDROID_ARCH_ABI}) - - set(CMAKE_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH} CACHE STRING "android find search path root") set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/docs/failurecodes/failurecodes.rst b/docs/failurecodes/failurecodes.rst index 1a5fe20..1e880d5 100644 --- a/docs/failurecodes/failurecodes.rst +++ b/docs/failurecodes/failurecodes.rst @@ -157,21 +157,21 @@ the description of the service provider certificate. This condition is not met. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Pre_Verfication_No_Test_Environment** + - | **Pre_Verification_No_Test_Environment** | Occurs when the development mode of AusweisApp2 is activated and a genuine ID card is used. | **Possible Solutions:** Disable developer mode. The use of genuine ID cards is not permitted with activated developer mode, as this is only intended to facilitate the commissioning of services with test ID cards. - - | **Pre_Verfication_Invalid_Certificate_Chain** + - | **Pre_Verification_Invalid_Certificate_Chain** | A certificate chain was sent from the server that is unknown to AusweisApp2. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Pre_Verfication_Invalid_Certificate_Signature** + - | **Pre_Verification_Invalid_Certificate_Signature** | At least one signature in the certificate chain used by the server is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Pre_Verfication_Certificate_Expired** + - | **Pre_Verification_Certificate_Expired** | The certificate chain used by the server is currently not valid. | **Possible Solutions:** Make sure your system time is set correctly. If the problem persists, see :ref:`failure_code_inform_service_provider`. @@ -262,14 +262,14 @@ - | **Generic_Send_Receive_Paos_Unhandled** | A message was sent by the server in the PAOS communication during authentication, that - could be completely processed. + could not be completely processed. | **Possible Solutions:** :ref:`failure_code_contact_support`. - | **Generic_Send_Receive_Network_Error** | A network error has occurred in the PAOS communication during authentication. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. - - | **Generic_Send_Receive_Ssl_Error** + - | **Generic_Send_Receive_Tls_Error** | An authentication error occurred in the PAOS communication during the TLS handshake. The TLS certificate is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. @@ -318,7 +318,7 @@ did not behave as expected by the server. | **Possible Solutions:** :ref:`failure_code_contact_support`. - - | **Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply** + - | **Check_Refresh_Address_Fatal_Tls_Error_Before_Reply** | An error occurred during the TLS handshake when checking the return address after a successful authentication. The TLS certificate is incorrect. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. @@ -341,7 +341,7 @@ didn't work for checking the return address. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. - - | **Check_Refresh_Address_Fatal_Ssl_Error_After_Reply** + - | **Check_Refresh_Address_Fatal_Tls_Error_After_Reply** | When checking the return address after successful authentication, the TLS handshake could not be completed successfully. | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`. @@ -413,7 +413,7 @@ self-authentication. | **Possible Solutions:** :ref:`failure_code_inform_service_provider`. - - | **Generic_Provider_Communication_Ssl_Error** + - | **Generic_Provider_Communication_Tls_Error** | An error occurred during the TLS handshake when communicating with a service provider. The TLS certificate is incorrect. This only applies to services that are started from AusweisApp2, such as self-authentication. diff --git a/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po index f99714f..6f1d212 100644 --- a/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po +++ b/docs/failurecodes/locales/de/LC_MESSAGES/failurecodes.po @@ -360,7 +360,7 @@ "TLS-Zertifikate in der Beschreibung des Diensteanbieterzertifikats " "enthalten sind. Diese Bedingung ist nicht erfüllt." -msgid "**Pre_Verfication_No_Test_Environment**" +msgid "**Pre_Verification_No_Test_Environment**" msgstr "" msgid "" @@ -380,7 +380,7 @@ "dieser nur die Inbetriebnahme von Diensten mit Testausweisen erleichtern " "soll." -msgid "**Pre_Verfication_Invalid_Certificate_Chain**" +msgid "**Pre_Verification_Invalid_Certificate_Chain**" msgstr "" msgid "" @@ -390,7 +390,7 @@ "Vom Server wurde eine Zertifikatskette gesendet, die der AusweisApp2 " "nicht bekannt ist." -msgid "**Pre_Verfication_Invalid_Certificate_Signature**" +msgid "**Pre_Verification_Invalid_Certificate_Signature**" msgstr "" msgid "" @@ -400,7 +400,7 @@ "Mindestens eine Signatur in der vom Server genutzten Zertifikatskette ist" " nicht korrekt." -msgid "**Pre_Verfication_Certificate_Expired**" +msgid "**Pre_Verification_Certificate_Expired**" msgstr "" msgid "The certificate chain used by the server is currently not valid." @@ -639,7 +639,7 @@ msgid "" "A message was sent by the server in the PAOS communication during " -"authentication, that could be completely processed." +"authentication, that could not be completely processed." msgstr "" "Bei einer Authentisierung ist eine Nachricht vom Server in der PAOS-" "Kommunikation gesendet worden, die nicht vollständig verarbeitet werden " @@ -655,7 +655,7 @@ "Bei einer Authentisierung ist ein Netzwerkfehler in der PAOS-" "Kommunikation aufgetreten." -msgid "**Generic_Send_Receive_Ssl_Error**" +msgid "**Generic_Send_Receive_Tls_Error**" msgstr "" msgid "" @@ -766,7 +766,7 @@ "geliefert. Die AusweisApp2 oder die Karte hat sich nicht entsprechend der" " Erwartung des Servers verhalten." -msgid "**Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply**" +msgid "**Check_Refresh_Address_Fatal_Tls_Error_Before_Reply**" msgstr "" msgid "" @@ -815,7 +815,7 @@ " Proxyserver konfiguriert. Dieser hat für die Überprüfung der " "Rücksprungadresse nicht funktioniert." -msgid "**Check_Refresh_Address_Fatal_Ssl_Error_After_Reply**" +msgid "**Check_Refresh_Address_Fatal_Tls_Error_After_Reply**" msgstr "" msgid "" @@ -976,7 +976,7 @@ "aus der AusweisApp2 heraus gestartet werden, wie zum Beispiel die " "Selbstauskunft." -msgid "**Generic_Provider_Communication_Ssl_Error**" +msgid "**Generic_Provider_Communication_Tls_Error**" msgstr "" msgid "" diff --git a/docs/installation/README.de.rst b/docs/installation/README.de.rst index a1aea8e..ae07729 100644 --- a/docs/installation/README.de.rst +++ b/docs/installation/README.de.rst @@ -173,8 +173,8 @@ remindToClose - showSetupAssistant - + uiStartupModule + DEFAULT transportPinReminder customProxyType @@ -183,8 +183,6 @@ proxy.example.org customProxyPort 1337 - autoUpdateCheck - keylessPassword shuffleScreenKeyboard @@ -209,12 +207,11 @@ ======================= ======================= autoCloseWindow AUTOHIDE remindToClose REMINDTOCLOSE -showSetupAssistant ASSISTANT +uiStartupModule ASSISTANT transportPinReminder TRANSPORTPINREMINDER customProxyType CUSTOMPROXYTYPE customProxyPort CUSTOMPROXYPORT customProxyHost CUSTOMPROXYHOST -autoUpdateCheck UPDATECHECK keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD diff --git a/docs/installation/README.en.rst b/docs/installation/README.en.rst index 2f03af3..4ab2cd5 100644 --- a/docs/installation/README.en.rst +++ b/docs/installation/README.en.rst @@ -160,8 +160,8 @@ remindToClose - showSetupAssistant - + uiStartupModule + DEFAULT transportPinReminder customProxyType @@ -170,8 +170,6 @@ proxy.example.org customProxyPort 1337 - autoUpdateCheck - keylessPassword shuffleScreenKeyboard @@ -195,12 +193,11 @@ ======================= ======================= autoCloseWindow AUTOHIDE remindToClose REMINDTOCLOSE -showSetupAssistant ASSISTANT +uiStartupModule ASSISTANT transportPinReminder TRANSPORTPINREMINDER customProxyType CUSTOMPROXYTYPE customProxyPort CUSTOMPROXYPORT customProxyHost CUSTOMPROXYHOST -autoUpdateCheck UPDATECHECK keylessPassword ONSCREENKEYBOARD shuffleScreenKeyboard SHUFFLESCREENKEYBOARD visualPrivacy SECURESCREENKEYBOARD @@ -251,7 +248,7 @@ Broadcast on UDP port 24727 in the local subnet have to be receivable by the AusweisApp2 to use the "Smartphone as Card Reader" functionality. -It may be necessary to deactive AP isolation on your router. +It may be necessary to deactivate AP isolation on your router. .. _communicationmodel_en: .. figure:: CommunicationModel_en.pdf diff --git a/docs/releasenotes/1.26.5.rst b/docs/releasenotes/1.26.5.rst new file mode 100644 index 0000000..450f414 --- /dev/null +++ b/docs/releasenotes/1.26.5.rst @@ -0,0 +1,36 @@ +AusweisApp2 1.26.5 +^^^^^^^^^^^^^^^^^^ + +**Releasedatum:** 25. Juli 2023 + + +Anwender +"""""""" +- Überarbeitung des Kopplungsprozesses der Funktion Smartphone als Kartenleser. + Beide an der Kopplung beteiligten Geräte müssen auf Version 1.26.5 aktualisiert werden. + Versionen kleiner als 1.26.5 lassen sich nicht mit einer AusweisApp2 1.26.5 koppeln. + +- Die Anzeige des Fortschritts erfolgt jetzt auch auf einem Smartphone als Kartenleser. + +- Der Tastaturmodus auf einem Smartphone als Kartenleser ist jetzt standardmäßig aktiviert. + +- Bei Nutzung des Tastaturmodus auf einem Smartphone als Kartenleser kann in den Einstellungen eine + erneute Anzeige der Berechtigungen aktiviert werden. + +- Ergänzung eines monochromen Icons unter Android. + +- Berücksichtigung von Command + W unter macOS. + +- Entfernung der Updatefunktion auf macOS zugunsten des Mac App Store. + +- Kleinere Fehlerbehebungen und Optimierungen. + + +Entwickler +"""""""""" +- Die Dokumentation für die Installation in Firmennetzwerken unter macOS für die Einstellung zum + Einrichtungsassistenten wurde korrigiert. + +- Optimierung der Größe des Android SDK. + +- Aktualisierung von OpenSSL auf die Version 3.0.9. diff --git a/docs/releasenotes/announce.rst b/docs/releasenotes/announce.rst index 13d2566..f8b914e 100644 --- a/docs/releasenotes/announce.rst +++ b/docs/releasenotes/announce.rst @@ -5,6 +5,8 @@ folgender Systeme und Funktionen eingestellt. - macOS Catalina 10.15 +- Android 7 +- iOS 13 - Online-Hilfe - PDF-Export-Funktion der Selbstauskunft diff --git a/docs/releasenotes/appcast.rst b/docs/releasenotes/appcast.rst index 682bc05..5aee357 100644 --- a/docs/releasenotes/appcast.rst +++ b/docs/releasenotes/appcast.rst @@ -4,6 +4,7 @@ .. toctree:: :maxdepth: 1 + 1.26.5 1.26.4 1.26.3 1.26.2 diff --git a/docs/releasenotes/issues.rst b/docs/releasenotes/issues.rst index 0ca9b1b..9f6d822 100644 --- a/docs/releasenotes/issues.rst +++ b/docs/releasenotes/issues.rst @@ -38,11 +38,6 @@ - Die visuelle Hervorhebung des aktiven Elements wird an einigen Stellen fälschlicherwiese auch aktiviert, wenn die Maus benutzt wurde. -- Unter macOS werden im System hinterlegte Proxy-Server nicht erkannt und - damit auch nicht automatisch verwendet. Um manuell einen Proxy-Server in - der AusweisApp2 zu hinterlegen beachten Sie die Anleitung zur Installation - in Firmennetzwerken. - Android / iOS """"""""""""" diff --git a/docs/releasenotes/support.rst b/docs/releasenotes/support.rst index 6a5f4bf..88faee3 100644 --- a/docs/releasenotes/support.rst +++ b/docs/releasenotes/support.rst @@ -54,13 +54,13 @@ Im Rahmen der Qualitätssicherung werden die folgenden Browserversionen getestet. -- Chrome 112 +- Chrome 115 -- Firefox 112 +- Firefox 115 -- Safari 16.4 (macOS) +- Safari 16.5 (macOS) -- Edge 112 +- Edge 115 @@ -118,13 +118,13 @@ Anbieter umgesetzten Aktivierung. Daher empfehlen wir einen der folgenden Browser zu verwenden. -- Chrome 112 (iOS/Android) +- Chrome 115 (iOS/Android) -- Firefox 112 (iOS/Android) +- Firefox 115 (iOS/Android) -- Samsung Internet 20 (Android) +- Samsung Internet 22 (Android) -- Safari 16.4 (iOS) +- Safari 16.5 (iOS) Kartenleser diff --git a/docs/releasenotes/versions.rst b/docs/releasenotes/versions.rst index 67040af..2eeb000 100644 --- a/docs/releasenotes/versions.rst +++ b/docs/releasenotes/versions.rst @@ -6,6 +6,7 @@ .. toctree:: :maxdepth: 1 + 1.26.5 1.26.4 1.26.3 1.26.2 diff --git a/docs/sdk/messages.rst b/docs/sdk/messages.rst index 8187f07..d091862 100644 --- a/docs/sdk/messages.rst +++ b/docs/sdk/messages.rst @@ -810,6 +810,8 @@ to unblock the PIN. - **deactivated**: True if eID function is deactivated, otherwise false. + The scan dialog on iOS won't be closed if this is True. You need to + send :ref:`interrupt` yourself to show an error message. - **retryCounter**: Count of possible retries for the PIN. If you enter a PIN with command :ref:`set_pin` it will be decreased if PIN was incorrect. diff --git a/docs/sdk/workflow.rst b/docs/sdk/workflow.rst index b5cc878..a55a977 100644 --- a/docs/sdk/workflow.rst +++ b/docs/sdk/workflow.rst @@ -24,7 +24,7 @@ .. code-block:: json - {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/DEMO"} + {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/AusweisAuskunft/WebServiceRequesterServlet"} {"msg": "AUTH"} diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 4af45b2..77505ba 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -109,11 +109,7 @@ endif() ################################## Versions -set(QT 6.4.1) -set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09) - -set(OPENSSL 3.0.8) -set(OPENSSL_HASH 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e) +include(Versions.cmake) ################################## Files set(QT_FILE qt-everywhere-src-${QT}.tar.xz) diff --git a/libs/Versions.cmake b/libs/Versions.cmake new file mode 100644 index 0000000..56bc6c0 --- /dev/null +++ b/libs/Versions.cmake @@ -0,0 +1,5 @@ +set(QT 6.4.1) +set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09) + +set(OPENSSL 3.0.9) +set(OPENSSL_HASH eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90) diff --git a/libs/patch.cmake.in b/libs/patch.cmake.in index 6f5ded1..adec3a6 100644 --- a/libs/patch.cmake.in +++ b/libs/patch.cmake.in @@ -15,11 +15,11 @@ function(PATCH_SOURCES _component) set(PATCHES_DIR @PROJECT_SOURCE_DIR@/patches) - file(GLOB PATCHES "${PATCHES_DIR}/${_component}-*.patch") + file(GLOB PATCHES "${PATCHES_DIR}/${_component}*.patch") PATCH_SOURCES_EXECUTE("${PATCHES}") if("@CMAKE_BUILD_TYPE@" STREQUAL "DEBUG") - file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}-*.patch") + file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}*.patch") PATCH_SOURCES_EXECUTE("${PATCHES_DEBUG}") endif() endfunction() diff --git a/libs/patches/openssl-0001-Adjust-iOS-target.patch b/libs/patches/openssl-0001-Adjust-iOS-target.patch index c2345ef..6f9fcdc 100644 --- a/libs/patches/openssl-0001-Adjust-iOS-target.patch +++ b/libs/patches/openssl-0001-Adjust-iOS-target.patch @@ -1,4 +1,4 @@ -From a16972bcfd33b694fd27d19e85754be74daa4430 Mon Sep 17 00:00:00 2001 +From c97e9531a9da0ad5ae3bfb7cec90b03475a58a76 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Fri, 12 Feb 2021 13:15:00 +0100 Subject: Adjust iOS target @@ -8,7 +8,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git x/Configurations/15-ios.conf y/Configurations/15-ios.conf -index 54d37f63f4..a4ade8d209 100644 +index 54d37f63f4..7e411b2e3a 100644 --- x/Configurations/15-ios.conf +++ y/Configurations/15-ios.conf @@ -25,7 +25,7 @@ my %targets = ( @@ -20,5 +20,3 @@ bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", asm_arch => 'aarch64', perlasm_scheme => "ios64", --- -2.35.1 diff --git a/libs/patches/openssl-0002-android-shlib_variant.patch b/libs/patches/openssl-0002-android-shlib_variant.patch index 24f251f..d562c10 100644 --- a/libs/patches/openssl-0002-android-shlib_variant.patch +++ b/libs/patches/openssl-0002-android-shlib_variant.patch @@ -1,4 +1,4 @@ -From 8e011194bf8b4e4275f51f76b75a1b22e45e9564 Mon Sep 17 00:00:00 2001 +From 8353ce61f188109953e327b4bddf65c95e4baf92 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Tue, 19 Jan 2021 17:07:51 +0100 Subject: android shlib_variant @@ -41,6 +41,3 @@ }, #################################################################### --- -2.35.1 - diff --git a/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch b/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch new file mode 100644 index 0000000..914498e --- /dev/null +++ b/libs/patches/openssl-0003-Do-not-ignore-empty-associated-data-with-AES-SIV-mod.patch @@ -0,0 +1,55 @@ +From 9faa80071777b8a0b9eca1ab59bf69adb4621d9f Mon Sep 17 00:00:00 2001 +From: Tomas Mraz +Date: Tue, 4 Jul 2023 17:30:35 +0200 +Subject: Do not ignore empty associated data with AES-SIV mode + +The AES-SIV mode allows for multiple associated data items +authenticated separately with any of these being 0 length. + +The provided implementation ignores such empty associated data +which is incorrect in regards to the RFC 5297 and is also +a security issue because such empty associated data then become +unauthenticated if an application expects to authenticate them. + +Fixes CVE-2023-2975 + +Reviewed-by: Matt Caswell +Reviewed-by: Paul Dale +(Merged from https://github.com/openssl/openssl/pull/21384) + +(cherry picked from commit c426c281cfc23ab182f7d7d7a35229e7db1494d9) +(cherry picked from commit 00e2f5eea29994d19293ec4e8c8775ba73678598) +--- + .../implementations/ciphers/cipher_aes_siv.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git x/providers/implementations/ciphers/cipher_aes_siv.c y/providers/implementations/ciphers/cipher_aes_siv.c +index 45010b90db..b396c8651a 100644 +--- x/providers/implementations/ciphers/cipher_aes_siv.c ++++ y/providers/implementations/ciphers/cipher_aes_siv.c +@@ -120,14 +120,18 @@ static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, + if (!ossl_prov_is_running()) + return 0; + +- if (inl == 0) { +- *outl = 0; +- return 1; +- } ++ /* Ignore just empty encryption/decryption call and not AAD. */ ++ if (out != NULL) { ++ if (inl == 0) { ++ if (outl != NULL) ++ *outl = 0; ++ return 1; ++ } + +- if (outsize < inl) { +- ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); +- return 0; ++ if (outsize < inl) { ++ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); ++ return 0; ++ } + } + + if (ctx->hw->cipher(ctx, out, in, inl) <= 0) diff --git a/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch b/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch new file mode 100644 index 0000000..4582d53 --- /dev/null +++ b/libs/patches/openssl-0004-Fix-DH_check-excessive-time-with-over-sized-modulus.patch @@ -0,0 +1,72 @@ +From c012334ed713416cc30d6b2ff4dbeca97d1503c3 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Thu, 6 Jul 2023 16:36:35 +0100 +Subject: Fix DH_check() excessive time with over sized modulus + +The DH_check() function checks numerous aspects of the key or parameters +that have been supplied. Some of those checks use the supplied modulus +value even if it is excessively large. + +There is already a maximum DH modulus size (10,000 bits) over which +OpenSSL will not generate or derive keys. DH_check() will however still +perform various tests for validity on such a large modulus. We introduce a +new maximum (32,768) over which DH_check() will just fail. + +An application that calls DH_check() and supplies a key or parameters +obtained from an untrusted source could be vulnerable to a Denial of +Service attack. + +The function DH_check() is itself called by a number of other OpenSSL +functions. An application calling any of those other functions may +similarly be affected. The other functions affected by this are +DH_check_ex() and EVP_PKEY_param_check(). + +CVE-2023-3446 + +Reviewed-by: Paul Dale +Reviewed-by: Tom Cosgrove +Reviewed-by: Bernd Edlinger +Reviewed-by: Tomas Mraz +(Merged from https://github.com/openssl/openssl/pull/21451) + +(cherry picked from commit 9e0094e2aa1b3428a12d5095132f133c078d3c3d) +(cherry picked from commit 1fa20cf2f506113c761777127a38bce5068740eb) +--- + crypto/dh/dh_check.c | 6 ++++++ + include/openssl/dh.h | 6 +++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git x/crypto/dh/dh_check.c y/crypto/dh/dh_check.c +index 0b391910d6..84a926998e 100644 +--- x/crypto/dh/dh_check.c ++++ y/crypto/dh/dh_check.c +@@ -152,6 +152,12 @@ int DH_check(const DH *dh, int *ret) + if (nid != NID_undef) + return 1; + ++ /* Don't do any checks at all with an excessively large modulus */ ++ if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { ++ ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); ++ return 0; ++ } ++ + if (!DH_check_params(dh, ret)) + return 0; + +diff --git x/include/openssl/dh.h y/include/openssl/dh.h +index b97871eca7..36420f51d8 100644 +--- x/include/openssl/dh.h ++++ y/include/openssl/dh.h +@@ -89,7 +89,11 @@ int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **ukm); + # include + + # ifndef OPENSSL_DH_MAX_MODULUS_BITS +-# define OPENSSL_DH_MAX_MODULUS_BITS 10000 ++# define OPENSSL_DH_MAX_MODULUS_BITS 10000 ++# endif ++ ++# ifndef OPENSSL_DH_CHECK_MAX_MODULUS_BITS ++# define OPENSSL_DH_CHECK_MAX_MODULUS_BITS 32768 + # endif + + # define OPENSSL_DH_FIPS_MIN_MODULUS_BITS 1024 diff --git a/libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch b/libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch deleted file mode 100644 index 23f53c9..0000000 --- a/libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch +++ /dev/null @@ -1,43 +0,0 @@ -From ca3a694221c62131a384cbabd7dc34f91add9eae Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= -Date: Mon, 25 Jul 2022 17:08:54 +0200 -Subject: Revert "Fix usage of logging category on Android" - -This reverts commit 87d8ee755bfdef8e72a122789c2e3ed382881a12. - -Change-Id: If19a9d615e01d61c79955cda4789ba1646520ee1 ---- - src/corelib/global/qlogging.cpp | 9 +-------- - 1 file changed, 1 insertion(+), 8 deletions(-) - -diff --git x/qtbase/src/corelib/global/qlogging.cpp y/qtbase/src/corelib/global/qlogging.cpp -index 9ac70b3340..737a91dc6e 100644 ---- x/qtbase/src/corelib/global/qlogging.cpp -+++ y/qtbase/src/corelib/global/qlogging.cpp -@@ -1450,10 +1450,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con - } else if (token == messageTokenC) { - message.append(str); - } else if (token == categoryTokenC) { --#ifndef Q_OS_ANDROID -- // Don't add the category to the message on Android - message.append(QLatin1StringView(context.category)); --#endif - } else if (token == typeTokenC) { - switch (type) { - case QtDebugMsg: message.append("debug"_L1); break; -@@ -1701,11 +1698,7 @@ static bool android_default_message_handler(QtMsgType type, - break; - }; - -- // If application name is a tag ensure it has no spaces -- // If a category is defined, use it as an Android logging tag -- __android_log_print(priority, isDefaultCategory(context.category) ? -- qPrintable(QCoreApplication::applicationName().replace(u' ', u'_')) : context.category, -- "%s\n", qPrintable(formattedMessage)); -+ __android_log_print(priority, qPrintable(QCoreApplication::applicationName()), "%s\n", qPrintable(formattedMessage)); - - return true; // Prevent further output to stderr - } --- -2.38.1 - diff --git a/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch b/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch deleted file mode 100644 index 86f8eb0..0000000 --- a/libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch +++ /dev/null @@ -1,66 +0,0 @@ -From c6818d0c25f067bc13198b9aa2ca82776a40ad3b Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Wed, 14 Dec 2022 11:52:12 +0100 -Subject: Revert "Android: Fix QSettings when using content URL" - -This reverts commit 140ca89a3c2b8d78889d27217f977cd4de10041b. ---- - src/corelib/io/qsettings.cpp | 21 +++------------------ - 1 file changed, 3 insertions(+), 18 deletions(-) - -diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp -index 60622e3aaa..a999aa6996 100644 ---- x/qtbase/src/corelib/io/qsettings.cpp -+++ y/qtbase/src/corelib/io/qsettings.cpp -@@ -48,9 +48,8 @@ - #define Q_XDG_PLATFORM - #endif - --#if !defined(QT_NO_STANDARDPATHS) \ -- && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID)) --# define QSETTINGS_USE_QSTANDARDPATHS -+#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT)) -+#define QSETTINGS_USE_QSTANDARDPATHS - #endif - - // ************************************************************************ -@@ -1332,15 +1331,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - } - - #ifndef QT_BOOTSTRAPPED -- QString lockFileName = confFile->name + ".lock"_L1; -- --# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS) -- // On android and if it is a content URL put the lock file in a -- // writable location to prevent permissions issues and invalid paths. -- if (confFile->name.startsWith("content:"_L1)) -- lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) -- + QFileInfo(lockFileName).fileName(); --# endif - /* - Use a lockfile in order to protect us against other QSettings instances - trying to write the same settings at the same time. -@@ -1348,7 +1338,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - We only need to lock if we are actually writing as only concurrent writes are a problem. - Concurrent read and write are not a problem because the writing operation is atomic. - */ -- QLockFile lockFile(lockFileName); -+ QLockFile lockFile(confFile->name + ".lock"_L1); - if (!readOnly && !lockFile.lock() && atomicSyncOnly) { - setStatus(QSettings::AccessError); - return; -@@ -1426,11 +1416,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) - #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile) - QSaveFile sf(confFile->name); - sf.setDirectWriteFallback(!atomicSyncOnly); --# ifdef Q_OS_ANDROID -- // QSaveFile requires direct write when using content scheme URL in Android -- if (confFile->name.startsWith("content:"_L1)) -- sf.setDirectWriteFallback(true); --# endif - #else - QFile sf(confFile->name); - #endif --- -2.39.0 - diff --git a/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch b/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch deleted file mode 100644 index ea17cb1..0000000 --- a/libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 97d4394f85f120724a9cbe518ba2233b87e48c68 Mon Sep 17 00:00:00 2001 -From: Julian Greilich -Date: Wed, 4 Jan 2023 16:32:28 +0100 -Subject: Android A11Y: Only access the main thread when it is not blocked - -When the qtMainLoopThread calls QSGThreadedRenderLoop::polishAndSync(), -it waits for the QSGRenderThread. - -In the QSGRenderThread, QAndroidPlatformOpenGLWindow::eglSurface() -calls QtAndroid::createSurface() and waits for the "android main -thread" to return a valid surface. -When the "android main thread" now calls "runInObjectContext" (e.g. by -calling QtAndroidAccessibility::childIdListForAccessibleObject()) it -waits for the qtMainLoopThread and the program is stuck in a deadlock. - -To prevent this, we protect all BlockedQueuedConnection from the -"android main thread" to the qtMainLoopThread by acquiring the -AndroidDeadlockProtector. -When QAndroidPlatformOpenGLWindow::eglSurface() already acquired the -AndroidDeadlockProtector we abort the current A11y call with an emtpy -or default value. - -Note: b8a95275440b8a143ee648466fd8b5401ee1e839 already tried to fix -this by checking "getSurfaceCount() != 0", but there are situations, -where a new surface is being created while an old surface is still -present. - -Task-number: QTBUG-105958 -Pick-to: 6.5 6.4 6.3 6.2 5.15 -Change-Id: Ie40e8654c99aace9e69b0b8412952fa22c89f071 -Reviewed-by: Assam Boudjelthia -(cherry picked from commit b832a5ac72c6015b6509d60b75b2ce5d5e570800) ---- - .../platforms/android/androidjniaccessibility.cpp | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp -index 3067cb178a..8990289dc4 100644 ---- x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp -+++ y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp -@@ -1,6 +1,7 @@ - // Copyright (C) 2021 The Qt Company Ltd. - // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -+#include "androiddeadlockprotector.h" - #include "androidjniaccessibility.h" - #include "androidjnimain.h" - #include "qandroidplatformintegration.h" -@@ -61,6 +62,14 @@ namespace QtAndroidAccessibility - template - void runInObjectContext(QObject *context, Func &&func, Ret *retVal) - { -+ AndroidDeadlockProtector protector; -+ if (!protector.acquire()) { -+ __android_log_print(ANDROID_LOG_WARN, m_qtTag, -+ "Could not run accessibility call in object context, accessing " -+ "main thread could lead to deadlock"); -+ return; -+ } -+ - if (!QtAndroid::blockEventLoopsWhenSuspended() - || QGuiApplication::applicationState() != Qt::ApplicationSuspended) { - QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal); --- -2.39.0 - diff --git a/libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch b/libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch deleted file mode 100644 index 29a7037..0000000 --- a/libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch +++ /dev/null @@ -1,49 +0,0 @@ -From bc1b984a5b1a53c0c9eccc44763aaf0c94294fb7 Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Mon, 9 Jan 2023 06:54:53 +0100 -Subject: Fix warning in q20algorithm.h when xcodebuild is used - -q20algorithm.h:150:20: error: unused function template 'operator()' -q20algorithm.h:163:20: error: unused function template 'operator()' -q20algorithm.h:176:20: error: unused function template 'operator()' - -Fixes: QTBUG-109874 -Change-Id: If5ccbfffd0b6a53f73f221b45033dab7e4775d89 ---- - src/corelib/global/q20algorithm.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git x/qtbase/src/corelib/global/q20algorithm.h y/qtbase/src/corelib/global/q20algorithm.h -index 69dc2d2446..88e8ab08d2 100644 ---- x/qtbase/src/corelib/global/q20algorithm.h -+++ y/qtbase/src/corelib/global/q20algorithm.h -@@ -147,7 +147,7 @@ using std::ranges::none_of; - [[maybe_unused]] inline constexpr struct { // Niebloid - template -- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const -+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const - { - while (first != last) { - if (std::invoke(pred, std::invoke(proj, *first))) -@@ -160,7 +160,7 @@ using std::ranges::none_of; - [[maybe_unused]] inline constexpr struct { // Niebloid - template -- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const -+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const - { - while (first != last) { - if (!std::invoke(pred, std::invoke(proj, *first))) -@@ -173,7 +173,7 @@ using std::ranges::none_of; - [[maybe_unused]] inline constexpr struct { // Niebloid - template -- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const -+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const - { - while (first != last) { - if (std::invoke(pred, std::invoke(proj, *first))) --- -2.39.0 - diff --git a/libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch b/libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch deleted file mode 100644 index 737430d..0000000 --- a/libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch +++ /dev/null @@ -1,130 +0,0 @@ -From d5555d3c62cbc8c061de0ae9e1f0c20374b4004e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= -Date: Mon, 12 Dec 2022 14:33:41 +0100 -Subject: macOS: Use NSStatusItem.menu to manage system tray menu - -Using [NSStatusItem popUpStatusItemMenu:] to manually show the menu is -deprecated, and was causing various issues when right clicking the menu, -such as not unhighlighting the menu item when dismissing the menu, or -worse, not quitting the application if a 'Quit' item was triggered from -a right click. - -The reason we were using popUpStatusItemMenu instead of the menu -property of NSStatusItem was that the latter prevented us from seeing -the action message of the NSStatusItem button, which we used to emit -the system tray's activated signal, but this can be solved by listing -for the menu's tracking state starting. - -Fixes: QTBUG-103515 -Pick-to: 6.4 -Change-Id: I686550ebac7d94d8d11b2e3c49ed16a8240cb214 -Reviewed-by: Volker Hilsheimer -(cherry picked from commit da754d5b6589c9877f0325edb3da5cbc64d966c7) ---- - .../platforms/cocoa/qcocoasystemtrayicon.h | 3 +- - .../platforms/cocoa/qcocoasystemtrayicon.mm | 36 ++++++++++++------- - 2 files changed, 24 insertions(+), 15 deletions(-) - -diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -index 414560e1192..75c33cc5a3f 100644 ---- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -+++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h -@@ -45,12 +45,11 @@ public: - bool isSystemTrayAvailable() const override; - bool supportsMessages() const override; - -- void statusItemClicked(); -+ void emitActivated(); - - private: - NSStatusItem *m_statusItem = nullptr; - QStatusItemDelegate *m_delegate = nullptr; -- QCocoaMenu *m_menu = nullptr; - }; - - QT_END_NAMESPACE -diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -index c004cd69b57..2f7f73b4813 100644 ---- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -+++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm -@@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init() - - m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this]; - -+ // In case the status item does not have a menu assigned to it -+ // we fall back to the item's button to detect activation. - m_statusItem.button.target = m_delegate; - m_statusItem.button.action = @selector(statusItemClicked); - [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown]; -@@ -81,8 +83,6 @@ void QCocoaSystemTrayIcon::cleanup() - - [m_delegate release]; - m_delegate = nil; -- -- m_menu = nullptr; - } - - QRect QCocoaSystemTrayIcon::geometry() const -@@ -178,12 +178,20 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) - - void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu) - { -- // We don't set the menu property of the NSStatusItem here, -- // as that would prevent us from receiving the action for the -- // click, and we wouldn't be able to emit the activated signal. -- // Instead we show the menu manually when the status item is -- // clicked. -- m_menu = static_cast(menu); -+ m_statusItem.menu = menu ? static_cast(menu)->nsMenu() : nil; -+ -+ if (m_statusItem.menu) { -+ // When a menu is assigned, NSStatusBarButtonCell will intercept the mouse -+ // down to pop up the menu, and we never see the NSStatusBarButton action. -+ // To ensure we emit the 'activated' signal in both cases we detect when -+ // menu starts tracking, which happens before the menu delegate is sent -+ // the menuWillOpen callback we use to emit aboutToShow for the menu. -+ [NSNotificationCenter.defaultCenter addObserver:m_delegate -+ selector:@selector(statusItemMenuBeganTracking:) -+ name:NSMenuDidBeginTrackingNotification -+ object:m_statusItem.menu -+ ]; -+ } - } - - void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip) -@@ -226,7 +234,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess - } - } - --void QCocoaSystemTrayIcon::statusItemClicked() -+void QCocoaSystemTrayIcon::emitActivated() - { - auto *mouseEvent = NSApp.currentEvent; - -@@ -245,9 +253,6 @@ void QCocoaSystemTrayIcon::statusItemClicked() - } - - emit activated(activationReason); -- -- if (NSMenu *menu = m_menu ? m_menu->nsMenu() : nil) -- QT_IGNORE_DEPRECATIONS([m_statusItem popUpStatusItemMenu:menu]); - } - - QT_END_NAMESPACE -@@ -270,7 +275,12 @@ QT_END_NAMESPACE - - - (void)statusItemClicked - { -- self.platformSystemTray->statusItemClicked(); -+ self.platformSystemTray->emitActivated(); -+} -+ -+- (void)statusItemMenuBeganTracking:(NSNotification*)notification -+{ -+ self.platformSystemTray->emitActivated(); - } - - - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification --- -2.39.2 - diff --git a/libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch b/libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch deleted file mode 100644 index b5c1ff9..0000000 --- a/libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch +++ /dev/null @@ -1,44 +0,0 @@ -From e28710e3f175663b030c00d75ee899a9a7b0cdd2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= -Date: Thu, 15 Dec 2022 16:40:34 +0100 -Subject: iOS: Don't assume screens will not be connected before - QIOSIntegration - -When an external screen is connected to an iPad, and the application is -starting up on that screen, we will get a connection notification about -that screen as part of the initial bootstrap of UIApplicationMain, -before we call the user's main(). - -Since we initialize and add all available screen on QIOSIntegration -creation, we can just ignore the early connection notification. - -This avoids a crash, but the window will not show anything on the -external screen, which is a separate issue. - -Pick-to: 6.5 6.4 6.2 -Fixes: QTBUG-106701 -Change-Id: I9e0a9736bf602277316bd004e0d01c640feaf319 -Reviewed-by: Volker Hilsheimer -(cherry picked from commit dd49793bc3b4dd3808f0f24b717c442a5095db14) ---- - src/plugins/platforms/ios/qiosscreen.mm | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -index f144c00fb0a..3d660189af4 100644 ---- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm -+++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -@@ -72,8 +72,8 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) - - + (void)screenConnected:(NSNotification*)notification - { -- Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO, -- "Screen connected before QIOSIntegration creation"); -+ if (!QIOSIntegration::instance()) -+ return; // Will be added when QIOSIntegration is created - - QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object])); - } --- -2.39.2 - diff --git a/libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch b/libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch deleted file mode 100644 index 5489207..0000000 --- a/libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch +++ /dev/null @@ -1,57 +0,0 @@ -From ae857fcf8415daafa6b77999dc8a44cd0e5ede7b Mon Sep 17 00:00:00 2001 -From: Jan Moeller -Date: Thu, 6 Apr 2023 09:27:16 +0200 -Subject: Ignore removed/changed screens if no QIOSIntegration instance exists - -QIOSTracker registers itself as handlers for system notifications about -changes of the screen environment. If no QIOSIntegration instance -exists, newly detected screens are not added to the list of known -screens (see screenConnected()). This, in turn, will result in a crash -if a screen is disconnected and removed in screenDisconnected() as it -is not known to qtPlatformScreenFor() and the function returns a -nullptr. - -Consider the QIOSIntegration also whenever a screen is "changed". This -is more of a safety measure do avoid crashes for unknown screens. - -This situation occurs if an iOS device is used to mirror the display -via AirPlay and no actual QGuiApplication exists, e.g. Qt is only -embedded in a Framework. - -Pick-to: 6.5 6.2 -Fixes: QTBUG-106701 -Change-Id: Id778fc5afa7c284b0536ee02b1ba2c10321cc5b1 -Reviewed-by: Volker Hilsheimer -Reviewed-by: Lars Schmertmann -(cherry picked from commit ffdfafc4b47b8267395370199073c292da33dd42) ---- - src/plugins/platforms/ios/qiosscreen.mm | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -index 3d660189af4..e0216ce6526 100644 ---- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm -+++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm -@@ -80,6 +80,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) - - + (void)screenDisconnected:(NSNotification*)notification - { -+ if (!QIOSIntegration::instance()) -+ return; -+ - QIOSScreen *screen = qtPlatformScreenFor([notification object]); - Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about"); - -@@ -88,6 +91,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) - - + (void)screenModeChanged:(NSNotification*)notification - { -+ if (!QIOSIntegration::instance()) -+ return; -+ - QIOSScreen *screen = qtPlatformScreenFor([notification object]); - Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about"); - --- -2.39.2 - diff --git a/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch b/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch deleted file mode 100644 index f7da165..0000000 --- a/libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 720768b715d432aa084c9c15b994a396a89968a8 Mon Sep 17 00:00:00 2001 -From: Julian Greilich -Date: Thu, 26 Jan 2023 19:19:21 +0100 -Subject: iOS NFC: Always ensure timeout after session invalidation - -iOS needs some time after invalidating a session before a new session -can be started. Otherwise the NFC dialog of iOS will not show up. - -For restarting a session inside the iOS NearfieldManager, this was -already solved with a timeout of 2 seconds. - -This commit fixes the case, that a user of the Nearfieldmanager -restarts a session manually too fast. - -Change-Id: Ic91ad225a9cab13ba92523f33a19f44af68575a0 -Reviewed-by: Timur Pocheptsov -(cherry picked from commit 849ba86ba9a073a266219b6a39786e20f4f3ed7b) -(cherry picked from commit 5052cd14c28bbf0ff93c465a4e33bf1dbd48c7dd) ---- - src/nfc/qnearfieldmanager_ios.mm | 44 +++++++++++++++++++++---------- - src/nfc/qnearfieldmanager_ios_p.h | 5 +++- - 2 files changed, 34 insertions(+), 15 deletions(-) - -diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm -index 6fd71451..a0651626 100644 ---- x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm -+++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm -@@ -25,6 +25,10 @@ QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() - connect(this, &QNearFieldManagerPrivateImpl::didInvalidateWithError, - this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError, - Qt::QueuedConnection); -+ -+ sessionTimer.setInterval(2000); -+ sessionTimer.setSingleShot(true); -+ connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer); - } - - QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() -@@ -62,7 +66,7 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access - if (@available(iOS 13, *)) - if (NFCTagReaderSession.readingAvailable) { - detectionRunning = true; -- startSession(); -+ scheduleSession(); - return true; - } - return false; -@@ -71,16 +75,28 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access - - void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage) - { -- if (detectionRunning) { -- stopSession(errorMessage); -- detectionRunning = false; -- Q_EMIT targetDetectionStopped(); -- } -+ if (!detectionRunning) -+ return; -+ -+ isSessionScheduled = false; -+ stopSession(errorMessage); -+ detectionRunning = false; -+ Q_EMIT targetDetectionStopped(); - } - -+void QNearFieldManagerPrivateImpl::scheduleSession() -+{ -+ if (sessionTimer.isActive()) { -+ isSessionScheduled = true; -+ return; -+ } -+ -+ startSession(); -+} - - void QNearFieldManagerPrivateImpl::startSession() - { -+ isSessionScheduled = false; - if (detectionRunning) - if (@available(iOS 13, *)) - [delegate startSession]; -@@ -132,17 +148,11 @@ void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *tar - void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart) - { - clearTargets(); -+ sessionTimer.start(); - - if (detectionRunning && doRestart) - { -- if (!isRestarting) { -- isRestarting = true; -- using namespace std::chrono_literals; -- QTimer::singleShot(2s, this, [this](){ -- isRestarting = false; -- startSession(); -- }); -- } -+ scheduleSession(); - return; - } - -@@ -150,4 +160,10 @@ void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart) - Q_EMIT targetDetectionStopped(); - } - -+void QNearFieldManagerPrivateImpl::onSessionTimer() -+{ -+ if (isSessionScheduled) -+ scheduleSession(); -+} -+ - QT_END_NAMESPACE -diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h -index 6aa1574e..b3668ff6 100644 ---- x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h -+++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h -@@ -54,9 +54,11 @@ Q_SIGNALS: - private: - QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) *delegate API_AVAILABLE(ios(13.0)) = nullptr; - bool detectionRunning = false; -- bool isRestarting = false; -+ bool isSessionScheduled = false; -+ QTimer sessionTimer; - QList detectedTargets; - -+ void scheduleSession(); - void startSession(); - void stopSession(const QString &error); - void clearTargets(); -@@ -65,6 +67,7 @@ private Q_SLOTS: - void onTagDiscovered(void *target); - void onTargetLost(QNearFieldTargetPrivateImpl *target); - void onDidInvalidateWithError(bool doRestart); -+ void onSessionTimer(); - }; - - --- -2.39.1 - diff --git a/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch b/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch deleted file mode 100644 index 7ad14c8..0000000 --- a/libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch +++ /dev/null @@ -1,102 +0,0 @@ -From f5b5a974f6ad854008c587c9494ae46785e21899 Mon Sep 17 00:00:00 2001 -From: Semih Yavuz -Date: Wed, 18 Jan 2023 15:36:23 +0100 -Subject: qmlformat: fix omitting some comments while reformatting - -We rewrite comments associated to a node on the preVisit call -(if they were marked as preComment), or postVisit( if comments were -marked as postComments) of the reformatter. If the comment -associated with a patternProperty kind of node, neither of these -functions are called. Add missing call to previsit/postVist -in the pattern property node visit. - -Pick-to: 6.4 6.5 -Fixes: QTBUG-109074 -Change-Id: If57968b3f5dbd83aa23dc2cd2bca3608ee841d49 -Reviewed-by: Sami Shalayel -Reviewed-by: Ulf Hermann -(cherry picked from commit 444d4f1f3f27a81996d9cbcc0642040b68728260) ---- - src/qmldom/qqmldomreformatter.cpp | 2 ++ - .../qmlformat/data/dontRemoveComments.formatted.qml | 13 +++++++++++++ - .../auto/qml/qmlformat/data/dontRemoveComments.qml | 13 +++++++++++++ - tests/auto/qml/qmlformat/tst_qmlformat.cpp | 3 +++ - 4 files changed, 31 insertions(+) - create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml - create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.qml - -diff --git x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp -index bb76f8f772..3dfacfc84e 100644 ---- x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp -+++ y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp -@@ -301,6 +301,7 @@ protected: - for (PatternPropertyList *it = ast; it; it = it->next) { - PatternProperty *assignment = AST::cast(it->property); - if (assignment) { -+ preVisit(assignment); - bool isStringLike = AST::cast(assignment->name) - || cast(assignment->name); - if (isStringLike) -@@ -316,6 +317,7 @@ protected: - accept(assignment->initializer); - if (it->next) - newLine(); -+ postVisit(assignment); - continue; - } - PatternPropertyList *getterSetter = AST::cast(it->next); -diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml -new file mode 100644 -index 0000000000..0c7a2829c9 ---- /dev/null -+++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml -@@ -0,0 +1,13 @@ -+Item { -+ property var test: [{ -+ // Testing -+ "foo": "bar" -+ }] -+ -+ onTestChanged: { -+ fooBar(test, { -+ // Testing -+ "foo": "bar" -+ }); -+ } -+} -diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml -new file mode 100644 -index 0000000000..1797834879 ---- /dev/null -+++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml -@@ -0,0 +1,13 @@ -+Item { -+ property var test: [{ -+// Testing -+ "foo": "bar" -+ }] -+ -+ onTestChanged: { -+ fooBar(test, { -+ // Testing -+ "foo": "bar" -+ }); -+ } -+} -diff --git x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp -index 9d7beb23a7..7755095acd 100644 ---- x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp -+++ y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp -@@ -276,6 +276,9 @@ void TestQmlformat::testFormat_data() - QTest::newRow("forWithLet") - << "forWithLet.qml" - << "forWithLet.formatted.qml" << QStringList {} << RunOption::OnCopy; -+ QTest::newRow("dontRemoveComments") -+ << "dontRemoveComments.qml" -+ << "dontRemoveComments.formatted.qml" << QStringList {} << RunOption::OnCopy; - } - - void TestQmlformat::testFormat() --- -2.39.1 - diff --git a/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch b/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch deleted file mode 100644 index d345633..0000000 --- a/libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5a844a0c1b5e9c1b9fb94831afc0724f5deaa7dd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= -Date: Tue, 12 Apr 2022 10:21:19 +0200 -Subject: Make qtdeclarative optional for CONTAINER_SDK - -Change-Id: Ia25b91ea5e3716aef4cb096de1052267b70e343d ---- - dependencies.yaml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git x/qtscxml/dependencies.yaml y/qtscxml/dependencies.yaml -index ee6f92e..7375551 100644 ---- x/qtscxml/dependencies.yaml -+++ y/qtscxml/dependencies.yaml -@@ -4,4 +4,4 @@ dependencies: - required: true - ../qtdeclarative: - ref: a514640b2a38391fceaaac3ca01b390ad3d62f31 -- required: true -+ required: false --- -2.38.1 - diff --git a/libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch b/libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch deleted file mode 100644 index c311a71..0000000 --- a/libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch +++ /dev/null @@ -1,38 +0,0 @@ -From ee68d7d67358f92c87720c2f740322fb03ad8299 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= -Date: Tue, 12 Apr 2022 11:39:12 +0200 -Subject: Disable qtscxml library - ---- - src/CMakeLists.txt | 4 ++-- - tools/CMakeLists.txt | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git x/qtscxml/src/CMakeLists.txt y/qtscxml/src/CMakeLists.txt -index f1b7c2b..7e28acc 100644 ---- x/qtscxml/src/CMakeLists.txt -+++ y/qtscxml/src/CMakeLists.txt -@@ -1,8 +1,8 @@ - --add_subdirectory(scxml) -+#add_subdirectory(scxml) - add_subdirectory(statemachine) - if(TARGET Qt::Qml) - add_subdirectory(statemachineqml) -- add_subdirectory(scxmlqml) -+# add_subdirectory(scxmlqml) - endif() - add_subdirectory(plugins) -diff --git x/qtscxml/tools/CMakeLists.txt y/qtscxml/tools/CMakeLists.txt -index 9726a78..956f904 100644 ---- x/qtscxml/tools/CMakeLists.txt -+++ y/qtscxml/tools/CMakeLists.txt -@@ -1,4 +1,4 @@ - - if(QT_FEATURE_commandlineparser) -- add_subdirectory(qscxmlc) -+ #add_subdirectory(qscxmlc) - endif() --- -2.38.1 - diff --git a/libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch b/libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch deleted file mode 100644 index 54eda29..0000000 --- a/libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 125584904a64497ae50b227ef326e0fc12683a4b Mon Sep 17 00:00:00 2001 -From: Jan Moeller -Date: Mon, 14 Feb 2022 13:46:46 +0100 -Subject: Disable linguist but keep translation tools - -Change-Id: I1c54eb0e7bb86ec0861b54b5abe753c86bb57dd9 ---- - src/linguist/CMakeLists.txt | 3 --- - 1 file changed, 3 deletions(-) - -diff --git x/qttools/src/linguist/CMakeLists.txt y/qttools/src/linguist/CMakeLists.txt -index 16ff9f559..fde23b0c4 100644 ---- x/qttools/src/linguist/CMakeLists.txt -+++ y/qttools/src/linguist/CMakeLists.txt -@@ -14,9 +14,6 @@ add_subdirectory(lrelease) - add_subdirectory(lrelease-pro) - add_subdirectory(lupdate) - add_subdirectory(lupdate-pro) --if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png) -- add_subdirectory(linguist) --endif() - - # special case begin - # Create a fake module that would emulate the Qt5::LinguistTools CMake Config package --- -2.38.1 - diff --git a/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch b/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch deleted file mode 100644 index ef7852d..0000000 --- a/libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch +++ /dev/null @@ -1,3235 +0,0 @@ -From d6c550d3ef01a50e100acd4fa44a2d6fbd376cbb Mon Sep 17 00:00:00 2001 -From: Lars Schmertmann -Date: Wed, 9 Nov 2022 09:49:38 +0100 -Subject: Revert "Move UiTools and UiPlugin modules to a upper level - sub-directory" - -This partially reverts commit 6af882fa2f45f73ec2ba4066d5ae3ad072d0c5ee. - -Change-Id: I247e2189577b74d813a210ace0b49d672a90975e ---- - src/CMakeLists.txt | 5 - - src/designer/src/CMakeLists.txt | 2 + - .../src/designer/doc/qtdesigner.qdocconf | 4 +- - src/designer/src/uiplugin/CMakeLists.txt | 27 + - src/designer/src/uiplugin/customwidget.h | 62 ++ - src/designer/src/uiplugin/customwidget.qdoc | 269 ++++++ - .../src/uiplugin/qdesignerexportwidget.h | 24 + - src/designer/src/uitools/CMakeLists.txt | 47 + - src/designer/src/uitools/qtuitoolsglobal.h | 24 + - src/designer/src/uitools/quiloader.cpp | 914 ++++++++++++++++++ - src/designer/src/uitools/quiloader.h | 61 ++ - src/designer/src/uitools/quiloader_p.h | 77 ++ - src/uiplugin/CMakeLists.txt | 27 - - src/uiplugin/customwidget.h | 62 -- - src/uiplugin/customwidget.qdoc | 269 ------ - src/uiplugin/qdesignerexportwidget.h | 24 - - src/uitools/CMakeLists.txt | 47 - - src/uitools/qtuitoolsglobal.h | 24 - - src/uitools/quiloader.cpp | 914 ------------------ - src/uitools/quiloader.h | 61 -- - src/uitools/quiloader_p.h | 77 -- - sync.profile | 4 +- - 22 files changed, 1511 insertions(+), 1514 deletions(-) - create mode 100644 src/designer/src/uiplugin/CMakeLists.txt - create mode 100644 src/designer/src/uiplugin/customwidget.h - create mode 100644 src/designer/src/uiplugin/customwidget.qdoc - create mode 100644 src/designer/src/uiplugin/qdesignerexportwidget.h - create mode 100644 src/designer/src/uitools/CMakeLists.txt - create mode 100644 src/designer/src/uitools/qtuitoolsglobal.h - create mode 100644 src/designer/src/uitools/quiloader.cpp - create mode 100644 src/designer/src/uitools/quiloader.h - create mode 100644 src/designer/src/uitools/quiloader_p.h - delete mode 100644 src/uiplugin/CMakeLists.txt - delete mode 100644 src/uiplugin/customwidget.h - delete mode 100644 src/uiplugin/customwidget.qdoc - delete mode 100644 src/uiplugin/qdesignerexportwidget.h - delete mode 100644 src/uitools/CMakeLists.txt - delete mode 100644 src/uitools/qtuitoolsglobal.h - delete mode 100644 src/uitools/quiloader.cpp - delete mode 100644 src/uitools/quiloader.h - delete mode 100644 src/uitools/quiloader_p.h - -diff --git x/qttools/src/CMakeLists.txt y/qttools/src/CMakeLists.txt -index b42cd4946..cb0c21a70 100644 ---- x/qttools/src/CMakeLists.txt -+++ y/qttools/src/CMakeLists.txt -@@ -21,11 +21,6 @@ qt_exclude_tool_directories_from_default_target( - qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake") - # special case end - --if(TARGET Qt::Widgets) -- add_subdirectory(uiplugin) -- add_subdirectory(uitools) --endif() -- - add_subdirectory(global) # special case add as first directory - if(QT_FEATURE_linguist) - add_subdirectory(linguist) -diff --git x/qttools/src/designer/src/CMakeLists.txt y/qttools/src/designer/src/CMakeLists.txt -index 31fc1734e..32fb45160 100644 ---- x/qttools/src/designer/src/CMakeLists.txt -+++ y/qttools/src/designer/src/CMakeLists.txt -@@ -8,6 +8,8 @@ qt_exclude_tool_directories_from_default_target( - plugins - ) - -+add_subdirectory(uiplugin) -+add_subdirectory(uitools) - if(QT_FEATURE_process) - add_subdirectory(lib) - add_subdirectory(components) -diff --git x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf -index 75c8c78dd..964fb47ed 100644 ---- x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf -+++ y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf -@@ -28,11 +28,11 @@ qhp.QtDesigner.subprojects.classes.sortPages = true - language = Cpp - - headerdirs += .. \ -- ../../../../uiplugin \ -+ ../../uiplugin \ - ../../lib - - sourcedirs = .. \ -- ../../../../uiplugin \ -+ ../../uiplugin \ - ../../lib - - exampledirs = ../../../../../examples/designer \ -diff --git x/qttools/src/designer/src/uiplugin/CMakeLists.txt y/qttools/src/designer/src/uiplugin/CMakeLists.txt -new file mode 100644 -index 000000000..4fedf8e33 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/CMakeLists.txt -@@ -0,0 +1,27 @@ -+# Generated from uiplugin.pro. -+ -+##################################################################### -+## UiPlugin Module: -+##################################################################### -+ -+qt_internal_add_module(UiPlugin -+ NO_PRIVATE_MODULE -+ HEADER_MODULE -+ QMAKE_MODULE_CONFIG designer_defines -+ PUBLIC_LIBRARIES -+ Qt::Core -+ Qt::Gui -+ Qt::Widgets -+) -+ -+# special case begin -+set(is_plugin "$") -+target_compile_definitions( -+ UiPlugin -+ INTERFACE -+ $<$:QDESIGNER_EXPORT_WIDGETS> -+) -+# special case end -+ -+#### Keys ignored in scope 1:.:.:uiplugin.pro:: -+# MODULE_CONFIG = "designer_defines" -diff --git x/qttools/src/designer/src/uiplugin/customwidget.h y/qttools/src/designer/src/uiplugin/customwidget.h -new file mode 100644 -index 000000000..2a47a32f8 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/customwidget.h -@@ -0,0 +1,62 @@ -+// Copyright (C) 2016 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -+ -+#ifndef CUSTOMWIDGET_H -+#define CUSTOMWIDGET_H -+ -+#include -+#include -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+class QWidget; -+class QDesignerFormEditorInterface; -+ -+class QDesignerCustomWidgetInterface -+{ -+public: -+ virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable -+ -+ virtual QString name() const = 0; -+ virtual QString group() const = 0; -+ virtual QString toolTip() const = 0; -+ virtual QString whatsThis() const = 0; -+ virtual QString includeFile() const = 0; -+ virtual QIcon icon() const = 0; -+ -+ virtual bool isContainer() const = 0; -+ -+ virtual QWidget *createWidget(QWidget *parent) = 0; -+ -+ virtual bool isInitialized() const { return false; } -+ virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); } -+ -+ virtual QString domXml() const -+ { -+ return QString::fromUtf8("") -+ .arg(name()).arg(name().toLower()); -+ } -+ -+ virtual QString codeTemplate() const { return QString(); } -+}; -+ -+#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface" -+ -+Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid) -+ -+class QDesignerCustomWidgetCollectionInterface -+{ -+public: -+ virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable -+ -+ virtual QList customWidgets() const = 0; -+}; -+ -+#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface" -+ -+Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid) -+ -+QT_END_NAMESPACE -+ -+#endif // CUSTOMWIDGET_H -diff --git x/qttools/src/designer/src/uiplugin/customwidget.qdoc y/qttools/src/designer/src/uiplugin/customwidget.qdoc -new file mode 100644 -index 000000000..557e9a454 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/customwidget.qdoc -@@ -0,0 +1,269 @@ -+// Copyright (C) 2016 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only -+ -+/*! -+ \class QDesignerCustomWidgetInterface -+ -+ \brief The QDesignerCustomWidgetInterface class enables Qt Designer -+ to access and construct custom widgets. -+ -+ \inmodule QtDesigner -+ -+ QDesignerCustomWidgetInterface provides a custom widget with an -+ interface. The class contains a set of functions that must be subclassed -+ to return basic information about the widget, such as its class name and -+ the name of its header file. Other functions must be implemented to -+ initialize the plugin when it is loaded, and to construct instances of -+ the custom widget for \QD to use. -+ -+ When implementing a custom widget you must subclass -+ QDesignerCustomWidgetInterface to expose your widget to \QD. For -+ example, this is the declaration for the plugin used in the -+ \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that -+ enables an analog clock custom widget to be used by \QD: -+ -+ \snippet customwidgetplugin/customwidgetplugin.h 0 -+ -+ Note that the only part of the class definition that is specific -+ to this particular custom widget is the class name. In addition, -+ since we are implementing an interface, we must ensure that it's -+ made known to the meta object system using the Q_INTERFACES() -+ macro. This enables \QD to use the qobject_cast() function to -+ query for supported interfaces using nothing but a QObject -+ pointer. -+ -+ After \QD loads a custom widget plugin, it calls the interface's -+ initialize() function to enable it to set up any resources that it -+ may need. This function is called with a QDesignerFormEditorInterface -+ parameter that provides the plugin with a gateway to all of \QD's API. -+ -+ \QD constructs instances of the custom widget by calling the plugin's -+ createWidget() function with a suitable parent widget. Plugins must -+ construct and return an instance of a custom widget with the specified -+ parent widget. -+ -+ Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA() -+ macro. For example, if a library called \c libcustomwidgetplugin.so -+ (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget -+ class called \c MyCustomWidget, we can export it by adding the -+ following line to the file containing the plugin header: -+ -+ \snippet plugins/doc_src_qtdesigner.cpp 14 -+ -+ This macro ensures that \QD can access and construct the custom widget. -+ Without this macro, there is no way for \QD to use it. -+ -+ When implementing a custom widget plugin, you build it as a -+ separate library. If you want to include several custom widget -+ plugins in the same library, you must in addition subclass -+ QDesignerCustomWidgetCollectionInterface. -+ -+ \warning If your custom widget plugin contains QVariant -+ properties, be aware that only the following \l -+ {QVariant::Type}{types} are supported: -+ -+ \list -+ \li QVariant::ByteArray -+ \li QVariant::Bool -+ \li QVariant::Color -+ \li QVariant::Cursor -+ \li QVariant::Date -+ \li QVariant::DateTime -+ \li QVariant::Double -+ \li QVariant::Int -+ \li QVariant::Point -+ \li QVariant::Rect -+ \li QVariant::Size -+ \li QVariant::SizePolicy -+ \li QVariant::String -+ \li QVariant::Time -+ \li QVariant::UInt -+ \endlist -+ -+ For a complete example using the QDesignerCustomWidgetInterface -+ class, see the \l {customwidgetplugin}{Custom Widget -+ Example}. The example shows how to create a custom widget plugin -+ for \QD. -+ -+ \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer} -+*/ -+ -+/*! -+ \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface() -+ -+ Destroys the custom widget interface. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::name() const -+ -+ Returns the class name of the custom widget supplied by the interface. -+ -+ The name returned \e must be identical to the class name used for the -+ custom widget. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::group() const -+ -+ Returns the name of the group to which the custom widget belongs. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::toolTip() const -+ -+ Returns a short description of the widget that can be used by \QD -+ in a tool tip. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::whatsThis() const -+ -+ Returns a description of the widget that can be used by \QD in -+ "What's This?" help for the widget. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::includeFile() const -+ -+ Returns the path to the include file that \l uic uses when -+ creating code for the custom widget. -+*/ -+ -+/*! -+ \fn QIcon QDesignerCustomWidgetInterface::icon() const -+ -+ Returns the icon used to represent the custom widget in \QD's -+ widget box. -+*/ -+ -+/*! -+ \fn bool QDesignerCustomWidgetInterface::isContainer() const -+ -+ Returns true if the custom widget is intended to be used as a -+ container; otherwise returns false. -+ -+ Most custom widgets are not used to hold other widgets, so their -+ implementations of this function will return false, but custom -+ containers will return true to ensure that they behave correctly -+ in \QD. -+*/ -+ -+/*! -+ \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent) -+ -+ Returns a new instance of the custom widget, with the given \a -+ parent. -+*/ -+ -+/*! -+ \fn bool QDesignerCustomWidgetInterface::isInitialized() const -+ -+ Returns true if the widget has been initialized; otherwise returns -+ false. -+ -+ \sa initialize() -+*/ -+ -+/*! -+ \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) -+ -+ Initializes the widget for use with the specified \a formEditor -+ interface. -+ -+ \sa isInitialized() -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::domXml() const -+ -+ Returns the XML that is used to describe the custom widget's -+ properties to \QD. -+*/ -+ -+/*! -+ \fn QString QDesignerCustomWidgetInterface::codeTemplate() const -+ -+ This function is reserved for future use by \QD. -+ -+ \omit -+ Returns the code template that \QD includes in forms that contain -+ the custom widget when they are saved. -+ \endomit -+*/ -+ -+/*! -+ \macro QDESIGNER_WIDGET_EXPORT -+ \relates QDesignerCustomWidgetInterface -+ \since 4.1 -+ -+ This macro is used when defining custom widgets to ensure that they are -+ correctly exported from plugins for use with \QD. -+ -+ On some platforms, the symbols required by \QD to create new widgets -+ are removed from plugins by the build system, making them unusable. -+ Using this macro ensures that the symbols are retained on those platforms, -+ and has no side effects on other platforms. -+ -+ For example, the \l{worldtimeclockplugin}{World Time Clock Plugin} -+ example exports a custom widget class with the following declaration: -+ -+ \snippet worldtimeclockplugin/worldtimeclock.h 0 -+ \dots -+ \snippet worldtimeclockplugin/worldtimeclock.h 2 -+ -+ \sa {Creating Custom Widgets for Qt Designer} -+*/ -+ -+ -+ -+ -+ -+/*! -+ \class QDesignerCustomWidgetCollectionInterface -+ -+ \brief The QDesignerCustomWidgetCollectionInterface class allows -+ you to include several custom widgets in one single library. -+ -+ \inmodule QtDesigner -+ -+ When implementing a custom widget plugin, you build it as a -+ separate library. If you want to include several custom widget -+ plugins in the same library, you must in addition subclass -+ QDesignerCustomWidgetCollectionInterface. -+ -+ QDesignerCustomWidgetCollectionInterface contains one single -+ function returning a list of the collection's -+ QDesignerCustomWidgetInterface objects. For example, if you have -+ several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and -+ \c CustomWidgetThree, the class definition may look like this: -+ -+ \snippet plugins/doc_src_qtdesigner.cpp 12 -+ -+ In the class constructor you add the interfaces to your custom -+ widgets to the list which you return in the customWidgets() -+ function: -+ -+ \snippet plugins/doc_src_qtdesigner.cpp 13 -+ -+ Note that instead of exporting each custom widget plugin using the -+ Q_PLUGIN_METADATA() macro, you export the entire collection. The -+ Q_PLUGIN_METADATA() macro ensures that \QD can access and construct -+ the custom widgets. Without this macro, there is no way for \QD to -+ use them. -+ -+ \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for -+ Qt Designer} -+*/ -+ -+/*! -+ \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() { -+ -+ Destroys the custom widget collection interface. -+*/ -+ -+/*! -+ \fn QList QDesignerCustomWidgetCollectionInterface::customWidgets() const -+ -+ Returns a list of interfaces to the collection's custom widgets. -+*/ -diff --git x/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h -new file mode 100644 -index 000000000..d90e9b217 ---- /dev/null -+++ y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h -@@ -0,0 +1,24 @@ -+// Copyright (C) 2016 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -+ -+#ifndef QDESIGNEREXPORTWIDGET_H -+#define QDESIGNEREXPORTWIDGET_H -+ -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+#if 0 -+// pragma for syncqt, don't remove. -+#pragma qt_class(QDesignerExportWidget) -+#endif -+ -+#if defined(QDESIGNER_EXPORT_WIDGETS) -+# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT -+#else -+# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT -+#endif -+ -+QT_END_NAMESPACE -+ -+#endif //QDESIGNEREXPORTWIDGET_H -diff --git x/qttools/src/designer/src/uitools/CMakeLists.txt y/qttools/src/designer/src/uitools/CMakeLists.txt -new file mode 100644 -index 000000000..5306fcbd5 ---- /dev/null -+++ y/qttools/src/designer/src/uitools/CMakeLists.txt -@@ -0,0 +1,47 @@ -+# Generated from uitools.pro. -+ -+##################################################################### -+## UiTools Module: -+##################################################################### -+ -+qt_internal_add_module(UiTools -+ SOURCES -+ ../lib/uilib/abstractformbuilder.cpp ../lib/uilib/abstractformbuilder.h -+ ../lib/uilib/formbuilder.cpp ../lib/uilib/formbuilder.h -+ ../lib/uilib/formbuilderextra.cpp ../lib/uilib/formbuilderextra_p.h -+ ../lib/uilib/properties.cpp ../lib/uilib/properties_p.h -+ ../lib/uilib/resourcebuilder.cpp ../lib/uilib/resourcebuilder_p.h -+ ../lib/uilib/textbuilder.cpp ../lib/uilib/textbuilder_p.h -+ ../lib/uilib/ui4.cpp ../lib/uilib/ui4_p.h -+ quiloader.cpp quiloader.h -+ DEFINES -+ QFORMINTERNAL_NAMESPACE -+ QT_DESIGNER -+ QT_DESIGNER_STATIC -+ QT_USE_QSTRINGBUILDER -+ INCLUDE_DIRECTORIES -+ ../lib/uilib -+ LIBRARIES -+ Qt::UiPlugin -+ PUBLIC_LIBRARIES -+ Qt::Core -+ Qt::Gui -+ Qt::Widgets -+) -+ -+## Scopes: -+##################################################################### -+ -+qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets -+ PUBLIC_LIBRARIES -+ Qt::OpenGLWidgets -+) -+ -+qt_internal_extend_target(UiTools CONDITION QT_FEATURE_opengl -+ LIBRARIES -+ Qt::OpenGL -+) -+qt_internal_add_docs(UiTools -+ doc/qtuitools.qdocconf -+) -+ -diff --git x/qttools/src/designer/src/uitools/qtuitoolsglobal.h y/qttools/src/designer/src/uitools/qtuitoolsglobal.h -new file mode 100644 -index 000000000..a2f967dee ---- /dev/null -+++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h -@@ -0,0 +1,24 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+#ifndef QTUITOOLSGLOBAL_H -+#define QTUITOOLSGLOBAL_H -+ -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+#ifndef QT_STATIC -+# if defined(QT_BUILD_UITOOLS_LIB) -+# define Q_UITOOLS_EXPORT Q_DECL_EXPORT -+# else -+# define Q_UITOOLS_EXPORT Q_DECL_IMPORT -+# endif -+#else -+# define Q_UITOOLS_EXPORT -+#endif -+ -+QT_END_NAMESPACE -+ -+#endif // QTUITOOLSGLOBAL_H -+ -diff --git x/qttools/src/designer/src/uitools/quiloader.cpp y/qttools/src/designer/src/uitools/quiloader.cpp -new file mode 100644 -index 000000000..a06d4717b ---- /dev/null -+++ y/qttools/src/designer/src/uitools/quiloader.cpp -@@ -0,0 +1,914 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+ -+#include "quiloader.h" -+#include "quiloader_p.h" -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+typedef QMap widget_map; -+Q_GLOBAL_STATIC(widget_map, g_widgets) -+ -+class QUiLoader; -+class QUiLoaderPrivate; -+ -+#ifndef QT_NO_DATASTREAM -+// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based -+// mime data when dragging items in views with QAbstractItemView::InternalMove. -+QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) -+{ -+ out << s.qualifier() << s.value(); -+ return out; -+} -+ -+QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) -+{ -+ QByteArray qualifier, value; -+ in >> qualifier >> value; -+ s.setQualifier(qualifier); -+ s.setValue(value); -+ return in; -+} -+#endif // QT_NO_DATASTREAM -+ -+QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const -+{ -+ return idBased -+ ? qtTrId(m_qualifier.constData()) -+ : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData()); -+} -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+namespace QFormInternal -+{ -+#endif -+ -+class TranslatingTextBuilder : public QTextBuilder -+{ -+public: -+ explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) : -+ m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {} -+ -+ QVariant loadText(const DomProperty *icon) const override; -+ -+ QVariant toNativeValue(const QVariant &value) const override; -+ -+ bool idBased() const { return m_idBased; } -+ -+private: -+ bool m_idBased; -+ bool m_trEnabled; -+ QByteArray m_className; -+}; -+ -+QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const -+{ -+ const DomString *str = text->elementString(); -+ if (!str) -+ return QVariant(); -+ if (str->hasAttributeNotr()) { -+ const QString notr = str->attributeNotr(); -+ if (notr == QStringLiteral("true") || notr == QStringLiteral("yes")) -+ return QVariant::fromValue(str->text()); -+ } -+ QUiTranslatableStringValue strVal; -+ strVal.setValue(str->text().toUtf8()); -+ if (m_idBased) -+ strVal.setQualifier(str->attributeId().toUtf8()); -+ else if (str->hasAttributeComment()) -+ strVal.setQualifier(str->attributeComment().toUtf8()); -+ return QVariant::fromValue(strVal); -+} -+ -+QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const -+{ -+ if (value.canConvert()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(value); -+ if (!m_trEnabled) -+ return QString::fromUtf8(tsv.value().constData()); -+ return QVariant::fromValue(tsv.translate(m_className, m_idBased)); -+ } -+ if (value.canConvert()) -+ return QVariant::fromValue(qvariant_cast(value)); -+ return value; -+} -+ -+// This is "exported" to linguist -+const QUiItemRolePair qUiItemRoles[] = { -+ { Qt::DisplayRole, Qt::DisplayPropertyRole }, -+#if QT_CONFIG(tooltip) -+ { Qt::ToolTipRole, Qt::ToolTipPropertyRole }, -+#endif -+#if QT_CONFIG(statustip) -+ { Qt::StatusTipRole, Qt::StatusTipPropertyRole }, -+#endif -+#if QT_CONFIG(whatsthis) -+ { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole }, -+#endif -+ { -1 , -1 } -+}; -+ -+static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased) -+{ -+ const QUiItemRolePair *irs = qUiItemRoles; -+ -+ int cnt = item->columnCount(); -+ for (int i = 0; i < cnt; ++i) { -+ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -+ QVariant v = item->data(i, irs[j].shadowRole); -+ if (v.isValid()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(v); -+ item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased)); -+ } -+ } -+ } -+ -+ cnt = item->childCount(); -+ for (int i = 0; i < cnt; ++i) -+ recursiveReTranslate(item->child(i), class_name, idBased); -+} -+ -+template -+static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased) -+{ -+ const QUiItemRolePair *irs = qUiItemRoles; -+ -+ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -+ QVariant v = item->data(irs[j].shadowRole); -+ if (v.isValid()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(v); -+ item->setData(irs[j].realRole, tsv.translate(class_name, idBased)); -+ } -+ } -+} -+ -+static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased) -+{ -+ if (item) -+ reTranslateWidgetItem(item, class_name, idBased); -+} -+ -+#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \ -+ do { \ -+ QVariant v = mainWidget->widget(i)->property(propName); \ -+ if (v.isValid()) { \ -+ QUiTranslatableStringValue tsv = qvariant_cast(v); \ -+ mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \ -+ } \ -+ } while (0) -+ -+class TranslationWatcher: public QObject -+{ -+ Q_OBJECT -+ -+public: -+ explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased): -+ QObject(parent), -+ m_className(className), -+ m_idBased(idBased) -+ { -+ } -+ -+ bool eventFilter(QObject *o, QEvent *event) override -+ { -+ if (event->type() == QEvent::LanguageChange) { -+ const auto &dynamicPropertyNames = o->dynamicPropertyNames(); -+ for (const QByteArray &prop : dynamicPropertyNames) { -+ if (prop.startsWith(PROP_GENERIC_PREFIX)) { -+ const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); -+ const QUiTranslatableStringValue tsv = -+ qvariant_cast(o->property(prop)); -+ o->setProperty(propName, tsv.translate(m_className, m_idBased)); -+ } -+ } -+ if (0) { -+#if QT_CONFIG(tabwidget) -+ } else if (QTabWidget *tabw = qobject_cast(o)) { -+ const int cnt = tabw->count(); -+ for (int i = 0; i < cnt; ++i) { -+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT); -+#if QT_CONFIG(tooltip) -+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP); -+# endif -+#if QT_CONFIG(whatsthis) -+ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); -+# endif -+ } -+#endif -+#if QT_CONFIG(listwidget) -+ } else if (QListWidget *listw = qobject_cast(o)) { -+ const int cnt = listw->count(); -+ for (int i = 0; i < cnt; ++i) -+ reTranslateWidgetItem(listw->item(i), m_className, m_idBased); -+#endif -+#if QT_CONFIG(treewidget) -+ } else if (QTreeWidget *treew = qobject_cast(o)) { -+ if (QTreeWidgetItem *item = treew->headerItem()) -+ recursiveReTranslate(item, m_className, m_idBased); -+ const int cnt = treew->topLevelItemCount(); -+ for (int i = 0; i < cnt; ++i) { -+ QTreeWidgetItem *item = treew->topLevelItem(i); -+ recursiveReTranslate(item, m_className, m_idBased); -+ } -+#endif -+#if QT_CONFIG(tablewidget) -+ } else if (QTableWidget *tablew = qobject_cast(o)) { -+ const int row_cnt = tablew->rowCount(); -+ const int col_cnt = tablew->columnCount(); -+ for (int j = 0; j < col_cnt; ++j) -+ reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased); -+ for (int i = 0; i < row_cnt; ++i) { -+ reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased); -+ for (int j = 0; j < col_cnt; ++j) -+ reTranslateTableItem(tablew->item(i, j), m_className, m_idBased); -+ } -+#endif -+#if QT_CONFIG(combobox) -+ } else if (QComboBox *combow = qobject_cast(o)) { -+ if (!qobject_cast(o)) { -+ const int cnt = combow->count(); -+ for (int i = 0; i < cnt; ++i) { -+ const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole); -+ if (v.isValid()) { -+ QUiTranslatableStringValue tsv = qvariant_cast(v); -+ combow->setItemText(i, tsv.translate(m_className, m_idBased)); -+ } -+ } -+ } -+#endif -+#if QT_CONFIG(toolbox) -+ } else if (QToolBox *toolw = qobject_cast(o)) { -+ const int cnt = toolw->count(); -+ for (int i = 0; i < cnt; ++i) { -+ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT); -+#if QT_CONFIG(tooltip) -+ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP); -+# endif -+ } -+#endif -+ } -+ } -+ return false; -+ } -+ -+private: -+ QByteArray m_className; -+ bool m_idBased; -+}; -+ -+class FormBuilderPrivate: public QFormBuilder -+{ -+ friend class QT_PREPEND_NAMESPACE(QUiLoader); -+ friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate); -+ using ParentClass = QFormBuilder; -+ -+public: -+ QUiLoader *loader = nullptr; -+ -+ bool dynamicTr = false; -+ bool trEnabled = true; -+ -+ FormBuilderPrivate() = default; -+ -+ QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name) -+ { -+ return ParentClass::createWidget(className, parent, name); -+ } -+ -+ QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name) -+ { -+ return ParentClass::createLayout(className, parent, name); -+ } -+ -+ QAction *defaultCreateAction(QObject *parent, const QString &name) -+ { -+ return ParentClass::createAction(parent, name); -+ } -+ -+ QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name) -+ { -+ return ParentClass::createActionGroup(parent, name); -+ } -+ -+ QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override -+ { -+ if (QWidget *widget = loader->createWidget(className, parent, name)) { -+ widget->setObjectName(name); -+ return widget; -+ } -+ -+ return nullptr; -+ } -+ -+ QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override -+ { -+ if (QLayout *layout = loader->createLayout(className, parent, name)) { -+ layout->setObjectName(name); -+ return layout; -+ } -+ -+ return nullptr; -+ } -+ -+ QActionGroup *createActionGroup(QObject *parent, const QString &name) override -+ { -+ if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) { -+ actionGroup->setObjectName(name); -+ return actionGroup; -+ } -+ -+ return nullptr; -+ } -+ -+ QAction *createAction(QObject *parent, const QString &name) override -+ { -+ if (QAction *action = loader->createAction(parent, name)) { -+ action->setObjectName(name); -+ return action; -+ } -+ -+ return nullptr; -+ } -+ -+ void applyProperties(QObject *o, const QList &properties) override; -+ QWidget *create(DomUI *ui, QWidget *parentWidget) override; -+ QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override; -+ bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override; -+ -+private: -+ QByteArray m_class; -+ TranslationWatcher *m_trwatch = nullptr; -+ bool m_idBased = false; -+}; -+ -+static QString convertTranslatable(const DomProperty *p, const QByteArray &className, -+ bool idBased, QUiTranslatableStringValue *strVal) -+{ -+ if (p->kind() != DomProperty::String) -+ return QString(); -+ const DomString *dom_str = p->elementString(); -+ if (!dom_str) -+ return QString(); -+ if (dom_str->hasAttributeNotr()) { -+ const QString notr = dom_str->attributeNotr(); -+ if (notr == QStringLiteral("yes") || notr == QStringLiteral("true")) -+ return QString(); -+ } -+ strVal->setValue(dom_str->text().toUtf8()); -+ strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8()); -+ if (strVal->value().isEmpty() && strVal->qualifier().isEmpty()) -+ return QString(); -+ return strVal->translate(className, idBased); -+} -+ -+void FormBuilderPrivate::applyProperties(QObject *o, const QList &properties) -+{ -+ QFormBuilder::applyProperties(o, properties); -+ -+ if (!m_trwatch) -+ m_trwatch = new TranslationWatcher(o, m_class, m_idBased); -+ -+ if (properties.isEmpty()) -+ return; -+ -+ // Unlike string item roles, string properties are not loaded via the textBuilder -+ // (as they are "shadowed" by the property sheets in designer). So do the initial -+ // translation here. -+ bool anyTrs = false; -+ for (const DomProperty *p : properties) { -+ QUiTranslatableStringValue strVal; -+ const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); -+ if (text.isEmpty()) -+ continue; -+ const QByteArray name = p->attributeName().toUtf8(); -+ if (dynamicTr) { -+ const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name); -+ o->setProperty(dynname, QVariant::fromValue(strVal)); -+ anyTrs = trEnabled; -+ } -+ if (p->elementString()->text() != text) -+ o->setProperty(name, text); -+ } -+ if (anyTrs) -+ o->installEventFilter(m_trwatch); -+} -+ -+QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget) -+{ -+ m_class = ui->elementClass().toUtf8(); -+ m_trwatch = nullptr; -+ m_idBased = ui->attributeIdbasedtr(); -+ setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class)); -+ return QFormBuilder::create(ui, parentWidget); -+} -+ -+QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget) -+{ -+ QWidget *w = QFormBuilder::create(ui_widget, parentWidget); -+ if (w == nullptr) -+ return nullptr; -+ -+ if (0) { -+#if QT_CONFIG(tabwidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(listwidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(treewidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(tablewidget) -+ } else if (qobject_cast(w)) { -+#endif -+#if QT_CONFIG(combobox) -+ } else if (qobject_cast(w)) { -+ if (qobject_cast(w)) -+ return w; -+#endif -+#if QT_CONFIG(toolbox) -+ } else if (qobject_cast(w)) { -+#endif -+ } else { -+ return w; -+ } -+ if (dynamicTr && trEnabled) -+ w->installEventFilter(m_trwatch); -+ return w; -+} -+ -+#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \ -+ do { \ -+ if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \ -+ QUiTranslatableStringValue strVal; \ -+ const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \ -+ if (!text.isEmpty()) { \ -+ if (dynamicTr) \ -+ mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \ -+ mainWidget->setter(i, text); \ -+ } \ -+ } \ -+ } while (0) -+ -+bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) -+{ -+ if (parentWidget == nullptr) -+ return true; -+ -+ if (!ParentClass::addItem(ui_widget, widget, parentWidget)) -+ return false; -+ -+ // Check special cases. First: Custom container -+ const QString className = QLatin1String(parentWidget->metaObject()->className()); -+ if (!d->customWidgetAddPageMethod(className).isEmpty()) -+ return true; -+ -+ const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); -+ -+ if (0) { -+#if QT_CONFIG(tabwidget) -+ } else if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { -+ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -+ const int i = tabWidget->count() - 1; -+ TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT); -+#if QT_CONFIG(tooltip) -+ TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP); -+# endif -+#if QT_CONFIG(whatsthis) -+ TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); -+# endif -+#endif -+#if QT_CONFIG(toolbox) -+ } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { -+ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -+ const int i = toolBox->count() - 1; -+ TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT); -+#if QT_CONFIG(tooltip) -+ TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP); -+# endif -+#endif -+ } -+ -+ return true; -+} -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+} -+#endif -+ -+class QUiLoaderPrivate -+{ -+public: -+#ifdef QFORMINTERNAL_NAMESPACE -+ QFormInternal::FormBuilderPrivate builder; -+#else -+ FormBuilderPrivate builder; -+#endif -+ -+ void setupWidgetMap() const; -+}; -+ -+void QUiLoaderPrivate::setupWidgetMap() const -+{ -+ if (!g_widgets()->isEmpty()) -+ return; -+ -+#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true); -+#define DECLARE_LAYOUT(a, b) -+ -+#include "widgets.table" -+ -+#undef DECLARE_WIDGET -+#undef DECLARE_WIDGET_1 -+#undef DECLARE_LAYOUT -+} -+ -+/*! -+ \class QUiLoader -+ \inmodule QtUiTools -+ -+ \brief The QUiLoader class enables standalone applications to -+ dynamically create user interfaces at run-time using the -+ information stored in UI files or specified in plugin paths. -+ -+ In addition, you can customize or create your own user interface by -+ deriving your own loader class. -+ -+ If you have a custom component or an application that embeds \QD, you can -+ also use the QFormBuilder class provided by the QtDesigner module to create -+ user interfaces from UI files. -+ -+ The QUiLoader class provides a collection of functions allowing you to -+ create widgets based on the information stored in UI files (created -+ with \QD) or available in the specified plugin paths. The specified plugin -+ paths can be retrieved using the pluginPaths() function. Similarly, the -+ contents of a UI file can be retrieved using the load() function. For -+ example: -+ -+ \snippet quiloader/mywidget.cpp 0 -+ -+ \if !defined(qtforpython) -+ By including the user interface in the form's resources (\c myform.qrc), we -+ ensure that it will be present at run-time: -+ -+ \quotefile quiloader/mywidget.qrc -+ \endif -+ -+ The availableWidgets() function returns a QStringList with the class names -+ of the widgets available in the specified plugin paths. To create these -+ widgets, simply use the createWidget() function. For example: -+ -+ \snippet quiloader/main.cpp 0 -+ -+ To make a custom widget available to the loader, you can use the -+ addPluginPath() function; to remove all available widgets, you can call -+ the clearPluginPaths() function. -+ -+ The createAction(), createActionGroup(), createLayout(), and createWidget() -+ functions are used internally by the QUiLoader class whenever it has to -+ create an action, action group, layout, or widget respectively. For that -+ reason, you can subclass the QUiLoader class and reimplement these -+ functions to intervene the process of constructing a user interface. For -+ example, you might want to have a list of the actions created when loading -+ a form or creating a custom widget. -+ -+ For a complete example using the QUiLoader class, see the -+ \l{Calculator Builder Example}. -+ -+ \sa {Qt UI Tools}, QFormBuilder -+*/ -+ -+/*! -+ Creates a form loader with the given \a parent. -+*/ -+QUiLoader::QUiLoader(QObject *parent) -+ : QObject(parent), d_ptr(new QUiLoaderPrivate) -+{ -+ Q_D(QUiLoader); -+ -+#ifndef QT_NO_DATASTREAM -+ static int metaTypeId = 0; -+ if (!metaTypeId) { -+ metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); -+ } -+#endif // QT_NO_DATASTREAM -+ d->builder.loader = this; -+ -+#if QT_CONFIG(library) -+ QStringList paths; -+ const QStringList &libraryPaths = QApplication::libraryPaths(); -+ for (const QString &path : libraryPaths) { -+ QString libPath = path; -+ libPath += QDir::separator(); -+ libPath += QStringLiteral("designer"); -+ paths.append(libPath); -+ } -+ -+ d->builder.setPluginPath(paths); -+#endif // QT_CONFIG(library) -+} -+ -+/*! -+ Destroys the loader. -+*/ -+QUiLoader::~QUiLoader() = default; -+ -+/*! -+ Loads a form from the given \a device and creates a new widget with the -+ given \a parentWidget to hold its contents. -+ -+ \sa createWidget(), errorString() -+*/ -+QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) -+{ -+ Q_D(QUiLoader); -+ // QXmlStreamReader will report errors on open failure. -+ if (!device->isOpen()) -+ device->open(QIODevice::ReadOnly|QIODevice::Text); -+ return d->builder.load(device, parentWidget); -+} -+ -+/*! -+ Returns a list naming the paths in which the loader will search when -+ locating custom widget plugins. -+ -+ \sa addPluginPath(), clearPluginPaths() -+*/ -+QStringList QUiLoader::pluginPaths() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.pluginPaths(); -+} -+ -+/*! -+ Clears the list of paths in which the loader will search when locating -+ plugins. -+ -+ \sa addPluginPath(), pluginPaths() -+*/ -+void QUiLoader::clearPluginPaths() -+{ -+ Q_D(QUiLoader); -+ d->builder.clearPluginPaths(); -+} -+ -+/*! -+ Adds the given \a path to the list of paths in which the loader will search -+ when locating plugins. -+ -+ \sa pluginPaths(), clearPluginPaths() -+*/ -+void QUiLoader::addPluginPath(const QString &path) -+{ -+ Q_D(QUiLoader); -+ d->builder.addPluginPath(path); -+} -+ -+/*! -+ Creates a new widget with the given \a parent and \a name using the class -+ specified by \a className. You can use this function to create any of the -+ widgets returned by the availableWidgets() function. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa availableWidgets(), load() -+*/ -+QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateWidget(className, parent, name); -+} -+ -+/*! -+ Creates a new layout with the given \a parent and \a name using the class -+ specified by \a className. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa createWidget(), load() -+*/ -+QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateLayout(className, parent, name); -+} -+ -+/*! -+ Creates a new action group with the given \a parent and \a name. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa createAction(), createWidget(), load() -+ */ -+QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateActionGroup(parent, name); -+} -+ -+/*! -+ Creates a new action with the given \a parent and \a name. -+ -+ The function is also used internally by the QUiLoader class whenever it -+ creates a widget. Hence, you can subclass QUiLoader and reimplement this -+ function to intervene process of constructing a user interface or widget. -+ However, in your implementation, ensure that you call QUiLoader's version -+ first. -+ -+ \sa createActionGroup(), createWidget(), load() -+*/ -+QAction *QUiLoader::createAction(QObject *parent, const QString &name) -+{ -+ Q_D(QUiLoader); -+ return d->builder.defaultCreateAction(parent, name); -+} -+ -+/*! -+ Returns a list naming all available widgets that can be built using the -+ createWidget() function, i.e all the widgets specified within the given -+ plugin paths. -+ -+ \sa pluginPaths(), createWidget() -+ -+*/ -+QStringList QUiLoader::availableWidgets() const -+{ -+ Q_D(const QUiLoader); -+ -+ d->setupWidgetMap(); -+ widget_map available = *g_widgets(); -+ -+ const auto &customWidgets = d->builder.customWidgets(); -+ for (QDesignerCustomWidgetInterface *plugin : customWidgets) -+ available.insert(plugin->name(), true); -+ -+ return available.keys(); -+} -+ -+ -+/*! -+ \since 4.5 -+ Returns a list naming all available layouts that can be built using the -+ createLayout() function -+ -+ \sa createLayout() -+*/ -+ -+QStringList QUiLoader::availableLayouts() const -+{ -+ QStringList rc; -+#define DECLARE_WIDGET(a, b) -+#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a)); -+ -+#include "widgets.table" -+ -+#undef DECLARE_WIDGET -+#undef DECLARE_LAYOUT -+ return rc; -+} -+ -+/*! -+ Sets the working directory of the loader to \a dir. The loader will look -+ for other resources, such as icons and resource files, in paths relative to -+ this directory. -+ -+ \sa workingDirectory() -+*/ -+ -+void QUiLoader::setWorkingDirectory(const QDir &dir) -+{ -+ Q_D(QUiLoader); -+ d->builder.setWorkingDirectory(dir); -+} -+ -+/*! -+ Returns the working directory of the loader. -+ -+ \sa setWorkingDirectory() -+*/ -+ -+QDir QUiLoader::workingDirectory() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.workingDirectory(); -+} -+/*! -+ \since 4.5 -+ -+ If \a enabled is true, user interfaces loaded by this loader will -+ automatically retranslate themselves upon receiving a language change -+ event. Otherwise, the user interfaces will not be retranslated. -+ -+ \sa isLanguageChangeEnabled() -+*/ -+ -+void QUiLoader::setLanguageChangeEnabled(bool enabled) -+{ -+ Q_D(QUiLoader); -+ d->builder.dynamicTr = enabled; -+} -+ -+/*! -+ \since 4.5 -+ -+ Returns true if dynamic retranslation on language change is enabled; -+ returns false otherwise. -+ -+ \sa setLanguageChangeEnabled() -+*/ -+ -+bool QUiLoader::isLanguageChangeEnabled() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.dynamicTr; -+} -+ -+/*! -+ \internal -+ \since 4.5 -+ -+ If \a enabled is true, user interfaces loaded by this loader will be -+ translated. Otherwise, the user interfaces will not be translated. -+ -+ \note This is orthogonal to languageChangeEnabled. -+ -+ \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() -+*/ -+ -+void QUiLoader::setTranslationEnabled(bool enabled) -+{ -+ Q_D(QUiLoader); -+ d->builder.trEnabled = enabled; -+} -+ -+/*! -+ \internal -+ \since 4.5 -+ -+ Returns true if translation is enabled; returns false otherwise. -+ -+ \sa setTranslationEnabled() -+*/ -+ -+bool QUiLoader::isTranslationEnabled() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.trEnabled; -+} -+ -+/*! -+ Returns a human-readable description of the last error occurred in load(). -+ -+ \since 5.0 -+ \sa load() -+*/ -+ -+QString QUiLoader::errorString() const -+{ -+ Q_D(const QUiLoader); -+ return d->builder.errorString(); -+} -+ -+QT_END_NAMESPACE -+ -+#include "quiloader.moc" -diff --git x/qttools/src/designer/src/uitools/quiloader.h y/qttools/src/designer/src/uitools/quiloader.h -new file mode 100644 -index 000000000..742b5606f ---- /dev/null -+++ y/qttools/src/designer/src/uitools/quiloader.h -@@ -0,0 +1,61 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+#ifndef QUILOADER_H -+#define QUILOADER_H -+ -+#include -+#include -+#include -+ -+QT_BEGIN_NAMESPACE -+ -+class QWidget; -+class QLayout; -+class QAction; -+class QActionGroup; -+class QString; -+class QIODevice; -+class QDir; -+ -+class QUiLoaderPrivate; -+class Q_UITOOLS_EXPORT QUiLoader : public QObject -+{ -+ Q_OBJECT -+public: -+ explicit QUiLoader(QObject *parent = nullptr); -+ ~QUiLoader() override; -+ -+ QStringList pluginPaths() const; -+ void clearPluginPaths(); -+ void addPluginPath(const QString &path); -+ -+ QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr); -+ QStringList availableWidgets() const; -+ QStringList availableLayouts() const; -+ -+ virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString()); -+ virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString()); -+ virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString()); -+ virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString()); -+ -+ void setWorkingDirectory(const QDir &dir); -+ QDir workingDirectory() const; -+ -+ void setLanguageChangeEnabled(bool enabled); -+ bool isLanguageChangeEnabled() const; -+ -+ void setTranslationEnabled(bool enabled); -+ bool isTranslationEnabled() const; -+ -+ QString errorString() const; -+ -+private: -+ QScopedPointer d_ptr; -+ Q_DECLARE_PRIVATE(QUiLoader) -+ Q_DISABLE_COPY_MOVE(QUiLoader) -+}; -+ -+QT_END_NAMESPACE -+ -+#endif // QUILOADER_H -diff --git x/qttools/src/designer/src/uitools/quiloader_p.h y/qttools/src/designer/src/uitools/quiloader_p.h -new file mode 100644 -index 000000000..efd943217 ---- /dev/null -+++ y/qttools/src/designer/src/uitools/quiloader_p.h -@@ -0,0 +1,77 @@ -+// Copyright (C) 2020 The Qt Company Ltd. -+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -+ -+#ifndef QUILOADER_P_H -+#define QUILOADER_P_H -+ -+// -+// W A R N I N G -+// ------------- -+// -+// This file is not part of the Qt API. It exists purely as an -+// implementation detail. This header file may change from version to -+// version without notice, or even be removed. -+// -+// We mean it. -+// -+ -+#include -+#include -+#include -+ -+QT_FORWARD_DECLARE_CLASS(QDataStream) -+ -+// This file is here for use by the form preview in Linguist. If you change anything -+// here or in the code which uses it, remember to adapt Linguist accordingly. -+ -+#define PROP_GENERIC_PREFIX "_q_notr_" -+#define PROP_TOOLITEMTEXT "_q_toolItemText_notr" -+#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr" -+#define PROP_TABPAGETEXT "_q_tabPageText_notr" -+#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr" -+#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr" -+ -+QT_BEGIN_NAMESPACE -+ -+class Q_UITOOLS_EXPORT QUiTranslatableStringValue -+{ -+public: -+ QByteArray value() const { return m_value; } -+ void setValue(const QByteArray &value) { m_value = value; } -+ QByteArray qualifier() const { return m_qualifier; } -+ void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; } -+ -+ QString translate(const QByteArray &className, bool idBased) const; -+ -+private: -+ QByteArray m_value; -+ QByteArray m_qualifier; // Comment or ID for id-based tr(). -+}; -+ -+#ifndef QT_NO_DATASTREAM -+Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); -+Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); -+#endif // QT_NO_DATASTREAM -+ -+struct QUiItemRolePair { -+ int realRole; -+ int shadowRole; -+}; -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+namespace QFormInternal -+{ -+#endif -+ -+extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; -+ -+#ifdef QFORMINTERNAL_NAMESPACE -+} -+#endif -+ -+QT_END_NAMESPACE -+ -+Q_DECLARE_METATYPE(QUiTranslatableStringValue) -+ -+ -+#endif // QUILOADER_P_H -diff --git x/qttools/src/uiplugin/CMakeLists.txt y/qttools/src/uiplugin/CMakeLists.txt -deleted file mode 100644 -index 4fedf8e33..000000000 ---- x/qttools/src/uiplugin/CMakeLists.txt -+++ /dev/null -@@ -1,27 +0,0 @@ --# Generated from uiplugin.pro. -- --##################################################################### --## UiPlugin Module: --##################################################################### -- --qt_internal_add_module(UiPlugin -- NO_PRIVATE_MODULE -- HEADER_MODULE -- QMAKE_MODULE_CONFIG designer_defines -- PUBLIC_LIBRARIES -- Qt::Core -- Qt::Gui -- Qt::Widgets --) -- --# special case begin --set(is_plugin "$") --target_compile_definitions( -- UiPlugin -- INTERFACE -- $<$:QDESIGNER_EXPORT_WIDGETS> --) --# special case end -- --#### Keys ignored in scope 1:.:.:uiplugin.pro:: --# MODULE_CONFIG = "designer_defines" -diff --git x/qttools/src/uiplugin/customwidget.h y/qttools/src/uiplugin/customwidget.h -deleted file mode 100644 -index 2a47a32f8..000000000 ---- x/qttools/src/uiplugin/customwidget.h -+++ /dev/null -@@ -1,62 +0,0 @@ --// Copyright (C) 2016 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -- --#ifndef CUSTOMWIDGET_H --#define CUSTOMWIDGET_H -- --#include --#include --#include -- --QT_BEGIN_NAMESPACE -- --class QWidget; --class QDesignerFormEditorInterface; -- --class QDesignerCustomWidgetInterface --{ --public: -- virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable -- -- virtual QString name() const = 0; -- virtual QString group() const = 0; -- virtual QString toolTip() const = 0; -- virtual QString whatsThis() const = 0; -- virtual QString includeFile() const = 0; -- virtual QIcon icon() const = 0; -- -- virtual bool isContainer() const = 0; -- -- virtual QWidget *createWidget(QWidget *parent) = 0; -- -- virtual bool isInitialized() const { return false; } -- virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); } -- -- virtual QString domXml() const -- { -- return QString::fromUtf8("") -- .arg(name()).arg(name().toLower()); -- } -- -- virtual QString codeTemplate() const { return QString(); } --}; -- --#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface" -- --Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid) -- --class QDesignerCustomWidgetCollectionInterface --{ --public: -- virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable -- -- virtual QList customWidgets() const = 0; --}; -- --#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface" -- --Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid) -- --QT_END_NAMESPACE -- --#endif // CUSTOMWIDGET_H -diff --git x/qttools/src/uiplugin/customwidget.qdoc y/qttools/src/uiplugin/customwidget.qdoc -deleted file mode 100644 -index 557e9a454..000000000 ---- x/qttools/src/uiplugin/customwidget.qdoc -+++ /dev/null -@@ -1,269 +0,0 @@ --// Copyright (C) 2016 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only -- --/*! -- \class QDesignerCustomWidgetInterface -- -- \brief The QDesignerCustomWidgetInterface class enables Qt Designer -- to access and construct custom widgets. -- -- \inmodule QtDesigner -- -- QDesignerCustomWidgetInterface provides a custom widget with an -- interface. The class contains a set of functions that must be subclassed -- to return basic information about the widget, such as its class name and -- the name of its header file. Other functions must be implemented to -- initialize the plugin when it is loaded, and to construct instances of -- the custom widget for \QD to use. -- -- When implementing a custom widget you must subclass -- QDesignerCustomWidgetInterface to expose your widget to \QD. For -- example, this is the declaration for the plugin used in the -- \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that -- enables an analog clock custom widget to be used by \QD: -- -- \snippet customwidgetplugin/customwidgetplugin.h 0 -- -- Note that the only part of the class definition that is specific -- to this particular custom widget is the class name. In addition, -- since we are implementing an interface, we must ensure that it's -- made known to the meta object system using the Q_INTERFACES() -- macro. This enables \QD to use the qobject_cast() function to -- query for supported interfaces using nothing but a QObject -- pointer. -- -- After \QD loads a custom widget plugin, it calls the interface's -- initialize() function to enable it to set up any resources that it -- may need. This function is called with a QDesignerFormEditorInterface -- parameter that provides the plugin with a gateway to all of \QD's API. -- -- \QD constructs instances of the custom widget by calling the plugin's -- createWidget() function with a suitable parent widget. Plugins must -- construct and return an instance of a custom widget with the specified -- parent widget. -- -- Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA() -- macro. For example, if a library called \c libcustomwidgetplugin.so -- (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget -- class called \c MyCustomWidget, we can export it by adding the -- following line to the file containing the plugin header: -- -- \snippet plugins/doc_src_qtdesigner.cpp 14 -- -- This macro ensures that \QD can access and construct the custom widget. -- Without this macro, there is no way for \QD to use it. -- -- When implementing a custom widget plugin, you build it as a -- separate library. If you want to include several custom widget -- plugins in the same library, you must in addition subclass -- QDesignerCustomWidgetCollectionInterface. -- -- \warning If your custom widget plugin contains QVariant -- properties, be aware that only the following \l -- {QVariant::Type}{types} are supported: -- -- \list -- \li QVariant::ByteArray -- \li QVariant::Bool -- \li QVariant::Color -- \li QVariant::Cursor -- \li QVariant::Date -- \li QVariant::DateTime -- \li QVariant::Double -- \li QVariant::Int -- \li QVariant::Point -- \li QVariant::Rect -- \li QVariant::Size -- \li QVariant::SizePolicy -- \li QVariant::String -- \li QVariant::Time -- \li QVariant::UInt -- \endlist -- -- For a complete example using the QDesignerCustomWidgetInterface -- class, see the \l {customwidgetplugin}{Custom Widget -- Example}. The example shows how to create a custom widget plugin -- for \QD. -- -- \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer} --*/ -- --/*! -- \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface() -- -- Destroys the custom widget interface. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::name() const -- -- Returns the class name of the custom widget supplied by the interface. -- -- The name returned \e must be identical to the class name used for the -- custom widget. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::group() const -- -- Returns the name of the group to which the custom widget belongs. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::toolTip() const -- -- Returns a short description of the widget that can be used by \QD -- in a tool tip. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::whatsThis() const -- -- Returns a description of the widget that can be used by \QD in -- "What's This?" help for the widget. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::includeFile() const -- -- Returns the path to the include file that \l uic uses when -- creating code for the custom widget. --*/ -- --/*! -- \fn QIcon QDesignerCustomWidgetInterface::icon() const -- -- Returns the icon used to represent the custom widget in \QD's -- widget box. --*/ -- --/*! -- \fn bool QDesignerCustomWidgetInterface::isContainer() const -- -- Returns true if the custom widget is intended to be used as a -- container; otherwise returns false. -- -- Most custom widgets are not used to hold other widgets, so their -- implementations of this function will return false, but custom -- containers will return true to ensure that they behave correctly -- in \QD. --*/ -- --/*! -- \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent) -- -- Returns a new instance of the custom widget, with the given \a -- parent. --*/ -- --/*! -- \fn bool QDesignerCustomWidgetInterface::isInitialized() const -- -- Returns true if the widget has been initialized; otherwise returns -- false. -- -- \sa initialize() --*/ -- --/*! -- \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) -- -- Initializes the widget for use with the specified \a formEditor -- interface. -- -- \sa isInitialized() --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::domXml() const -- -- Returns the XML that is used to describe the custom widget's -- properties to \QD. --*/ -- --/*! -- \fn QString QDesignerCustomWidgetInterface::codeTemplate() const -- -- This function is reserved for future use by \QD. -- -- \omit -- Returns the code template that \QD includes in forms that contain -- the custom widget when they are saved. -- \endomit --*/ -- --/*! -- \macro QDESIGNER_WIDGET_EXPORT -- \relates QDesignerCustomWidgetInterface -- \since 4.1 -- -- This macro is used when defining custom widgets to ensure that they are -- correctly exported from plugins for use with \QD. -- -- On some platforms, the symbols required by \QD to create new widgets -- are removed from plugins by the build system, making them unusable. -- Using this macro ensures that the symbols are retained on those platforms, -- and has no side effects on other platforms. -- -- For example, the \l{worldtimeclockplugin}{World Time Clock Plugin} -- example exports a custom widget class with the following declaration: -- -- \snippet worldtimeclockplugin/worldtimeclock.h 0 -- \dots -- \snippet worldtimeclockplugin/worldtimeclock.h 2 -- -- \sa {Creating Custom Widgets for Qt Designer} --*/ -- -- -- -- -- --/*! -- \class QDesignerCustomWidgetCollectionInterface -- -- \brief The QDesignerCustomWidgetCollectionInterface class allows -- you to include several custom widgets in one single library. -- -- \inmodule QtDesigner -- -- When implementing a custom widget plugin, you build it as a -- separate library. If you want to include several custom widget -- plugins in the same library, you must in addition subclass -- QDesignerCustomWidgetCollectionInterface. -- -- QDesignerCustomWidgetCollectionInterface contains one single -- function returning a list of the collection's -- QDesignerCustomWidgetInterface objects. For example, if you have -- several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and -- \c CustomWidgetThree, the class definition may look like this: -- -- \snippet plugins/doc_src_qtdesigner.cpp 12 -- -- In the class constructor you add the interfaces to your custom -- widgets to the list which you return in the customWidgets() -- function: -- -- \snippet plugins/doc_src_qtdesigner.cpp 13 -- -- Note that instead of exporting each custom widget plugin using the -- Q_PLUGIN_METADATA() macro, you export the entire collection. The -- Q_PLUGIN_METADATA() macro ensures that \QD can access and construct -- the custom widgets. Without this macro, there is no way for \QD to -- use them. -- -- \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for -- Qt Designer} --*/ -- --/*! -- \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() { -- -- Destroys the custom widget collection interface. --*/ -- --/*! -- \fn QList QDesignerCustomWidgetCollectionInterface::customWidgets() const -- -- Returns a list of interfaces to the collection's custom widgets. --*/ -diff --git x/qttools/src/uiplugin/qdesignerexportwidget.h y/qttools/src/uiplugin/qdesignerexportwidget.h -deleted file mode 100644 -index d90e9b217..000000000 ---- x/qttools/src/uiplugin/qdesignerexportwidget.h -+++ /dev/null -@@ -1,24 +0,0 @@ --// Copyright (C) 2016 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -- --#ifndef QDESIGNEREXPORTWIDGET_H --#define QDESIGNEREXPORTWIDGET_H -- --#include -- --QT_BEGIN_NAMESPACE -- --#if 0 --// pragma for syncqt, don't remove. --#pragma qt_class(QDesignerExportWidget) --#endif -- --#if defined(QDESIGNER_EXPORT_WIDGETS) --# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT --#else --# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT --#endif -- --QT_END_NAMESPACE -- --#endif //QDESIGNEREXPORTWIDGET_H -diff --git x/qttools/src/uitools/CMakeLists.txt y/qttools/src/uitools/CMakeLists.txt -deleted file mode 100644 -index 448bd1840..000000000 ---- x/qttools/src/uitools/CMakeLists.txt -+++ /dev/null -@@ -1,47 +0,0 @@ --# Generated from uitools.pro. -- --##################################################################### --## UiTools Module: --##################################################################### -- --qt_internal_add_module(UiTools -- SOURCES -- ../designer/src/lib/uilib/abstractformbuilder.cpp ../designer/src/lib/uilib/abstractformbuilder.h -- ../designer/src/lib/uilib/formbuilder.cpp ../designer/src/lib/uilib/formbuilder.h -- ../designer/src/lib/uilib/formbuilderextra.cpp ../designer/src/lib/uilib/formbuilderextra_p.h -- ../designer/src/lib/uilib/properties.cpp ../designer/src/lib/uilib/properties_p.h -- ../designer/src/lib/uilib/resourcebuilder.cpp ../designer/src/lib/uilib/resourcebuilder_p.h -- ../designer/src/lib/uilib/textbuilder.cpp ../designer/src/lib/uilib/textbuilder_p.h -- ../designer/src/lib/uilib/ui4.cpp ../designer/src/lib/uilib/ui4_p.h -- quiloader.cpp quiloader.h -- DEFINES -- QFORMINTERNAL_NAMESPACE -- QT_DESIGNER -- QT_DESIGNER_STATIC -- QT_USE_QSTRINGBUILDER -- INCLUDE_DIRECTORIES -- ../designer/src/lib/uilib -- LIBRARIES -- Qt::UiPlugin -- PUBLIC_LIBRARIES -- Qt::Core -- Qt::Gui -- Qt::Widgets --) -- --## Scopes: --##################################################################### -- --qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets -- PUBLIC_LIBRARIES -- Qt::OpenGLWidgets --) -- --qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGL -- LIBRARIES -- Qt::OpenGL --) --qt_internal_add_docs(UiTools -- doc/qtuitools.qdocconf --) -- -diff --git x/qttools/src/uitools/qtuitoolsglobal.h y/qttools/src/uitools/qtuitoolsglobal.h -deleted file mode 100644 -index a2f967dee..000000000 ---- x/qttools/src/uitools/qtuitoolsglobal.h -+++ /dev/null -@@ -1,24 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- --#ifndef QTUITOOLSGLOBAL_H --#define QTUITOOLSGLOBAL_H -- --#include -- --QT_BEGIN_NAMESPACE -- --#ifndef QT_STATIC --# if defined(QT_BUILD_UITOOLS_LIB) --# define Q_UITOOLS_EXPORT Q_DECL_EXPORT --# else --# define Q_UITOOLS_EXPORT Q_DECL_IMPORT --# endif --#else --# define Q_UITOOLS_EXPORT --#endif -- --QT_END_NAMESPACE -- --#endif // QTUITOOLSGLOBAL_H -- -diff --git x/qttools/src/uitools/quiloader.cpp y/qttools/src/uitools/quiloader.cpp -deleted file mode 100644 -index a06d4717b..000000000 ---- x/qttools/src/uitools/quiloader.cpp -+++ /dev/null -@@ -1,914 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- -- --#include "quiloader.h" --#include "quiloader_p.h" -- --#include -- --#include --#include --#include --#include -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include -- --#include --#include --#include --#include --#include -- --QT_BEGIN_NAMESPACE -- --typedef QMap widget_map; --Q_GLOBAL_STATIC(widget_map, g_widgets) -- --class QUiLoader; --class QUiLoaderPrivate; -- --#ifndef QT_NO_DATASTREAM --// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based --// mime data when dragging items in views with QAbstractItemView::InternalMove. --QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) --{ -- out << s.qualifier() << s.value(); -- return out; --} -- --QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) --{ -- QByteArray qualifier, value; -- in >> qualifier >> value; -- s.setQualifier(qualifier); -- s.setValue(value); -- return in; --} --#endif // QT_NO_DATASTREAM -- --QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const --{ -- return idBased -- ? qtTrId(m_qualifier.constData()) -- : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData()); --} -- --#ifdef QFORMINTERNAL_NAMESPACE --namespace QFormInternal --{ --#endif -- --class TranslatingTextBuilder : public QTextBuilder --{ --public: -- explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) : -- m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {} -- -- QVariant loadText(const DomProperty *icon) const override; -- -- QVariant toNativeValue(const QVariant &value) const override; -- -- bool idBased() const { return m_idBased; } -- --private: -- bool m_idBased; -- bool m_trEnabled; -- QByteArray m_className; --}; -- --QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const --{ -- const DomString *str = text->elementString(); -- if (!str) -- return QVariant(); -- if (str->hasAttributeNotr()) { -- const QString notr = str->attributeNotr(); -- if (notr == QStringLiteral("true") || notr == QStringLiteral("yes")) -- return QVariant::fromValue(str->text()); -- } -- QUiTranslatableStringValue strVal; -- strVal.setValue(str->text().toUtf8()); -- if (m_idBased) -- strVal.setQualifier(str->attributeId().toUtf8()); -- else if (str->hasAttributeComment()) -- strVal.setQualifier(str->attributeComment().toUtf8()); -- return QVariant::fromValue(strVal); --} -- --QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const --{ -- if (value.canConvert()) { -- QUiTranslatableStringValue tsv = qvariant_cast(value); -- if (!m_trEnabled) -- return QString::fromUtf8(tsv.value().constData()); -- return QVariant::fromValue(tsv.translate(m_className, m_idBased)); -- } -- if (value.canConvert()) -- return QVariant::fromValue(qvariant_cast(value)); -- return value; --} -- --// This is "exported" to linguist --const QUiItemRolePair qUiItemRoles[] = { -- { Qt::DisplayRole, Qt::DisplayPropertyRole }, --#if QT_CONFIG(tooltip) -- { Qt::ToolTipRole, Qt::ToolTipPropertyRole }, --#endif --#if QT_CONFIG(statustip) -- { Qt::StatusTipRole, Qt::StatusTipPropertyRole }, --#endif --#if QT_CONFIG(whatsthis) -- { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole }, --#endif -- { -1 , -1 } --}; -- --static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased) --{ -- const QUiItemRolePair *irs = qUiItemRoles; -- -- int cnt = item->columnCount(); -- for (int i = 0; i < cnt; ++i) { -- for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -- QVariant v = item->data(i, irs[j].shadowRole); -- if (v.isValid()) { -- QUiTranslatableStringValue tsv = qvariant_cast(v); -- item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased)); -- } -- } -- } -- -- cnt = item->childCount(); -- for (int i = 0; i < cnt; ++i) -- recursiveReTranslate(item->child(i), class_name, idBased); --} -- --template --static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased) --{ -- const QUiItemRolePair *irs = qUiItemRoles; -- -- for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { -- QVariant v = item->data(irs[j].shadowRole); -- if (v.isValid()) { -- QUiTranslatableStringValue tsv = qvariant_cast(v); -- item->setData(irs[j].realRole, tsv.translate(class_name, idBased)); -- } -- } --} -- --static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased) --{ -- if (item) -- reTranslateWidgetItem(item, class_name, idBased); --} -- --#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \ -- do { \ -- QVariant v = mainWidget->widget(i)->property(propName); \ -- if (v.isValid()) { \ -- QUiTranslatableStringValue tsv = qvariant_cast(v); \ -- mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \ -- } \ -- } while (0) -- --class TranslationWatcher: public QObject --{ -- Q_OBJECT -- --public: -- explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased): -- QObject(parent), -- m_className(className), -- m_idBased(idBased) -- { -- } -- -- bool eventFilter(QObject *o, QEvent *event) override -- { -- if (event->type() == QEvent::LanguageChange) { -- const auto &dynamicPropertyNames = o->dynamicPropertyNames(); -- for (const QByteArray &prop : dynamicPropertyNames) { -- if (prop.startsWith(PROP_GENERIC_PREFIX)) { -- const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); -- const QUiTranslatableStringValue tsv = -- qvariant_cast(o->property(prop)); -- o->setProperty(propName, tsv.translate(m_className, m_idBased)); -- } -- } -- if (0) { --#if QT_CONFIG(tabwidget) -- } else if (QTabWidget *tabw = qobject_cast(o)) { -- const int cnt = tabw->count(); -- for (int i = 0; i < cnt; ++i) { -- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT); --#if QT_CONFIG(tooltip) -- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP); --# endif --#if QT_CONFIG(whatsthis) -- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); --# endif -- } --#endif --#if QT_CONFIG(listwidget) -- } else if (QListWidget *listw = qobject_cast(o)) { -- const int cnt = listw->count(); -- for (int i = 0; i < cnt; ++i) -- reTranslateWidgetItem(listw->item(i), m_className, m_idBased); --#endif --#if QT_CONFIG(treewidget) -- } else if (QTreeWidget *treew = qobject_cast(o)) { -- if (QTreeWidgetItem *item = treew->headerItem()) -- recursiveReTranslate(item, m_className, m_idBased); -- const int cnt = treew->topLevelItemCount(); -- for (int i = 0; i < cnt; ++i) { -- QTreeWidgetItem *item = treew->topLevelItem(i); -- recursiveReTranslate(item, m_className, m_idBased); -- } --#endif --#if QT_CONFIG(tablewidget) -- } else if (QTableWidget *tablew = qobject_cast(o)) { -- const int row_cnt = tablew->rowCount(); -- const int col_cnt = tablew->columnCount(); -- for (int j = 0; j < col_cnt; ++j) -- reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased); -- for (int i = 0; i < row_cnt; ++i) { -- reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased); -- for (int j = 0; j < col_cnt; ++j) -- reTranslateTableItem(tablew->item(i, j), m_className, m_idBased); -- } --#endif --#if QT_CONFIG(combobox) -- } else if (QComboBox *combow = qobject_cast(o)) { -- if (!qobject_cast(o)) { -- const int cnt = combow->count(); -- for (int i = 0; i < cnt; ++i) { -- const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole); -- if (v.isValid()) { -- QUiTranslatableStringValue tsv = qvariant_cast(v); -- combow->setItemText(i, tsv.translate(m_className, m_idBased)); -- } -- } -- } --#endif --#if QT_CONFIG(toolbox) -- } else if (QToolBox *toolw = qobject_cast(o)) { -- const int cnt = toolw->count(); -- for (int i = 0; i < cnt; ++i) { -- RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT); --#if QT_CONFIG(tooltip) -- RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP); --# endif -- } --#endif -- } -- } -- return false; -- } -- --private: -- QByteArray m_className; -- bool m_idBased; --}; -- --class FormBuilderPrivate: public QFormBuilder --{ -- friend class QT_PREPEND_NAMESPACE(QUiLoader); -- friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate); -- using ParentClass = QFormBuilder; -- --public: -- QUiLoader *loader = nullptr; -- -- bool dynamicTr = false; -- bool trEnabled = true; -- -- FormBuilderPrivate() = default; -- -- QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name) -- { -- return ParentClass::createWidget(className, parent, name); -- } -- -- QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name) -- { -- return ParentClass::createLayout(className, parent, name); -- } -- -- QAction *defaultCreateAction(QObject *parent, const QString &name) -- { -- return ParentClass::createAction(parent, name); -- } -- -- QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name) -- { -- return ParentClass::createActionGroup(parent, name); -- } -- -- QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override -- { -- if (QWidget *widget = loader->createWidget(className, parent, name)) { -- widget->setObjectName(name); -- return widget; -- } -- -- return nullptr; -- } -- -- QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override -- { -- if (QLayout *layout = loader->createLayout(className, parent, name)) { -- layout->setObjectName(name); -- return layout; -- } -- -- return nullptr; -- } -- -- QActionGroup *createActionGroup(QObject *parent, const QString &name) override -- { -- if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) { -- actionGroup->setObjectName(name); -- return actionGroup; -- } -- -- return nullptr; -- } -- -- QAction *createAction(QObject *parent, const QString &name) override -- { -- if (QAction *action = loader->createAction(parent, name)) { -- action->setObjectName(name); -- return action; -- } -- -- return nullptr; -- } -- -- void applyProperties(QObject *o, const QList &properties) override; -- QWidget *create(DomUI *ui, QWidget *parentWidget) override; -- QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override; -- bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override; -- --private: -- QByteArray m_class; -- TranslationWatcher *m_trwatch = nullptr; -- bool m_idBased = false; --}; -- --static QString convertTranslatable(const DomProperty *p, const QByteArray &className, -- bool idBased, QUiTranslatableStringValue *strVal) --{ -- if (p->kind() != DomProperty::String) -- return QString(); -- const DomString *dom_str = p->elementString(); -- if (!dom_str) -- return QString(); -- if (dom_str->hasAttributeNotr()) { -- const QString notr = dom_str->attributeNotr(); -- if (notr == QStringLiteral("yes") || notr == QStringLiteral("true")) -- return QString(); -- } -- strVal->setValue(dom_str->text().toUtf8()); -- strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8()); -- if (strVal->value().isEmpty() && strVal->qualifier().isEmpty()) -- return QString(); -- return strVal->translate(className, idBased); --} -- --void FormBuilderPrivate::applyProperties(QObject *o, const QList &properties) --{ -- QFormBuilder::applyProperties(o, properties); -- -- if (!m_trwatch) -- m_trwatch = new TranslationWatcher(o, m_class, m_idBased); -- -- if (properties.isEmpty()) -- return; -- -- // Unlike string item roles, string properties are not loaded via the textBuilder -- // (as they are "shadowed" by the property sheets in designer). So do the initial -- // translation here. -- bool anyTrs = false; -- for (const DomProperty *p : properties) { -- QUiTranslatableStringValue strVal; -- const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); -- if (text.isEmpty()) -- continue; -- const QByteArray name = p->attributeName().toUtf8(); -- if (dynamicTr) { -- const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name); -- o->setProperty(dynname, QVariant::fromValue(strVal)); -- anyTrs = trEnabled; -- } -- if (p->elementString()->text() != text) -- o->setProperty(name, text); -- } -- if (anyTrs) -- o->installEventFilter(m_trwatch); --} -- --QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget) --{ -- m_class = ui->elementClass().toUtf8(); -- m_trwatch = nullptr; -- m_idBased = ui->attributeIdbasedtr(); -- setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class)); -- return QFormBuilder::create(ui, parentWidget); --} -- --QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget) --{ -- QWidget *w = QFormBuilder::create(ui_widget, parentWidget); -- if (w == nullptr) -- return nullptr; -- -- if (0) { --#if QT_CONFIG(tabwidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(listwidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(treewidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(tablewidget) -- } else if (qobject_cast(w)) { --#endif --#if QT_CONFIG(combobox) -- } else if (qobject_cast(w)) { -- if (qobject_cast(w)) -- return w; --#endif --#if QT_CONFIG(toolbox) -- } else if (qobject_cast(w)) { --#endif -- } else { -- return w; -- } -- if (dynamicTr && trEnabled) -- w->installEventFilter(m_trwatch); -- return w; --} -- --#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \ -- do { \ -- if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \ -- QUiTranslatableStringValue strVal; \ -- const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \ -- if (!text.isEmpty()) { \ -- if (dynamicTr) \ -- mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \ -- mainWidget->setter(i, text); \ -- } \ -- } \ -- } while (0) -- --bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) --{ -- if (parentWidget == nullptr) -- return true; -- -- if (!ParentClass::addItem(ui_widget, widget, parentWidget)) -- return false; -- -- // Check special cases. First: Custom container -- const QString className = QLatin1String(parentWidget->metaObject()->className()); -- if (!d->customWidgetAddPageMethod(className).isEmpty()) -- return true; -- -- const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); -- -- if (0) { --#if QT_CONFIG(tabwidget) -- } else if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { -- const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -- const int i = tabWidget->count() - 1; -- TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT); --#if QT_CONFIG(tooltip) -- TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP); --# endif --#if QT_CONFIG(whatsthis) -- TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); --# endif --#endif --#if QT_CONFIG(toolbox) -- } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { -- const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); -- const int i = toolBox->count() - 1; -- TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT); --#if QT_CONFIG(tooltip) -- TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP); --# endif --#endif -- } -- -- return true; --} -- --#ifdef QFORMINTERNAL_NAMESPACE --} --#endif -- --class QUiLoaderPrivate --{ --public: --#ifdef QFORMINTERNAL_NAMESPACE -- QFormInternal::FormBuilderPrivate builder; --#else -- FormBuilderPrivate builder; --#endif -- -- void setupWidgetMap() const; --}; -- --void QUiLoaderPrivate::setupWidgetMap() const --{ -- if (!g_widgets()->isEmpty()) -- return; -- --#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true); --#define DECLARE_LAYOUT(a, b) -- --#include "widgets.table" -- --#undef DECLARE_WIDGET --#undef DECLARE_WIDGET_1 --#undef DECLARE_LAYOUT --} -- --/*! -- \class QUiLoader -- \inmodule QtUiTools -- -- \brief The QUiLoader class enables standalone applications to -- dynamically create user interfaces at run-time using the -- information stored in UI files or specified in plugin paths. -- -- In addition, you can customize or create your own user interface by -- deriving your own loader class. -- -- If you have a custom component or an application that embeds \QD, you can -- also use the QFormBuilder class provided by the QtDesigner module to create -- user interfaces from UI files. -- -- The QUiLoader class provides a collection of functions allowing you to -- create widgets based on the information stored in UI files (created -- with \QD) or available in the specified plugin paths. The specified plugin -- paths can be retrieved using the pluginPaths() function. Similarly, the -- contents of a UI file can be retrieved using the load() function. For -- example: -- -- \snippet quiloader/mywidget.cpp 0 -- -- \if !defined(qtforpython) -- By including the user interface in the form's resources (\c myform.qrc), we -- ensure that it will be present at run-time: -- -- \quotefile quiloader/mywidget.qrc -- \endif -- -- The availableWidgets() function returns a QStringList with the class names -- of the widgets available in the specified plugin paths. To create these -- widgets, simply use the createWidget() function. For example: -- -- \snippet quiloader/main.cpp 0 -- -- To make a custom widget available to the loader, you can use the -- addPluginPath() function; to remove all available widgets, you can call -- the clearPluginPaths() function. -- -- The createAction(), createActionGroup(), createLayout(), and createWidget() -- functions are used internally by the QUiLoader class whenever it has to -- create an action, action group, layout, or widget respectively. For that -- reason, you can subclass the QUiLoader class and reimplement these -- functions to intervene the process of constructing a user interface. For -- example, you might want to have a list of the actions created when loading -- a form or creating a custom widget. -- -- For a complete example using the QUiLoader class, see the -- \l{Calculator Builder Example}. -- -- \sa {Qt UI Tools}, QFormBuilder --*/ -- --/*! -- Creates a form loader with the given \a parent. --*/ --QUiLoader::QUiLoader(QObject *parent) -- : QObject(parent), d_ptr(new QUiLoaderPrivate) --{ -- Q_D(QUiLoader); -- --#ifndef QT_NO_DATASTREAM -- static int metaTypeId = 0; -- if (!metaTypeId) { -- metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); -- } --#endif // QT_NO_DATASTREAM -- d->builder.loader = this; -- --#if QT_CONFIG(library) -- QStringList paths; -- const QStringList &libraryPaths = QApplication::libraryPaths(); -- for (const QString &path : libraryPaths) { -- QString libPath = path; -- libPath += QDir::separator(); -- libPath += QStringLiteral("designer"); -- paths.append(libPath); -- } -- -- d->builder.setPluginPath(paths); --#endif // QT_CONFIG(library) --} -- --/*! -- Destroys the loader. --*/ --QUiLoader::~QUiLoader() = default; -- --/*! -- Loads a form from the given \a device and creates a new widget with the -- given \a parentWidget to hold its contents. -- -- \sa createWidget(), errorString() --*/ --QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) --{ -- Q_D(QUiLoader); -- // QXmlStreamReader will report errors on open failure. -- if (!device->isOpen()) -- device->open(QIODevice::ReadOnly|QIODevice::Text); -- return d->builder.load(device, parentWidget); --} -- --/*! -- Returns a list naming the paths in which the loader will search when -- locating custom widget plugins. -- -- \sa addPluginPath(), clearPluginPaths() --*/ --QStringList QUiLoader::pluginPaths() const --{ -- Q_D(const QUiLoader); -- return d->builder.pluginPaths(); --} -- --/*! -- Clears the list of paths in which the loader will search when locating -- plugins. -- -- \sa addPluginPath(), pluginPaths() --*/ --void QUiLoader::clearPluginPaths() --{ -- Q_D(QUiLoader); -- d->builder.clearPluginPaths(); --} -- --/*! -- Adds the given \a path to the list of paths in which the loader will search -- when locating plugins. -- -- \sa pluginPaths(), clearPluginPaths() --*/ --void QUiLoader::addPluginPath(const QString &path) --{ -- Q_D(QUiLoader); -- d->builder.addPluginPath(path); --} -- --/*! -- Creates a new widget with the given \a parent and \a name using the class -- specified by \a className. You can use this function to create any of the -- widgets returned by the availableWidgets() function. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa availableWidgets(), load() --*/ --QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateWidget(className, parent, name); --} -- --/*! -- Creates a new layout with the given \a parent and \a name using the class -- specified by \a className. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa createWidget(), load() --*/ --QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateLayout(className, parent, name); --} -- --/*! -- Creates a new action group with the given \a parent and \a name. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa createAction(), createWidget(), load() -- */ --QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateActionGroup(parent, name); --} -- --/*! -- Creates a new action with the given \a parent and \a name. -- -- The function is also used internally by the QUiLoader class whenever it -- creates a widget. Hence, you can subclass QUiLoader and reimplement this -- function to intervene process of constructing a user interface or widget. -- However, in your implementation, ensure that you call QUiLoader's version -- first. -- -- \sa createActionGroup(), createWidget(), load() --*/ --QAction *QUiLoader::createAction(QObject *parent, const QString &name) --{ -- Q_D(QUiLoader); -- return d->builder.defaultCreateAction(parent, name); --} -- --/*! -- Returns a list naming all available widgets that can be built using the -- createWidget() function, i.e all the widgets specified within the given -- plugin paths. -- -- \sa pluginPaths(), createWidget() -- --*/ --QStringList QUiLoader::availableWidgets() const --{ -- Q_D(const QUiLoader); -- -- d->setupWidgetMap(); -- widget_map available = *g_widgets(); -- -- const auto &customWidgets = d->builder.customWidgets(); -- for (QDesignerCustomWidgetInterface *plugin : customWidgets) -- available.insert(plugin->name(), true); -- -- return available.keys(); --} -- -- --/*! -- \since 4.5 -- Returns a list naming all available layouts that can be built using the -- createLayout() function -- -- \sa createLayout() --*/ -- --QStringList QUiLoader::availableLayouts() const --{ -- QStringList rc; --#define DECLARE_WIDGET(a, b) --#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a)); -- --#include "widgets.table" -- --#undef DECLARE_WIDGET --#undef DECLARE_LAYOUT -- return rc; --} -- --/*! -- Sets the working directory of the loader to \a dir. The loader will look -- for other resources, such as icons and resource files, in paths relative to -- this directory. -- -- \sa workingDirectory() --*/ -- --void QUiLoader::setWorkingDirectory(const QDir &dir) --{ -- Q_D(QUiLoader); -- d->builder.setWorkingDirectory(dir); --} -- --/*! -- Returns the working directory of the loader. -- -- \sa setWorkingDirectory() --*/ -- --QDir QUiLoader::workingDirectory() const --{ -- Q_D(const QUiLoader); -- return d->builder.workingDirectory(); --} --/*! -- \since 4.5 -- -- If \a enabled is true, user interfaces loaded by this loader will -- automatically retranslate themselves upon receiving a language change -- event. Otherwise, the user interfaces will not be retranslated. -- -- \sa isLanguageChangeEnabled() --*/ -- --void QUiLoader::setLanguageChangeEnabled(bool enabled) --{ -- Q_D(QUiLoader); -- d->builder.dynamicTr = enabled; --} -- --/*! -- \since 4.5 -- -- Returns true if dynamic retranslation on language change is enabled; -- returns false otherwise. -- -- \sa setLanguageChangeEnabled() --*/ -- --bool QUiLoader::isLanguageChangeEnabled() const --{ -- Q_D(const QUiLoader); -- return d->builder.dynamicTr; --} -- --/*! -- \internal -- \since 4.5 -- -- If \a enabled is true, user interfaces loaded by this loader will be -- translated. Otherwise, the user interfaces will not be translated. -- -- \note This is orthogonal to languageChangeEnabled. -- -- \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() --*/ -- --void QUiLoader::setTranslationEnabled(bool enabled) --{ -- Q_D(QUiLoader); -- d->builder.trEnabled = enabled; --} -- --/*! -- \internal -- \since 4.5 -- -- Returns true if translation is enabled; returns false otherwise. -- -- \sa setTranslationEnabled() --*/ -- --bool QUiLoader::isTranslationEnabled() const --{ -- Q_D(const QUiLoader); -- return d->builder.trEnabled; --} -- --/*! -- Returns a human-readable description of the last error occurred in load(). -- -- \since 5.0 -- \sa load() --*/ -- --QString QUiLoader::errorString() const --{ -- Q_D(const QUiLoader); -- return d->builder.errorString(); --} -- --QT_END_NAMESPACE -- --#include "quiloader.moc" -diff --git x/qttools/src/uitools/quiloader.h y/qttools/src/uitools/quiloader.h -deleted file mode 100644 -index 742b5606f..000000000 ---- x/qttools/src/uitools/quiloader.h -+++ /dev/null -@@ -1,61 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- --#ifndef QUILOADER_H --#define QUILOADER_H -- --#include --#include --#include -- --QT_BEGIN_NAMESPACE -- --class QWidget; --class QLayout; --class QAction; --class QActionGroup; --class QString; --class QIODevice; --class QDir; -- --class QUiLoaderPrivate; --class Q_UITOOLS_EXPORT QUiLoader : public QObject --{ -- Q_OBJECT --public: -- explicit QUiLoader(QObject *parent = nullptr); -- ~QUiLoader() override; -- -- QStringList pluginPaths() const; -- void clearPluginPaths(); -- void addPluginPath(const QString &path); -- -- QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr); -- QStringList availableWidgets() const; -- QStringList availableLayouts() const; -- -- virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString()); -- virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString()); -- virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString()); -- virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString()); -- -- void setWorkingDirectory(const QDir &dir); -- QDir workingDirectory() const; -- -- void setLanguageChangeEnabled(bool enabled); -- bool isLanguageChangeEnabled() const; -- -- void setTranslationEnabled(bool enabled); -- bool isTranslationEnabled() const; -- -- QString errorString() const; -- --private: -- QScopedPointer d_ptr; -- Q_DECLARE_PRIVATE(QUiLoader) -- Q_DISABLE_COPY_MOVE(QUiLoader) --}; -- --QT_END_NAMESPACE -- --#endif // QUILOADER_H -diff --git x/qttools/src/uitools/quiloader_p.h y/qttools/src/uitools/quiloader_p.h -deleted file mode 100644 -index efd943217..000000000 ---- x/qttools/src/uitools/quiloader_p.h -+++ /dev/null -@@ -1,77 +0,0 @@ --// Copyright (C) 2020 The Qt Company Ltd. --// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -- --#ifndef QUILOADER_P_H --#define QUILOADER_P_H -- --// --// W A R N I N G --// ------------- --// --// This file is not part of the Qt API. It exists purely as an --// implementation detail. This header file may change from version to --// version without notice, or even be removed. --// --// We mean it. --// -- --#include --#include --#include -- --QT_FORWARD_DECLARE_CLASS(QDataStream) -- --// This file is here for use by the form preview in Linguist. If you change anything --// here or in the code which uses it, remember to adapt Linguist accordingly. -- --#define PROP_GENERIC_PREFIX "_q_notr_" --#define PROP_TOOLITEMTEXT "_q_toolItemText_notr" --#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr" --#define PROP_TABPAGETEXT "_q_tabPageText_notr" --#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr" --#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr" -- --QT_BEGIN_NAMESPACE -- --class Q_UITOOLS_EXPORT QUiTranslatableStringValue --{ --public: -- QByteArray value() const { return m_value; } -- void setValue(const QByteArray &value) { m_value = value; } -- QByteArray qualifier() const { return m_qualifier; } -- void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; } -- -- QString translate(const QByteArray &className, bool idBased) const; -- --private: -- QByteArray m_value; -- QByteArray m_qualifier; // Comment or ID for id-based tr(). --}; -- --#ifndef QT_NO_DATASTREAM --Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); --Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); --#endif // QT_NO_DATASTREAM -- --struct QUiItemRolePair { -- int realRole; -- int shadowRole; --}; -- --#ifdef QFORMINTERNAL_NAMESPACE --namespace QFormInternal --{ --#endif -- --extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; -- --#ifdef QFORMINTERNAL_NAMESPACE --} --#endif -- --QT_END_NAMESPACE -- --Q_DECLARE_METATYPE(QUiTranslatableStringValue) -- -- --#endif // QUILOADER_P_H -diff --git x/qttools/sync.profile y/qttools/sync.profile -index caa7ed5ad..de4261afc 100644 ---- x/qttools/sync.profile -+++ y/qttools/sync.profile -@@ -1,8 +1,8 @@ - %modules = ( # path to module name map - "QtTools" => "$basedir/src/global", - "QtHelp" => "$basedir/src/assistant/help", -- "QtUiTools" => "$basedir/src/uitools", -- "QtUiPlugin" => "$basedir/src/uiplugin", -+ "QtUiTools" => "$basedir/src/designer/src/uitools", -+ "QtUiPlugin" => "$basedir/src/designer/src/uiplugin", - "QtDesigner" => "$basedir/src/designer/src/lib", - "QtDesignerComponents" => "$basedir/src/designer/src/components/lib", - ); --- -2.38.1 - diff --git a/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch b/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch deleted file mode 100644 index 0ded83d..0000000 --- a/libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch +++ /dev/null @@ -1,39 +0,0 @@ -From dfc2918f8d635edf9300512fc5c1a067a89707d1 Mon Sep 17 00:00:00 2001 -From: Alexey Edelev -Date: Wed, 23 Nov 2022 12:40:45 +0100 -Subject: Fix Linux build with CMake versions >= 3.25 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The 'LINUX' variable exists in CMake since the version 3.25. This -variable previously was undefined while preparsing the configure.cmake -files. Since the CMake script that defines the 'check_for_ulimit' -function is not included while evaluating configure.cmake first time -we need to add a stub. - -Change-Id: I25bdec4f4a1b6af23174507a8f0f9cbf01f0c398 -Reviewed-by: Jörg Bornemann -(cherry picked from commit 240e71877865ed07e4c8d5bd4553aa0772c2adf4) -Reviewed-by: Qt Cherry-pick Bot -(cherry picked from commit 517d0890f9e95c841bea3421f2455651ca0d8070) ---- - configure.cmake | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git x/qtwebengine/configure.cmake y/qtwebengine/configure.cmake -index f485c1b4b..fff76d54a 100644 ---- x/qtwebengine/configure.cmake -+++ y/qtwebengine/configure.cmake -@@ -3,6 +3,8 @@ if(QT_CONFIGURE_RUNNING) - endfunction() - function(add_check_for_support) - endfunction() -+ function(check_for_ulimit) -+ endfunction() - else() - find_package(Ninja 1.7.2) - find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT) --- -2.38.1 - diff --git a/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch new file mode 100644 index 0000000..8a73295 --- /dev/null +++ b/libs/patches/qtbase-0001-Revert-Fix-usage-of-logging-category-on-Android.patch @@ -0,0 +1,40 @@ +From 68bc2e3fae6480d6315f524c2ee9acf3a33a435a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +Date: Mon, 25 Jul 2022 17:08:54 +0200 +Subject: Revert "Fix usage of logging category on Android" + +This reverts commit 87d8ee755bfdef8e72a122789c2e3ed382881a12. + +Change-Id: If19a9d615e01d61c79955cda4789ba1646520ee1 +--- + src/corelib/global/qlogging.cpp | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git x/qtbase/src/corelib/global/qlogging.cpp y/qtbase/src/corelib/global/qlogging.cpp +index 9ac70b3340..737a91dc6e 100644 +--- x/qtbase/src/corelib/global/qlogging.cpp ++++ y/qtbase/src/corelib/global/qlogging.cpp +@@ -1450,10 +1450,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con + } else if (token == messageTokenC) { + message.append(str); + } else if (token == categoryTokenC) { +-#ifndef Q_OS_ANDROID +- // Don't add the category to the message on Android + message.append(QLatin1StringView(context.category)); +-#endif + } else if (token == typeTokenC) { + switch (type) { + case QtDebugMsg: message.append("debug"_L1); break; +@@ -1701,11 +1698,7 @@ static bool android_default_message_handler(QtMsgType type, + break; + }; + +- // If application name is a tag ensure it has no spaces +- // If a category is defined, use it as an Android logging tag +- __android_log_print(priority, isDefaultCategory(context.category) ? +- qPrintable(QCoreApplication::applicationName().replace(u' ', u'_')) : context.category, +- "%s\n", qPrintable(formattedMessage)); ++ __android_log_print(priority, qPrintable(QCoreApplication::applicationName()), "%s\n", qPrintable(formattedMessage)); + + return true; // Prevent further output to stderr + } diff --git a/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch b/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch new file mode 100644 index 0000000..13641dc --- /dev/null +++ b/libs/patches/qtbase-0002-Android-Restore-the-default-QSettings-path-to-the-.c.patch @@ -0,0 +1,89 @@ +From bdd9f0e3a243977858df6691b734b7f596a9729b Mon Sep 17 00:00:00 2001 +From: Bartlomiej Moskal +Date: Tue, 30 May 2023 14:17:19 +0200 +Subject: Android: Restore the default QSettings path to the .config directory + +After 140ca89a3c2b8d78889d27217f977cd4de10041b commit, the path of the +QSettings default file location changed. That caused the problem with +updating the app (old settings file is not used anymore). That is why we +should still use old (.config) directory for QSettings file if the file +exists. + +Pick-to: 6.2 6.5 6.6 +Fixes: QTBUG-109405 +Fixes: QTBUG-109369 +Change-Id: I8ce53e0a80e4c2d16802b27b000ab3fbed198628 +Reviewed-by: Assam Boudjelthia +(cherry picked from commit beaaa0bf02fee696b03f2839bea8e0e6bc685a62) +--- + src/corelib/io/qsettings.cpp | 40 +++++++++++++++++++++++++----------- + 1 file changed, 28 insertions(+), 12 deletions(-) + +diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp +index 60622e3aaa..9fb2e0b522 100644 +--- x/qtbase/src/corelib/io/qsettings.cpp ++++ y/qtbase/src/corelib/io/qsettings.cpp +@@ -954,26 +954,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope) + } + + #ifndef Q_OS_WIN +-static QString make_user_path() ++static constexpr QChar sep = u'/'; ++ ++#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID) ++static QString make_user_path_without_qstandard_paths() + { +- static constexpr QChar sep = u'/'; +-#ifndef QSETTINGS_USE_QSTANDARDPATHS +- // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously +- // for some time now. Moving away from that would require migrating existing settings. + QByteArray env = qgetenv("XDG_CONFIG_HOME"); + if (env.isEmpty()) { + return QDir::homePath() + "/.config/"_L1; + } else if (env.startsWith('/')) { + return QFile::decodeName(env) + sep; +- } else { +- return QDir::homePath() + sep + QFile::decodeName(env) + sep; + } ++ ++ return QDir::homePath() + sep + QFile::decodeName(env) + sep; ++} ++#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID ++ ++static QString make_user_path() ++{ ++#ifndef QSETTINGS_USE_QSTANDARDPATHS ++ // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously ++ // for some time now. Moving away from that would require migrating existing settings. ++ // The migration has already been done for Android. ++ return make_user_path_without_qstandard_paths(); + #else +- // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code; +- // it makes the use of test mode from unit tests possible. ++ ++#ifdef Q_OS_ANDROID ++ // If an old settings path exists, use it instead of creating a new one ++ QString ret = make_user_path_without_qstandard_paths(); ++ if (QFile(ret).exists()) ++ return ret; ++#endif // Q_OS_ANDROID ++ ++ // When using a proper XDG platform or Android platform, use QStandardPaths rather than the ++ // above hand-written code. It makes the use of test mode from unit tests possible. + // Ideally all platforms should use this, but see above for the migration issue. + return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep; +-#endif ++#endif // !QSETTINGS_USE_QSTANDARDPATHS + } + #endif // !Q_OS_WIN + +@@ -1338,8 +1355,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) + // On android and if it is a content URL put the lock file in a + // writable location to prevent permissions issues and invalid paths. + if (confFile->name.startsWith("content:"_L1)) +- lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +- + QFileInfo(lockFileName).fileName(); ++ lockFileName = make_user_path() + QFileInfo(lockFileName).fileName(); + # endif + /* + Use a lockfile in order to protect us against other QSettings instances diff --git a/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch b/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch new file mode 100644 index 0000000..df11194 --- /dev/null +++ b/libs/patches/qtbase-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch @@ -0,0 +1,63 @@ +From a7490023e8f11906b30013c93ff991d941efc622 Mon Sep 17 00:00:00 2001 +From: Julian Greilich +Date: Wed, 4 Jan 2023 16:32:28 +0100 +Subject: Android A11Y: Only access the main thread when it is not blocked + +When the qtMainLoopThread calls QSGThreadedRenderLoop::polishAndSync(), +it waits for the QSGRenderThread. + +In the QSGRenderThread, QAndroidPlatformOpenGLWindow::eglSurface() +calls QtAndroid::createSurface() and waits for the "android main +thread" to return a valid surface. +When the "android main thread" now calls "runInObjectContext" (e.g. by +calling QtAndroidAccessibility::childIdListForAccessibleObject()) it +waits for the qtMainLoopThread and the program is stuck in a deadlock. + +To prevent this, we protect all BlockedQueuedConnection from the +"android main thread" to the qtMainLoopThread by acquiring the +AndroidDeadlockProtector. +When QAndroidPlatformOpenGLWindow::eglSurface() already acquired the +AndroidDeadlockProtector we abort the current A11y call with an emtpy +or default value. + +Note: b8a95275440b8a143ee648466fd8b5401ee1e839 already tried to fix +this by checking "getSurfaceCount() != 0", but there are situations, +where a new surface is being created while an old surface is still +present. + +Task-number: QTBUG-105958 +Pick-to: 6.5 6.4 6.3 6.2 5.15 +Change-Id: Ie40e8654c99aace9e69b0b8412952fa22c89f071 +Reviewed-by: Assam Boudjelthia +(cherry picked from commit b832a5ac72c6015b6509d60b75b2ce5d5e570800) +--- + .../platforms/android/androidjniaccessibility.cpp | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp +index 3067cb178a..8990289dc4 100644 +--- x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp ++++ y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp +@@ -1,6 +1,7 @@ + // Copyright (C) 2021 The Qt Company Ltd. + // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + ++#include "androiddeadlockprotector.h" + #include "androidjniaccessibility.h" + #include "androidjnimain.h" + #include "qandroidplatformintegration.h" +@@ -61,6 +62,14 @@ namespace QtAndroidAccessibility + template + void runInObjectContext(QObject *context, Func &&func, Ret *retVal) + { ++ AndroidDeadlockProtector protector; ++ if (!protector.acquire()) { ++ __android_log_print(ANDROID_LOG_WARN, m_qtTag, ++ "Could not run accessibility call in object context, accessing " ++ "main thread could lead to deadlock"); ++ return; ++ } ++ + if (!QtAndroid::blockEventLoopsWhenSuspended() + || QGuiApplication::applicationState() != Qt::ApplicationSuspended) { + QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal); diff --git a/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch b/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch new file mode 100644 index 0000000..e9761b1 --- /dev/null +++ b/libs/patches/qtbase-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch @@ -0,0 +1,46 @@ +From 03485e0ca36c615b87b82c6711fbacf0493d02bc Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Mon, 9 Jan 2023 06:54:53 +0100 +Subject: Fix warning in q20algorithm.h when xcodebuild is used + +q20algorithm.h:150:20: error: unused function template 'operator()' +q20algorithm.h:163:20: error: unused function template 'operator()' +q20algorithm.h:176:20: error: unused function template 'operator()' + +Fixes: QTBUG-109874 +Change-Id: If5ccbfffd0b6a53f73f221b45033dab7e4775d89 +--- + src/corelib/global/q20algorithm.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/corelib/global/q20algorithm.h y/qtbase/src/corelib/global/q20algorithm.h +index 69dc2d2446..88e8ab08d2 100644 +--- x/qtbase/src/corelib/global/q20algorithm.h ++++ y/qtbase/src/corelib/global/q20algorithm.h +@@ -147,7 +147,7 @@ using std::ranges::none_of; + [[maybe_unused]] inline constexpr struct { // Niebloid + template +- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const ++ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const + { + while (first != last) { + if (std::invoke(pred, std::invoke(proj, *first))) +@@ -160,7 +160,7 @@ using std::ranges::none_of; + [[maybe_unused]] inline constexpr struct { // Niebloid + template +- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const ++ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const + { + while (first != last) { + if (!std::invoke(pred, std::invoke(proj, *first))) +@@ -173,7 +173,7 @@ using std::ranges::none_of; + [[maybe_unused]] inline constexpr struct { // Niebloid + template +- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const ++ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const + { + while (first != last) { + if (std::invoke(pred, std::invoke(proj, *first))) diff --git a/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch b/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch new file mode 100644 index 0000000..85819c9 --- /dev/null +++ b/libs/patches/qtbase-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch @@ -0,0 +1,127 @@ +From e2402debef95b7ccc2050f331ee9f5076332ae91 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= +Date: Mon, 12 Dec 2022 14:33:41 +0100 +Subject: macOS: Use NSStatusItem.menu to manage system tray menu + +Using [NSStatusItem popUpStatusItemMenu:] to manually show the menu is +deprecated, and was causing various issues when right clicking the menu, +such as not unhighlighting the menu item when dismissing the menu, or +worse, not quitting the application if a 'Quit' item was triggered from +a right click. + +The reason we were using popUpStatusItemMenu instead of the menu +property of NSStatusItem was that the latter prevented us from seeing +the action message of the NSStatusItem button, which we used to emit +the system tray's activated signal, but this can be solved by listing +for the menu's tracking state starting. + +Fixes: QTBUG-103515 +Pick-to: 6.4 +Change-Id: I686550ebac7d94d8d11b2e3c49ed16a8240cb214 +Reviewed-by: Volker Hilsheimer +(cherry picked from commit da754d5b6589c9877f0325edb3da5cbc64d966c7) +--- + .../platforms/cocoa/qcocoasystemtrayicon.h | 3 +- + .../platforms/cocoa/qcocoasystemtrayicon.mm | 36 ++++++++++++------- + 2 files changed, 24 insertions(+), 15 deletions(-) + +diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h +index 414560e119..75c33cc5a3 100644 +--- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h ++++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h +@@ -45,12 +45,11 @@ public: + bool isSystemTrayAvailable() const override; + bool supportsMessages() const override; + +- void statusItemClicked(); ++ void emitActivated(); + + private: + NSStatusItem *m_statusItem = nullptr; + QStatusItemDelegate *m_delegate = nullptr; +- QCocoaMenu *m_menu = nullptr; + }; + + QT_END_NAMESPACE +diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +index c004cd69b5..2f7f73b481 100644 +--- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm ++++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +@@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init() + + m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this]; + ++ // In case the status item does not have a menu assigned to it ++ // we fall back to the item's button to detect activation. + m_statusItem.button.target = m_delegate; + m_statusItem.button.action = @selector(statusItemClicked); + [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown]; +@@ -81,8 +83,6 @@ void QCocoaSystemTrayIcon::cleanup() + + [m_delegate release]; + m_delegate = nil; +- +- m_menu = nullptr; + } + + QRect QCocoaSystemTrayIcon::geometry() const +@@ -178,12 +178,20 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) + + void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu) + { +- // We don't set the menu property of the NSStatusItem here, +- // as that would prevent us from receiving the action for the +- // click, and we wouldn't be able to emit the activated signal. +- // Instead we show the menu manually when the status item is +- // clicked. +- m_menu = static_cast(menu); ++ m_statusItem.menu = menu ? static_cast(menu)->nsMenu() : nil; ++ ++ if (m_statusItem.menu) { ++ // When a menu is assigned, NSStatusBarButtonCell will intercept the mouse ++ // down to pop up the menu, and we never see the NSStatusBarButton action. ++ // To ensure we emit the 'activated' signal in both cases we detect when ++ // menu starts tracking, which happens before the menu delegate is sent ++ // the menuWillOpen callback we use to emit aboutToShow for the menu. ++ [NSNotificationCenter.defaultCenter addObserver:m_delegate ++ selector:@selector(statusItemMenuBeganTracking:) ++ name:NSMenuDidBeginTrackingNotification ++ object:m_statusItem.menu ++ ]; ++ } + } + + void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip) +@@ -226,7 +234,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess + } + } + +-void QCocoaSystemTrayIcon::statusItemClicked() ++void QCocoaSystemTrayIcon::emitActivated() + { + auto *mouseEvent = NSApp.currentEvent; + +@@ -245,9 +253,6 @@ void QCocoaSystemTrayIcon::statusItemClicked() + } + + emit activated(activationReason); +- +- if (NSMenu *menu = m_menu ? m_menu->nsMenu() : nil) +- QT_IGNORE_DEPRECATIONS([m_statusItem popUpStatusItemMenu:menu]); + } + + QT_END_NAMESPACE +@@ -270,7 +275,12 @@ QT_END_NAMESPACE + + - (void)statusItemClicked + { +- self.platformSystemTray->statusItemClicked(); ++ self.platformSystemTray->emitActivated(); ++} ++ ++- (void)statusItemMenuBeganTracking:(NSNotification*)notification ++{ ++ self.platformSystemTray->emitActivated(); + } + + - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification diff --git a/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch b/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch new file mode 100644 index 0000000..63c2ce9 --- /dev/null +++ b/libs/patches/qtbase-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch @@ -0,0 +1,41 @@ +From d967022bcd7061771f10e4d36d38ab8ffe5aef98 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= +Date: Thu, 15 Dec 2022 16:40:34 +0100 +Subject: iOS: Don't assume screens will not be connected before + QIOSIntegration + +When an external screen is connected to an iPad, and the application is +starting up on that screen, we will get a connection notification about +that screen as part of the initial bootstrap of UIApplicationMain, +before we call the user's main(). + +Since we initialize and add all available screen on QIOSIntegration +creation, we can just ignore the early connection notification. + +This avoids a crash, but the window will not show anything on the +external screen, which is a separate issue. + +Pick-to: 6.5 6.4 6.2 +Fixes: QTBUG-106701 +Change-Id: I9e0a9736bf602277316bd004e0d01c640feaf319 +Reviewed-by: Volker Hilsheimer +(cherry picked from commit dd49793bc3b4dd3808f0f24b717c442a5095db14) +--- + src/plugins/platforms/ios/qiosscreen.mm | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm +index f144c00fb0..3d660189af 100644 +--- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm ++++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm +@@ -72,8 +72,8 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) + + + (void)screenConnected:(NSNotification*)notification + { +- Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO, +- "Screen connected before QIOSIntegration creation"); ++ if (!QIOSIntegration::instance()) ++ return; // Will be added when QIOSIntegration is created + + QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object])); + } diff --git a/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch b/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch new file mode 100644 index 0000000..ff42334 --- /dev/null +++ b/libs/patches/qtbase-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch @@ -0,0 +1,54 @@ +From 6d6832fc530c9296d92dd924f6f6bca0effa6412 Mon Sep 17 00:00:00 2001 +From: Jan Moeller +Date: Thu, 6 Apr 2023 09:27:16 +0200 +Subject: Ignore removed/changed screens if no QIOSIntegration instance exists + +QIOSTracker registers itself as handlers for system notifications about +changes of the screen environment. If no QIOSIntegration instance +exists, newly detected screens are not added to the list of known +screens (see screenConnected()). This, in turn, will result in a crash +if a screen is disconnected and removed in screenDisconnected() as it +is not known to qtPlatformScreenFor() and the function returns a +nullptr. + +Consider the QIOSIntegration also whenever a screen is "changed". This +is more of a safety measure do avoid crashes for unknown screens. + +This situation occurs if an iOS device is used to mirror the display +via AirPlay and no actual QGuiApplication exists, e.g. Qt is only +embedded in a Framework. + +Pick-to: 6.5 6.2 +Fixes: QTBUG-106701 +Change-Id: Id778fc5afa7c284b0536ee02b1ba2c10321cc5b1 +Reviewed-by: Volker Hilsheimer +Reviewed-by: Lars Schmertmann +(cherry picked from commit ffdfafc4b47b8267395370199073c292da33dd42) +--- + src/plugins/platforms/ios/qiosscreen.mm | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm +index 3d660189af..e0216ce652 100644 +--- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm ++++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm +@@ -80,6 +80,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) + + + (void)screenDisconnected:(NSNotification*)notification + { ++ if (!QIOSIntegration::instance()) ++ return; ++ + QIOSScreen *screen = qtPlatformScreenFor([notification object]); + Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about"); + +@@ -88,6 +91,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) + + + (void)screenModeChanged:(NSNotification*)notification + { ++ if (!QIOSIntegration::instance()) ++ return; ++ + QIOSScreen *screen = qtPlatformScreenFor([notification object]); + Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about"); + diff --git a/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch b/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch new file mode 100644 index 0000000..ba82d24 --- /dev/null +++ b/libs/patches/qtbase-0008-Fix-specific-overflow-in-qtextlayout.patch @@ -0,0 +1,75 @@ +From 25b9264bd6e5a547db3692032dd5c49cb2db0bfd Mon Sep 17 00:00:00 2001 +From: Allan Sandfeld Jensen +Date: Fri, 5 May 2023 09:51:32 +0200 +Subject: Fix specific overflow in qtextlayout + +Adds qAddOverflow and qMulOverflow definitions to QFixed + +Fixes: QTBUG-113337 +Pick-to: 6.5 6.5.1 6.2 5.15 +Change-Id: I13579306defceaccdc0fbb1ec0e9b77c6f8d1af9 +Reviewed-by: Eirik Aavitsland +Reviewed-by: Thiago Macieira +(cherry picked from commit 7b7a01c266b507636eab51a36328c7c72d82d93c) +--- + src/gui/painting/qfixed_p.h | 17 +++++++++++++++++ + src/gui/text/qtextlayout.cpp | 9 ++++++--- + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/gui/painting/qfixed_p.h y/qtbase/src/gui/painting/qfixed_p.h +index f3718a097e..c0a13d057f 100644 +--- x/qtbase/src/gui/painting/qfixed_p.h ++++ y/qtbase/src/gui/painting/qfixed_p.h +@@ -18,6 +18,7 @@ + #include + #include "QtCore/qdebug.h" + #include "QtCore/qpoint.h" ++#include "QtCore/qnumeric.h" + #include "QtCore/qsize.h" + + QT_BEGIN_NAMESPACE +@@ -136,6 +137,22 @@ constexpr inline QFixed operator+(uint i, QFixed d) { return d+i; } + constexpr inline QFixed operator-(uint i, QFixed d) { return -(d-i); } + // constexpr inline QFixed operator*(qreal d, QFixed d2) { return d2*d; } + ++inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r) ++{ ++ int val; ++ bool result = qAddOverflow(v1.value(), v2.value(), &val); ++ r->setValue(val); ++ return result; ++} ++ ++inline bool qMulOverflow(QFixed v1, QFixed v2, QFixed *r) ++{ ++ int val; ++ bool result = qMulOverflow(v1.value(), v2.value(), &val); ++ r->setValue(val); ++ return result; ++} ++ + #ifndef QT_NO_DEBUG_STREAM + inline QDebug &operator<<(QDebug &dbg, QFixed f) + { return dbg << f.toReal(); } +diff --git x/qtbase/src/gui/text/qtextlayout.cpp y/qtbase/src/gui/text/qtextlayout.cpp +index 365131f508..6a36b2458a 100644 +--- x/qtbase/src/gui/text/qtextlayout.cpp ++++ y/qtbase/src/gui/text/qtextlayout.cpp +@@ -2105,11 +2105,14 @@ found: + eng->maxWidth = qMax(eng->maxWidth, line.textWidth); + } else { + eng->minWidth = qMax(eng->minWidth, lbh.minw); +- eng->maxWidth += line.textWidth; ++ if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth)) ++ eng->maxWidth = QFIXED_MAX; + } + +- if (line.textWidth > 0 && item < eng->layoutData->items.size()) +- eng->maxWidth += lbh.spaceData.textWidth; ++ if (line.textWidth > 0 && item < eng->layoutData->items.size()) { ++ if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth)) ++ eng->maxWidth = QFIXED_MAX; ++ } + + line.textWidth += trailingSpace; + if (lbh.spaceData.length) { diff --git a/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch b/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch new file mode 100644 index 0000000..9f1a1ec --- /dev/null +++ b/libs/patches/qtbase-0009-Schannel-Reject-certificate-not-signed-by-a-configur.patch @@ -0,0 +1,289 @@ +From 550172c8a2f5e7195e2255bc50cffb2a64b8701c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= +Date: Wed, 10 May 2023 16:43:41 +0200 +Subject: Schannel: Reject certificate not signed by a configured CA + certificate + +Not entirely clear why, but when building the certificate chain for a +peer the system certificate store is searched for root certificates. +General expectation is that after calling +`sslConfiguration.setCaCertificates()` the system certificates will +not be taken into consideration. + +To work around this behavior, we do a manual check that the root of the +chain is part of the configured CA certificates. + +Pick-to: 6.5 6.2 5.15 +Change-Id: I03666a4d9b0eac39ae97e150b4743120611a11b3 +Reviewed-by: Edward Welbourne +Reviewed-by: Volker Hilsheimer +(cherry picked from commit ada2c573c1a25f8d96577734968fe317ddfa292a) +--- + src/plugins/tls/schannel/qtls_schannel.cpp | 21 ++++ + .../network/ssl/client-auth/CMakeLists.txt | 24 ++++ + .../network/ssl/client-auth/certs/.gitignore | 4 + + .../client-auth/certs/accepted-client.conf | 14 +++ + .../network/ssl/client-auth/certs/generate.sh | 33 +++++ + .../tst_manual_ssl_client_auth.cpp | 118 ++++++++++++++++++ + 6 files changed, 214 insertions(+) + create mode 100644 tests/manual/network/ssl/client-auth/CMakeLists.txt + create mode 100644 tests/manual/network/ssl/client-auth/certs/.gitignore + create mode 100644 tests/manual/network/ssl/client-auth/certs/accepted-client.conf + create mode 100755 tests/manual/network/ssl/client-auth/certs/generate.sh + create mode 100644 tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp + +diff --git x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp +index 58e74357d8..c15eab8796 100644 +--- x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp ++++ y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp +@@ -2106,6 +2106,27 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext) + verifyDepth = DWORD(q->peerVerifyDepth()); + + const auto &caCertificates = q->sslConfiguration().caCertificates(); ++ ++ if (!rootCertOnDemandLoadingAllowed() ++ && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) ++ && (q->peerVerifyMode() == QSslSocket::VerifyPeer ++ || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) { ++ // When verifying a peer Windows "helpfully" builds a chain that ++ // may include roots from the system store. But we don't want that if ++ // the user has set their own CA certificates. ++ // Since Windows claims this is not a partial chain the root is included ++ // and we have to check that it is one of our configured CAs. ++ CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1]; ++ QSslCertificate certificate = getCertificateFromChainElement(element); ++ if (!caCertificates.contains(certificate)) { ++ auto error = QSslError(QSslError::CertificateUntrusted, certificate); ++ sslErrors += error; ++ emit q->peerVerifyError(error); ++ if (q->state() != QAbstractSocket::ConnectedState) ++ return false; ++ } ++ } ++ + QList peerCertificateChain; + for (DWORD i = 0; i < verifyDepth; i++) { + CERT_CHAIN_ELEMENT *element = chain->rgpElement[i]; +diff --git x/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt +new file mode 100644 +index 0000000000..67ecc20bf4 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt +@@ -0,0 +1,24 @@ ++# Copyright (C) 2023 The Qt Company Ltd. ++# SPDX-License-Identifier: BSD-3-Clause ++ ++qt_internal_add_manual_test(tst_manual_ssl_client_auth ++ SOURCES ++ tst_manual_ssl_client_auth.cpp ++ LIBRARIES ++ Qt::Network ++) ++ ++qt_internal_add_resource(tst_manual_ssl_client_auth "tst_manual_ssl_client_auth" ++ PREFIX ++ "/" ++ FILES ++ "certs/127.0.0.1.pem" ++ "certs/127.0.0.1-key.pem" ++ "certs/127.0.0.1-client.pem" ++ "certs/127.0.0.1-client-key.pem" ++ "certs/accepted-client.pem" ++ "certs/accepted-client-key.pem" ++ "certs/rootCA.pem" ++ BASE ++ "certs" ++) +diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore +new file mode 100644 +index 0000000000..5866f7b609 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore +@@ -0,0 +1,4 @@ ++* ++!/.gitignore ++!/generate.sh ++!/accepted-client.conf +diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf +new file mode 100644 +index 0000000000..a88b276efe +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf +@@ -0,0 +1,14 @@ ++[req] ++default_md = sha512 ++basicConstraints = CA:FALSE ++extendedKeyUsage = clientAuth ++[req] ++distinguished_name = client_distinguished_name ++prompt = no ++[client_distinguished_name] ++C = NO ++ST = Oslo ++L = Oslo ++O = The Qt Project ++OU = The Qt Project ++CN = Fake Qt Project Client Certificate +diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh +new file mode 100755 +index 0000000000..5dbe3b3712 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++# Copyright (C) 2023 The Qt Company Ltd. ++# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 ++ ++# Requires mkcert and openssl ++ ++warn () { echo "$@" >&2; } ++die () { warn "$@"; exit 1; } ++ ++ ++command -v mkcert 1>/dev/null 2>&1 || die "Failed to find mkcert" ++command -v openssl 1>/dev/null 2>&1 || die "Failed to find openssl" ++ ++SCRIPT=$(realpath "$0") ++SCRIPTPATH=$(dirname "$SCRIPT") ++ ++pushd "$SCRIPTPATH" || die "Unable to pushd to $SCRIPTPATH" ++mkcert 127.0.0.1 ++mkcert -client 127.0.0.1 ++warn "Remember to run mkcert -install if you haven't already" ++ ++# Generate CA ++openssl genrsa -out ca-key.pem 2048 ++openssl req -new -x509 -noenc -days 365 -key ca-key.pem -out rootCA.pem ++ ++# Generate accepted client certificate ++openssl genrsa -out accepted-client-key.pem 2048 ++openssl req -new -sha512 -nodes -key accepted-client-key.pem -out accepted-client.csr -config accepted-client.conf ++openssl x509 -req -sha512 -days 45 -in accepted-client.csr -CA rootCA.pem -CAkey ca-key.pem -CAcreateserial -out accepted-client.pem ++rm accepted-client.csr ++rm rootCA.srl ++ ++popd || die "Unable to popd" +diff --git x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +new file mode 100644 +index 0000000000..2307cbb191 +--- /dev/null ++++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +@@ -0,0 +1,118 @@ ++// Copyright (C) 2023 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++// Client and/or server presents a certificate signed by a system-trusted CA ++// but the other side presents a certificate signed by a different CA. ++constexpr bool TestServerPresentsIncorrectCa = false; ++constexpr bool TestClientPresentsIncorrectCa = true; ++ ++class ServerThread : public QThread ++{ ++ Q_OBJECT ++public: ++ void run() override ++ { ++ QSslServer server; ++ ++ QSslConfiguration config = server.sslConfiguration(); ++ QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); ++ config.setCaCertificates(certs); ++ config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) ++ .first()); ++ QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); ++ if (!keyFile.open(QIODevice::ReadOnly)) ++ qFatal("Failed to open key file"); ++ config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); ++ config.setPeerVerifyMode(QSslSocket::VerifyPeer); ++ server.setSslConfiguration(config); ++ ++ connect(&server, &QSslServer::pendingConnectionAvailable, [&server]() { ++ QSslSocket *socket = static_cast(server.nextPendingConnection()); ++ qDebug() << "[s] newConnection" << socket->peerAddress() << socket->peerPort(); ++ socket->disconnectFromHost(); ++ qApp->quit(); ++ }); ++ connect(&server, &QSslServer::startedEncryptionHandshake, [](QSslSocket *socket) { ++ qDebug() << "[s] new handshake" << socket->peerAddress() << socket->peerPort(); ++ }); ++ connect(&server, &QSslServer::errorOccurred, ++ [](QSslSocket *socket, QAbstractSocket::SocketError error) { ++ qDebug() << "[s] errorOccurred" << socket->peerAddress() << socket->peerPort() ++ << error << socket->errorString(); ++ }); ++ connect(&server, &QSslServer::peerVerifyError, ++ [](QSslSocket *socket, const QSslError &error) { ++ qDebug() << "[s] peerVerifyError" << socket->peerAddress() << socket->peerPort() ++ << error; ++ }); ++ server.listen(QHostAddress::LocalHost, 24242); ++ ++ exec(); ++ ++ server.close(); ++ } ++}; ++ ++int main(int argc, char **argv) ++{ ++ QCoreApplication app(argc, argv); ++ ++ using namespace Qt::StringLiterals; ++ ++ if (!QFileInfo(u":/rootCA.pem"_s).exists()) ++ qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); ++ ++ ServerThread serverThread; ++ serverThread.start(); ++ ++ QSslSocket socket; ++ QSslConfiguration config = socket.sslConfiguration(); ++ QString certificatePath; ++ QString keyFileName; ++ if constexpr (TestClientPresentsIncorrectCa) { // true: Present cert signed with incorrect CA: should fail ++ certificatePath = u":/127.0.0.1-client.pem"_s; ++ keyFileName = u":/127.0.0.1-client-key.pem"_s; ++ } else { // false: Use correct CA: should succeed ++ certificatePath = u":/accepted-client.pem"_s; ++ keyFileName = u":/accepted-client-key.pem"_s; ++ } ++ config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); ++ if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail ++ config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); ++ QFile keyFile(keyFileName); ++ if (!keyFile.open(QIODevice::ReadOnly)) ++ qFatal("Failed to open key file"); ++ config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); ++ socket.setSslConfiguration(config); ++ ++ QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); ++ QObject::connect(&socket, &QSslSocket::errorOccurred, ++ [&socket](QAbstractSocket::SocketError error) { ++ qDebug() << "[c] errorOccurred" << error << socket.errorString(); ++ qApp->quit(); ++ }); ++ QObject::connect(&socket, &QSslSocket::sslErrors, [](const QList &errors) { ++ qDebug() << "[c] sslErrors" << errors; ++ }); ++ QObject::connect(&socket, &QSslSocket::connected, []() { qDebug() << "[c] connected"; }); ++ ++ socket.connectToHostEncrypted(QStringLiteral("127.0.0.1"), 24242); ++ ++ const int res = app.exec(); ++ serverThread.quit(); ++ serverThread.wait(); ++ return res; ++} ++ ++#include "tst_manual_ssl_client_auth.moc" diff --git a/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch b/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch new file mode 100644 index 0000000..84724d3 --- /dev/null +++ b/libs/patches/qtbase-0010-Ssl-Copy-the-on-demand-cert-loading-bool-from-defaul.patch @@ -0,0 +1,110 @@ +From d13e70c1d56a94d64eb68d2f3cba670e58a1a73f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= +Date: Thu, 25 May 2023 14:40:29 +0200 +Subject: Ssl: Copy the on-demand cert loading bool from default config + +Otherwise individual sockets will still load system certificates when +a chain doesn't match against the configured CA certificates. +That's not intended behavior, since specifically setting the CA +certificates means you don't want the system certificates to be used. + +Follow-up to/amends ada2c573c1a25f8d96577734968fe317ddfa292a + +This is potentially a breaking change because now, if you ever add a +CA to the default config, it will disable loading system certificates +on demand for all sockets. And the only way to re-enable it is to +create a null-QSslConfiguration and set it as the new default. + +Pick-to: 6.5 6.2 5.15 +Change-Id: Ic3b2ab125c0cdd58ad654af1cb36173960ce2d1e +Reviewed-by: Timur Pocheptsov +(cherry picked from commit 57ba6260c0801055b7188fdaa1818b940590f5f1) +--- + src/network/ssl/qsslsocket.cpp | 5 ++++ + .../tst_manual_ssl_client_auth.cpp | 24 ++++++++++++++++--- + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp +index cd76517c25..a94f2b79c3 100644 +--- x/qtbase/src/network/ssl/qsslsocket.cpp ++++ y/qtbase/src/network/ssl/qsslsocket.cpp +@@ -1973,6 +1973,10 @@ QSslSocketPrivate::QSslSocketPrivate() + , flushTriggered(false) + { + QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration); ++ // If the global configuration doesn't allow root certificates to be loaded ++ // on demand then we have to disable it for this socket as well. ++ if (!configuration.allowRootCertOnDemandLoading) ++ allowRootCertOnDemandLoading = false; + + const auto *tlsBackend = tlsBackendInUse(); + if (!tlsBackend) { +@@ -2281,6 +2285,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri + ptr->sessionProtocol = global->sessionProtocol; + ptr->ciphers = global->ciphers; + ptr->caCertificates = global->caCertificates; ++ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading; + ptr->protocol = global->protocol; + ptr->peerVerifyMode = global->peerVerifyMode; + ptr->peerVerifyDepth = global->peerVerifyDepth; +diff --git x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +index 2307cbb191..4d4aaca7e3 100644 +--- x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp ++++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp +@@ -16,6 +16,9 @@ + // but the other side presents a certificate signed by a different CA. + constexpr bool TestServerPresentsIncorrectCa = false; + constexpr bool TestClientPresentsIncorrectCa = true; ++// Decides whether or not to put the root CA into the global ssl configuration ++// or into the socket's specific ssl configuration. ++constexpr bool UseGlobalConfiguration = true; + + class ServerThread : public QThread + { +@@ -26,8 +29,10 @@ public: + QSslServer server; + + QSslConfiguration config = server.sslConfiguration(); +- QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); +- config.setCaCertificates(certs); ++ if (!UseGlobalConfiguration) { ++ QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); ++ config.setCaCertificates(certs); ++ } + config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) + .first()); + QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); +@@ -73,6 +78,12 @@ int main(int argc, char **argv) + if (!QFileInfo(u":/rootCA.pem"_s).exists()) + qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); + ++ if (UseGlobalConfiguration) { ++ QSslConfiguration config = QSslConfiguration::defaultConfiguration(); ++ config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); ++ QSslConfiguration::setDefaultConfiguration(config); ++ } ++ + ServerThread serverThread; + serverThread.start(); + +@@ -88,12 +99,19 @@ int main(int argc, char **argv) + keyFileName = u":/accepted-client-key.pem"_s; + } + config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); +- if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail ++ if (!UseGlobalConfiguration && TestServerPresentsIncorrectCa) { ++ // Verify server using incorrect CA: should fail + config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); ++ } else if (UseGlobalConfiguration && !TestServerPresentsIncorrectCa) { ++ // Verify server using correct CA, we need to explicitly set the ++ // system CAs when the global config is overridden. ++ config.setCaCertificates(QSslConfiguration::systemCaCertificates()); ++ } + QFile keyFile(keyFileName); + if (!keyFile.open(QIODevice::ReadOnly)) + qFatal("Failed to open key file"); + config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); ++ + socket.setSslConfiguration(config); + + QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); diff --git a/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch b/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch new file mode 100644 index 0000000..4dcdca6 --- /dev/null +++ b/libs/patches/qtbase-0011-Improve-Intent-source-app-detection.patch @@ -0,0 +1,51 @@ +From bdc4845cd844e674f17161435a11e60dde2769cc Mon Sep 17 00:00:00 2001 +From: Jens Trillmann +Date: Wed, 5 Jul 2023 09:33:03 +0200 +Subject: Improve Intent source app detection + +Activity.getReferrer does not only return app IDs but also URLs if +Intent.EXTRA_REFERRER is set on the Intent. In the case of Chrome the referrer +is set to the website triggering the Intent. To improve the detection of the +calling app we check first if the browser specific +Browser.EXTRAS_APPLICATION_ID is set. If it is not set we fall back to +Intent.getReferrer. + +Pick-to: 6.6 +Change-Id: I33d1edd52de98486d9616713e531ea20ada87bcb +--- + .../qtproject/qt/android/bindings/QtActivity.java | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java +index 9cef8146fd..f862f6aaee 100644 +--- x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java ++++ y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java +@@ -16,6 +16,7 @@ import android.graphics.Canvas; + import android.net.Uri; + import android.os.Build; + import android.os.Bundle; ++import android.provider.Browser; + import android.util.AttributeSet; + import android.view.ActionMode; + import android.view.ActionMode.Callback; +@@ -237,9 +238,17 @@ public class QtActivity extends Activity + return; + + String sourceInformation = ""; +- Uri referrer = getReferrer(); +- if (referrer != null) +- sourceInformation = referrer.toString().replaceFirst("android-app://", ""); ++ String browserApplicationId = intent.getExtras() == null ? "" : intent.getExtras().getString(Browser.EXTRA_APPLICATION_ID); ++ if (!browserApplicationId.isEmpty()) ++ { ++ sourceInformation = browserApplicationId; ++ } ++ else ++ { ++ Uri referrer = getReferrer(); ++ if (referrer != null) ++ sourceInformation = referrer.toString().replaceFirst("android-app://", ""); ++ } + + intent.putExtra(EXTRA_SOURCE_INFO, sourceInformation); + } diff --git a/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch b/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch new file mode 100644 index 0000000..5602a02 --- /dev/null +++ b/libs/patches/qtbase-0012-QXmlStreamReader-change-fastScanName-to-take-a-Value.patch @@ -0,0 +1,105 @@ +From f9a1c8668e5f4787e9b0b3136076138f4fda5563 Mon Sep 17 00:00:00 2001 +From: Ahmad Samir +Date: Wed, 12 Apr 2023 13:10:26 +0200 +Subject: QXmlStreamReader: change fastScanName() to take a Value* + +For easier debugging, e.g. to print out value.len and value.prefix. + +Pick-to: 6.6 6.5 6.5.2 6.2 5.15 +Change-Id: Ib0eed38772f899502962f578775d34ea2744fdde +Reviewed-by: Marc Mutz +(cherry picked from commit 1a423ce4372d18a779f3c0d746d5283d9a425839) +--- + src/corelib/serialization/qxmlstream.cpp | 16 ++++++++-------- + src/corelib/serialization/qxmlstream.g | 3 ++- + src/corelib/serialization/qxmlstream_p.h | 2 +- + src/corelib/serialization/qxmlstreamparser_p.h | 3 ++- + 4 files changed, 13 insertions(+), 11 deletions(-) + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index a6a2bc41af..f64db47867 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -1243,7 +1243,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() + return n; + } + +-inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) ++inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + { + qsizetype n = 0; + uint c; +@@ -1280,16 +1280,16 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) + case '+': + case '*': + putChar(c); +- if (prefix && *prefix == n+1) { +- *prefix = 0; ++ if (val && val->prefix == n + 1) { ++ val->prefix = 0; + putChar(':'); + --n; + } + return n; + case ':': +- if (prefix) { +- if (*prefix == 0) { +- *prefix = qint16(n + 2); ++ if (val) { ++ if (val->prefix == 0) { ++ val->prefix = qint16(n + 2); + } else { // only one colon allowed according to the namespace spec. + putChar(c); + return n; +@@ -1305,8 +1305,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix) + } + } + +- if (prefix) +- *prefix = 0; ++ if (val) ++ val->prefix = 0; + qsizetype pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); +diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g +index d06c371eb8..f3152bff37 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.g ++++ y/qtbase/src/corelib/serialization/qxmlstream.g +@@ -1419,7 +1419,8 @@ space_opt ::= space; + qname ::= LETTER; + /. + case $rule_number: { +- sym(1).len += fastScanName(&sym(1).prefix); ++ Value &val = sym(1); ++ val.len += fastScanName(&val); + if (atEnd) { + resume($rule_number); + return false; +diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h +index 8e523f9c67..5da1f4aa5a 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstream_p.h +@@ -471,7 +471,7 @@ public: + qsizetype fastScanLiteralContent(); + qsizetype fastScanSpace(); + qsizetype fastScanContentCharList(); +- qsizetype fastScanName(qint16 *prefix = nullptr); ++ qsizetype fastScanName(Value *val = nullptr); + inline qsizetype fastScanNMTOKEN(); + + +diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +index e3ae6faa44..59370a9310 100644 +--- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +@@ -947,7 +947,8 @@ bool QXmlStreamReaderPrivate::parse() + break; + + case 262: { +- sym(1).len += fastScanName(&sym(1).prefix); ++ Value &val = sym(1); ++ val.len += fastScanName(&val); + if (atEnd) { + resume(262); + return false; diff --git a/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch b/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch new file mode 100644 index 0000000..375a274 --- /dev/null +++ b/libs/patches/qtbase-0013-QXmlStreamReader-make-fastScanName-indicate-parsing-.patch @@ -0,0 +1,270 @@ +From 836d7df23ec9b6cb3dea1bb68b7c8bc75090702e Mon Sep 17 00:00:00 2001 +From: Ahmad Samir +Date: Thu, 22 Jun 2023 15:56:07 +0300 +Subject: QXmlStreamReader: make fastScanName() indicate parsing status to + callers + +This fixes a crash while parsing an XML file with garbage data, the file +starts with '<' then garbage data: +- The loop in the parse() keeps iterating until it hits "case 262:", + which calls fastScanName() +- fastScanName() iterates over the text buffer scanning for the + attribute name (e.g. "xml:lang"), until it finds ':' +- Consider a Value val, fastScanName() is called on it, it would set + val.prefix to a number > val.len, then it would hit the 4096 condition + and return (returned 0, now it returns the equivalent of + std::null_opt), which means that val.len doesn't get modified, making + it smaller than val.prefix +- The code would try constructing an XmlStringRef with negative length, + which would hit an assert in one of QStringView's constructors + +Add an assert to the XmlStringRef constructor. + +Add unittest based on the file from the bug report. + +Later on I will replace FastScanNameResult with std::optional +(std::optional is C++17, which isn't required by Qt 5.15, and we want to +backport this fix). + +Credit to OSS-Fuzz. + +Fixes: QTBUG-109781 +Fixes: QTBUG-114829 +Pick-to: 6.6 6.5 6.2 5.15 +Change-Id: I455a5eeb47870c2ac9ffd0cbcdcd99c1ae2dd374 +Reviewed-by: Allan Sandfeld Jensen +(cherry picked from commit 6326bec46a618c72feba4a2bb994c4d475050aed) +--- + src/corelib/serialization/qxmlstream.cpp | 23 ++++++++--- + src/corelib/serialization/qxmlstream.g | 12 +++++- + src/corelib/serialization/qxmlstream_p.h | 14 ++++++- + .../serialization/qxmlstreamparser_p.h | 12 +++++- + .../qxmlstream/tst_qxmlstream.cpp | 39 +++++++++++++++++++ + 5 files changed, 88 insertions(+), 12 deletions(-) + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index f64db47867..34568b7351 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -1243,7 +1243,9 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList() + return n; + } + +-inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) ++// Fast scan an XML attribute name (e.g. "xml:lang"). ++inline QXmlStreamReaderPrivate::FastScanNameResult ++QXmlStreamReaderPrivate::fastScanName(Value *val) + { + qsizetype n = 0; + uint c; +@@ -1251,7 +1253,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + if (n >= 4096) { + // This is too long to be a sensible name, and + // can exhaust memory, or the range of decltype(*prefix) +- return 0; ++ raiseNamePrefixTooLongError(); ++ return {}; + } + switch (c) { + case '\n': +@@ -1285,18 +1288,18 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + putChar(':'); + --n; + } +- return n; ++ return FastScanNameResult(n); + case ':': + if (val) { + if (val->prefix == 0) { + val->prefix = qint16(n + 2); + } else { // only one colon allowed according to the namespace spec. + putChar(c); +- return n; ++ return FastScanNameResult(n); + } + } else { + putChar(c); +- return n; ++ return FastScanNameResult(n); + } + Q_FALLTHROUGH(); + default: +@@ -1310,7 +1313,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val) + qsizetype pos = textBuffer.size() - n; + putString(textBuffer, pos); + textBuffer.resize(pos); +- return 0; ++ return FastScanNameResult(0); + } + + enum NameChar { NameBeginning, NameNotBeginning, NotName }; +@@ -1791,6 +1794,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message) + raiseError(QXmlStreamReader::NotWellFormedError, message); + } + ++void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError() ++{ ++ // TODO: add a ImplementationLimitsExceededError and use it instead ++ raiseError(QXmlStreamReader::NotWellFormedError, ++ QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB " ++ "characters).")); ++} ++ + void QXmlStreamReaderPrivate::parseError() + { + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g +index f3152bff37..fc122e6681 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.g ++++ y/qtbase/src/corelib/serialization/qxmlstream.g +@@ -1420,7 +1420,11 @@ qname ::= LETTER; + /. + case $rule_number: { + Value &val = sym(1); +- val.len += fastScanName(&val); ++ if (auto res = fastScanName(&val)) ++ val.len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume($rule_number); + return false; +@@ -1431,7 +1435,11 @@ qname ::= LETTER; + name ::= LETTER; + /. + case $rule_number: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume($rule_number); + return false; +diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h +index 5da1f4aa5a..7925e59014 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstream_p.h +@@ -38,7 +38,7 @@ public: + + constexpr XmlStringRef() = default; + constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length) +- : m_string(string), m_pos(pos), m_size(length) ++ : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length)) + { + } + XmlStringRef(const QString *string) +@@ -471,7 +471,16 @@ public: + qsizetype fastScanLiteralContent(); + qsizetype fastScanSpace(); + qsizetype fastScanContentCharList(); +- qsizetype fastScanName(Value *val = nullptr); ++ ++ struct FastScanNameResult { ++ FastScanNameResult() : ok(false) {} ++ explicit FastScanNameResult(qsizetype len) : addToLen(len), ok(true) { } ++ operator bool() { return ok; } ++ qsizetype operator*() { Q_ASSERT(ok); return addToLen; } ++ qsizetype addToLen; ++ bool ok; ++ }; ++ FastScanNameResult fastScanName(Value *val = nullptr); + inline qsizetype fastScanNMTOKEN(); + + +@@ -480,6 +489,7 @@ public: + + void raiseError(QXmlStreamReader::Error error, const QString& message = QString()); + void raiseWellFormedError(const QString &message); ++ void raiseNamePrefixTooLongError(); + + QXmlStreamEntityResolver *entityResolver; + +diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +index 59370a9310..afd83381b3 100644 +--- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h +@@ -948,7 +948,11 @@ bool QXmlStreamReaderPrivate::parse() + + case 262: { + Value &val = sym(1); +- val.len += fastScanName(&val); ++ if (auto res = fastScanName(&val)) ++ val.len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(262); + return false; +@@ -956,7 +960,11 @@ bool QXmlStreamReaderPrivate::parse() + } break; + + case 263: +- sym(1).len += fastScanName(); ++ if (auto res = fastScanName()) ++ sym(1).len += *res; ++ else ++ return false; ++ + if (atEnd) { + resume(263); + return false; +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +index 2799e7a999..7eb0aac5cc 100644 +--- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +@@ -581,6 +581,8 @@ private slots: + void readBack() const; + void roundTrip() const; + void roundTrip_data() const; ++ void test_fastScanName_data() const; ++ void test_fastScanName() const; + + void entityExpansionLimit() const; + +@@ -1753,5 +1755,42 @@ void tst_QXmlStream::roundTrip() const + QCOMPARE(out, in); + } + ++void tst_QXmlStream::test_fastScanName_data() const ++{ ++ QTest::addColumn("data"); ++ QTest::addColumn("errorType"); ++ ++ // 4096 is the limit in QXmlStreamReaderPrivate::fastScanName() ++ ++ QByteArray arr = " +Date: Fri, 2 Sep 2022 16:52:04 +0200 +Subject: QXmlStreamReader: use qOffsetStringArray for storing token types +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Change-Id: I9e58c17d97c44e1b13899d30396f65b452d8600f +Reviewed-by: Mårten Nordheim +(cherry picked from commit d674f3f5454fb39de9405484a8c01fb928523f67) +--- + src/corelib/serialization/qxmlstream.cpp | 67 ++++++------------------ + 1 file changed, 16 insertions(+), 51 deletions(-) + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index 34568b7351..535f98a215 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -15,6 +15,8 @@ + #include + #include + ++#include ++ + #include + #include "qxmlstream_p.h" + #include "qxmlstreamparser_p.h" +@@ -640,55 +642,19 @@ void QXmlStreamReader::skipCurrentElement() + } + } + +-/* +- * Use the following Perl script to generate the error string index list: +-===== PERL SCRIPT ==== +-print "static const char QXmlStreamReader_tokenTypeString_string[] =\n"; +-$counter = 0; +-$i = 0; +-while () { +- chomp; +- print " \"$_\\0\"\n"; +- $sizes[$i++] = $counter; +- $counter += length 1 + $_; +-} +-print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n "; +-for ($j = 0; $j < $i; ++$j) { +- printf "$sizes[$j], "; +-} +-print "0\n};\n"; +-===== PERL SCRIPT ==== +- +- * The input data is as follows (copied from qxmlstream.h): +-NoToken +-Invalid +-StartDocument +-EndDocument +-StartElement +-EndElement +-Characters +-Comment +-DTD +-EntityReference +-ProcessingInstruction +-*/ +-static const char QXmlStreamReader_tokenTypeString_string[] = +- "NoToken\0" +- "Invalid\0" +- "StartDocument\0" +- "EndDocument\0" +- "StartElement\0" +- "EndElement\0" +- "Characters\0" +- "Comment\0" +- "DTD\0" +- "EntityReference\0" +- "ProcessingInstruction\0"; +- +-static const short QXmlStreamReader_tokenTypeString_indices[] = { +- 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0 +-}; +- ++static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray( ++ "NoToken", ++ "Invalid", ++ "StartDocument", ++ "EndDocument", ++ "StartElement", ++ "EndElement", ++ "Characters", ++ "Comment", ++ "DTD", ++ "EntityReference", ++ "ProcessingInstruction" ++); + + /*! + \property QXmlStreamReader::namespaceProcessing +@@ -721,8 +687,7 @@ bool QXmlStreamReader::namespaceProcessing() const + QString QXmlStreamReader::tokenString() const + { + Q_D(const QXmlStreamReader); +- return QLatin1StringView(QXmlStreamReader_tokenTypeString_string + +- QXmlStreamReader_tokenTypeString_indices[d->type]); ++ return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type)); + } + + #endif // QT_NO_XMLSTREAMREADER diff --git a/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch b/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch new file mode 100644 index 0000000..b9fd729 --- /dev/null +++ b/libs/patches/qtbase-0015-QXmlStreamReader-Raise-error-on-unexpected-tokens.patch @@ -0,0 +1,394 @@ +From ce9ffbc726f7a0d90561db7206f3061371126190 Mon Sep 17 00:00:00 2001 +From: Axel Spoerl +Date: Fri, 30 Jun 2023 12:43:59 +0200 +Subject: QXmlStreamReader: Raise error on unexpected tokens + +QXmlStreamReader accepted multiple DOCTYPE elements, containing DTD +fragments in the XML prolog, and in the XML body. +Well-formed but invalid XML files - with multiple DTD fragments in +prolog and body, combined with recursive entity expansions - have +caused infinite loops in QXmlStreamReader. + +This patch implements a token check in QXmlStreamReader. +A stream is allowed to start with an XML prolog. StartDocument +and DOCTYPE elements are only allowed in this prolog, which +may also contain ProcessingInstruction and Comment elements. +As soon as anything else is seen, the prolog ends. +After that, the prolog-specific elements are treated as unexpected. +Furthermore, the prolog can contain at most one DOCTYPE element. + +Update the documentation to reflect the new behavior. +Add an autotest that checks the new error cases are correctly detected, +and no error is raised for legitimate input. + +The original OSS-Fuzz files (see bug reports) are not included in this +patch for file size reasons. They have been tested manually. Each of +them has more than one DOCTYPE element, causing infinite loops in +recursive entity expansions. The newly implemented functionality +detects those invalid DTD fragments. By raising an error, it aborts +stream reading before an infinite loop occurs. + +Thanks to OSS-Fuzz for finding this. + +Fixes: QTBUG-92113 +Fixes: QTBUG-95188 +Change-Id: I0a082b9188b2eee50b396c4d5b1c9e1fd237bbdd +Reviewed-by: Volker Hilsheimer +(cherry picked from commit c4301be7d5f94852e1b17f2c2989d5ca807855d4) +(cherry picked from commit c216c3d9859a20b3aeec985512e89316423fc3a8) +--- + src/corelib/serialization/qxmlstream.cpp | 140 +++++++++++++++++- + src/corelib/serialization/qxmlstream_p.h | 11 ++ + .../qxmlstream/tokenError/dtdInBody.xml | 20 +++ + .../qxmlstream/tokenError/multipleDtd.xml | 20 +++ + .../qxmlstream/tokenError/wellFormed.xml | 15 ++ + .../qxmlstream/tst_qxmlstream.cpp | 39 +++++ + 6 files changed, 237 insertions(+), 8 deletions(-) + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml + create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml + +diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp +index 535f98a215..050556f463 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream.cpp ++++ y/qtbase/src/corelib/serialization/qxmlstream.cpp +@@ -128,7 +128,7 @@ void reversed(const Range &&) = delete; + addData() or by waiting for it to arrive on the device(). + + \value UnexpectedElementError The parser encountered an element +- that was different to those it expected. ++ or token that was different to those it expected. + + */ + +@@ -263,13 +263,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const + + QXmlStreamReader is a well-formed XML 1.0 parser that does \e not + include external parsed entities. As long as no error occurs, the +- application code can thus be assured that the data provided by the +- stream reader satisfies the W3C's criteria for well-formed XML. For +- example, you can be certain that all tags are indeed nested and +- closed properly, that references to internal entities have been +- replaced with the correct replacement text, and that attributes have +- been normalized or added according to the internal subset of the +- DTD. ++ application code can thus be assured, that ++ \list ++ \li the data provided by the stream reader satisfies the W3C's ++ criteria for well-formed XML, ++ \li tokens are provided in a valid order. ++ \endlist ++ ++ Unless QXmlStreamReader raises an error, it guarantees the following: ++ \list ++ \li All tags are nested and closed properly. ++ \li References to internal entities have been replaced with the ++ correct replacement text. ++ \li Attributes have been normalized or added according to the ++ internal subset of the \l DTD. ++ \li Tokens of type \l StartDocument happen before all others, ++ aside from comments and processing instructions. ++ \li At most one DOCTYPE element (a token of type \l DTD) is present. ++ \li If present, the DOCTYPE appears before all other elements, ++ aside from StartDocument, comments and processing instructions. ++ \endlist ++ ++ In particular, once any token of type \l StartElement, \l EndElement, ++ \l Characters, \l EntityReference or \l EndDocument is seen, no ++ tokens of type StartDocument or DTD will be seen. If one is present in ++ the input stream, out of order, an error is raised. ++ ++ \note The token types \l Comment and \l ProcessingInstruction may appear ++ anywhere in the stream. + + If an error occurs while parsing, atEnd() and hasError() return + true, and error() returns the error that occurred. The functions +@@ -572,6 +593,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext() + d->token = -1; + return readNext(); + } ++ d->checkToken(); + return d->type; + } + +@@ -656,6 +678,11 @@ static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray( + "ProcessingInstruction" + ); + ++static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray( ++ "Prolog", ++ "Body" ++); ++ + /*! + \property QXmlStreamReader::namespaceProcessing + \brief the namespace-processing flag of the stream reader. +@@ -690,6 +717,15 @@ QString QXmlStreamReader::tokenString() const + return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type)); + } + ++/*! ++ \internal ++ \return \param loc (Prolog/Body) as a string. ++ */ ++static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt) ++{ ++ return QLatin1StringView(QXmlStreamReader_XmlContextString.at(static_cast(ctxt))); ++} ++ + #endif // QT_NO_XMLSTREAMREADER + + QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack() +@@ -776,6 +812,8 @@ void QXmlStreamReaderPrivate::init() + + type = QXmlStreamReader::NoToken; + error = QXmlStreamReader::NoError; ++ currentContext = XmlContext::Prolog; ++ foundDTD = false; + } + + /* +@@ -3692,6 +3730,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader) + } + } + ++static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type, ++ QXmlStreamReaderPrivate::XmlContext loc) ++{ ++ switch (type) { ++ case QXmlStreamReader::StartDocument: ++ case QXmlStreamReader::DTD: ++ return loc == QXmlStreamReaderPrivate::XmlContext::Prolog; ++ ++ case QXmlStreamReader::StartElement: ++ case QXmlStreamReader::EndElement: ++ case QXmlStreamReader::Characters: ++ case QXmlStreamReader::EntityReference: ++ case QXmlStreamReader::EndDocument: ++ return loc == QXmlStreamReaderPrivate::XmlContext::Body; ++ ++ case QXmlStreamReader::Comment: ++ case QXmlStreamReader::ProcessingInstruction: ++ return true; ++ ++ case QXmlStreamReader::NoToken: ++ case QXmlStreamReader::Invalid: ++ return false; ++ } ++ ++ return false; ++} ++ ++/*! ++ \internal ++ \brief QXmlStreamReader::isValidToken ++ \return \c true if \param type is a valid token type. ++ \return \c false if \param type is an unexpected token, ++ which indicates a non-well-formed or invalid XML stream. ++ */ ++bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type) ++{ ++ // Don't change currentContext, if Invalid or NoToken occur in the prolog ++ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken) ++ return false; ++ ++ // If a token type gets rejected in the body, there is no recovery ++ const bool result = isTokenAllowedInContext(type, currentContext); ++ if (result || currentContext == XmlContext::Body) ++ return result; ++ ++ // First non-Prolog token observed => switch context to body and check again. ++ currentContext = XmlContext::Body; ++ return isTokenAllowedInContext(type, currentContext); ++} ++ ++/*! ++ \internal ++ Checks token type and raises an error, if it is invalid ++ in the current context (prolog/body). ++ */ ++void QXmlStreamReaderPrivate::checkToken() ++{ ++ Q_Q(QXmlStreamReader); ++ ++ // The token type must be consumed, to keep track if the body has been reached. ++ const XmlContext context = currentContext; ++ const bool ok = isValidToken(type); ++ ++ // Do nothing if an error has been raised already (going along with an unexpected token) ++ if (error != QXmlStreamReader::Error::NoError) ++ return; ++ ++ if (!ok) { ++ raiseError(QXmlStreamReader::UnexpectedElementError, ++ QObject::tr("Unexpected token type %1 in %2.") ++ .arg(q->tokenString(), contextString(context))); ++ return; ++ } ++ ++ if (type != QXmlStreamReader::DTD) ++ return; ++ ++ // Raise error on multiple DTD tokens ++ if (foundDTD) { ++ raiseError(QXmlStreamReader::UnexpectedElementError, ++ QObject::tr("Found second DTD token in %1.").arg(contextString(context))); ++ } else { ++ foundDTD = true; ++ } ++} ++ + /*! + \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const + \since 4.5 +diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h +index 7925e59014..c24c74d5c9 100644 +--- x/qtbase/src/corelib/serialization/qxmlstream_p.h ++++ y/qtbase/src/corelib/serialization/qxmlstream_p.h +@@ -270,6 +270,17 @@ public: + QStringDecoder decoder; + bool atEnd; + ++ enum class XmlContext ++ { ++ Prolog, ++ Body, ++ }; ++ ++ XmlContext currentContext = XmlContext::Prolog; ++ bool foundDTD = false; ++ bool isValidToken(QXmlStreamReader::TokenType type); ++ void checkToken(); ++ + /*! + \sa setType() + */ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml +new file mode 100644 +index 0000000000..1c3ca4e271 +--- /dev/null ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml +@@ -0,0 +1,20 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ ++ ++ ++ ]> ++ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml +new file mode 100644 +index 0000000000..cd398c0f9f +--- /dev/null ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml +@@ -0,0 +1,20 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml +new file mode 100644 +index 0000000000..1b61a3f062 +--- /dev/null ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml +@@ -0,0 +1,15 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++]> ++ ++ ++ tst_QXmlStream ++ ++ +diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +index 7eb0aac5cc..ee962d3870 100644 +--- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp ++++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +@@ -586,6 +586,9 @@ private slots: + + void entityExpansionLimit() const; + ++ void tokenErrorHandling_data() const; ++ void tokenErrorHandling() const; ++ + private: + static QByteArray readFile(const QString &filename); + +@@ -1792,5 +1795,41 @@ void tst_QXmlStream::test_fastScanName() const + QCOMPARE(reader.error(), errorType); + } + ++void tst_QXmlStream::tokenErrorHandling_data() const ++{ ++ QTest::addColumn("fileName"); ++ QTest::addColumn("expectedError"); ++ QTest::addColumn("errorKeyWord"); ++ ++ constexpr auto invalid = QXmlStreamReader::Error::UnexpectedElementError; ++ constexpr auto valid = QXmlStreamReader::Error::NoError; ++ QTest::newRow("DtdInBody") << "dtdInBody.xml" << invalid << "DTD"; ++ QTest::newRow("multipleDTD") << "multipleDtd.xml" << invalid << "second DTD"; ++ QTest::newRow("wellFormed") << "wellFormed.xml" << valid << ""; ++} ++ ++void tst_QXmlStream::tokenErrorHandling() const ++{ ++ QFETCH(const QString, fileName); ++ QFETCH(const QXmlStreamReader::Error, expectedError); ++ QFETCH(const QString, errorKeyWord); ++ ++ const QDir dir(QFINDTESTDATA("tokenError")); ++ QFile file(dir.absoluteFilePath(fileName)); ++ ++ // Cross-compiling: File will be on host only ++ if (!file.exists()) ++ QSKIP("Testfile not found."); ++ ++ file.open(QIODevice::ReadOnly); ++ QXmlStreamReader reader(&file); ++ while (!reader.atEnd()) ++ reader.readNext(); ++ ++ QCOMPARE(reader.error(), expectedError); ++ if (expectedError != QXmlStreamReader::Error::NoError) ++ QVERIFY(reader.errorString().contains(errorKeyWord)); ++} ++ + #include "tst_qxmlstream.moc" + // vim: et:ts=4:sw=4:sts=4 diff --git a/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch b/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch new file mode 100644 index 0000000..9f06617 --- /dev/null +++ b/libs/patches/qtbase-0016-QOffsetStringArray-fix-ambiguous-qOffsetStringArray-.patch @@ -0,0 +1,42 @@ +From e6d25e8d3b67cf7d9601d3fdd07131280f8ff056 Mon Sep 17 00:00:00 2001 +From: Marc Mutz +Date: Sun, 4 Sep 2022 12:31:10 +0200 +Subject: QOffsetStringArray: fix ambiguous qOffsetStringArray overloads + +There are two qOffsetStringArray overloads: one in QT_NAMESPACE, the +other in QT_PREPEND_NAMESPACE(QtPrivate). In TUs which use using +namespace QtPrivate, a call to qOffsetStringArray() may become +ambiguous. + +Fix by renaming the qOffsetStringArray() to makeOffsetStringArray(). + +Pick-to: 6.4 6.3 6.2 +Change-Id: I242a969f363e230d6a8dfb048601a0c024724f6a +Reviewed-by: Thiago Macieira +(cherry picked from commit 21c5eeba673694f865badfd137ee9fc474177ae0) +--- + src/corelib/tools/qoffsetstringarray_p.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +index 3afb5cb731..68afef57d5 100644 +--- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h ++++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +@@ -116,7 +116,7 @@ template struct StaticMapEntry + }; + + template +-constexpr auto qOffsetStringArray(StringExtractor extractString, const T &... entries) ++constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries) + { + constexpr size_t Count = sizeof...(T); + constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); +@@ -140,7 +140,7 @@ template + constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept + { + auto extractString = [](const auto &s) -> decltype(auto) { return s; }; +- return QtPrivate::qOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); ++ return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); + } + + QT_WARNING_POP diff --git a/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch b/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch new file mode 100644 index 0000000..5f23bbb --- /dev/null +++ b/libs/patches/qtbase-0017-QOffsetStringArray-fix-size_t-qsizetype-mismatch.patch @@ -0,0 +1,31 @@ +From 72533c561d6952e63f86f11d9e4f0c6ffe8ed5a1 Mon Sep 17 00:00:00 2001 +From: Marc Mutz +Date: Mon, 5 Sep 2022 08:59:23 +0200 +Subject: QOffsetStringArray: fix size_t/qsizetype mismatch + +The sizeof operator returns, and both minifyValue and makeStaticString +accept, size_t. Don't funnel it through a qsizetype variable, then, +but maintain it as a size_t all the way. + +Pick-to: 6.4 6.3 6.2 +Task-number: QTBUG-103533 +Change-Id: I05c6a6c5da3d02daabbf1d25a15531c6f44a80ce +Reviewed-by: Sona Kurazyan +(cherry picked from commit 8932eee9a652d8a325410b147955c9939278f9ed) +--- + src/corelib/tools/qoffsetstringarray_p.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +index 68afef57d5..fbe714aca6 100644 +--- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h ++++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h +@@ -119,7 +119,7 @@ template + constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries) + { + constexpr size_t Count = sizeof...(T); +- constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); ++ constexpr size_t StringLength = (sizeof(extractString(T{})) + ...); + using MinifiedOffsetType = decltype(QtPrivate::minifyValue()); + + size_t offset = 0; diff --git a/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch b/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch new file mode 100644 index 0000000..c65a9aa --- /dev/null +++ b/libs/patches/qtconnectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch @@ -0,0 +1,137 @@ +From 37c9240e9d6d295118fcabedbaaf403310af8dba Mon Sep 17 00:00:00 2001 +From: Julian Greilich +Date: Thu, 26 Jan 2023 19:19:21 +0100 +Subject: iOS NFC: Always ensure timeout after session invalidation + +iOS needs some time after invalidating a session before a new session +can be started. Otherwise the NFC dialog of iOS will not show up. + +For restarting a session inside the iOS NearfieldManager, this was +already solved with a timeout of 2 seconds. + +This commit fixes the case, that a user of the Nearfieldmanager +restarts a session manually too fast. + +Change-Id: Ic91ad225a9cab13ba92523f33a19f44af68575a0 +Reviewed-by: Timur Pocheptsov +(cherry picked from commit 849ba86ba9a073a266219b6a39786e20f4f3ed7b) +(cherry picked from commit 5052cd14c28bbf0ff93c465a4e33bf1dbd48c7dd) +--- + src/nfc/qnearfieldmanager_ios.mm | 44 +++++++++++++++++++++---------- + src/nfc/qnearfieldmanager_ios_p.h | 5 +++- + 2 files changed, 34 insertions(+), 15 deletions(-) + +diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm +index 6fd71451..a0651626 100644 +--- x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm ++++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm +@@ -25,6 +25,10 @@ QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() + connect(this, &QNearFieldManagerPrivateImpl::didInvalidateWithError, + this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError, + Qt::QueuedConnection); ++ ++ sessionTimer.setInterval(2000); ++ sessionTimer.setSingleShot(true); ++ connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer); + } + + QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +@@ -62,7 +66,7 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access + if (@available(iOS 13, *)) + if (NFCTagReaderSession.readingAvailable) { + detectionRunning = true; +- startSession(); ++ scheduleSession(); + return true; + } + return false; +@@ -71,16 +75,28 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access + + void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage) + { +- if (detectionRunning) { +- stopSession(errorMessage); +- detectionRunning = false; +- Q_EMIT targetDetectionStopped(); +- } ++ if (!detectionRunning) ++ return; ++ ++ isSessionScheduled = false; ++ stopSession(errorMessage); ++ detectionRunning = false; ++ Q_EMIT targetDetectionStopped(); + } + ++void QNearFieldManagerPrivateImpl::scheduleSession() ++{ ++ if (sessionTimer.isActive()) { ++ isSessionScheduled = true; ++ return; ++ } ++ ++ startSession(); ++} + + void QNearFieldManagerPrivateImpl::startSession() + { ++ isSessionScheduled = false; + if (detectionRunning) + if (@available(iOS 13, *)) + [delegate startSession]; +@@ -132,17 +148,11 @@ void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *tar + void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart) + { + clearTargets(); ++ sessionTimer.start(); + + if (detectionRunning && doRestart) + { +- if (!isRestarting) { +- isRestarting = true; +- using namespace std::chrono_literals; +- QTimer::singleShot(2s, this, [this](){ +- isRestarting = false; +- startSession(); +- }); +- } ++ scheduleSession(); + return; + } + +@@ -150,4 +160,10 @@ void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart) + Q_EMIT targetDetectionStopped(); + } + ++void QNearFieldManagerPrivateImpl::onSessionTimer() ++{ ++ if (isSessionScheduled) ++ scheduleSession(); ++} ++ + QT_END_NAMESPACE +diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h +index 6aa1574e..b3668ff6 100644 +--- x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h ++++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h +@@ -54,9 +54,11 @@ Q_SIGNALS: + private: + QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) *delegate API_AVAILABLE(ios(13.0)) = nullptr; + bool detectionRunning = false; +- bool isRestarting = false; ++ bool isSessionScheduled = false; ++ QTimer sessionTimer; + QList detectedTargets; + ++ void scheduleSession(); + void startSession(); + void stopSession(const QString &error); + void clearTargets(); +@@ -65,6 +67,7 @@ private Q_SLOTS: + void onTagDiscovered(void *target); + void onTargetLost(QNearFieldTargetPrivateImpl *target); + void onDidInvalidateWithError(bool doRestart); ++ void onSessionTimer(); + }; + + diff --git a/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch b/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch new file mode 100644 index 0000000..b0a3983 --- /dev/null +++ b/libs/patches/qtdeclarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch @@ -0,0 +1,99 @@ +From 7785342c8d6fe223977958c59cd4102ed417d442 Mon Sep 17 00:00:00 2001 +From: Semih Yavuz +Date: Wed, 18 Jan 2023 15:36:23 +0100 +Subject: qmlformat: fix omitting some comments while reformatting + +We rewrite comments associated to a node on the preVisit call +(if they were marked as preComment), or postVisit( if comments were +marked as postComments) of the reformatter. If the comment +associated with a patternProperty kind of node, neither of these +functions are called. Add missing call to previsit/postVist +in the pattern property node visit. + +Pick-to: 6.4 6.5 +Fixes: QTBUG-109074 +Change-Id: If57968b3f5dbd83aa23dc2cd2bca3608ee841d49 +Reviewed-by: Sami Shalayel +Reviewed-by: Ulf Hermann +(cherry picked from commit 444d4f1f3f27a81996d9cbcc0642040b68728260) +--- + src/qmldom/qqmldomreformatter.cpp | 2 ++ + .../qmlformat/data/dontRemoveComments.formatted.qml | 13 +++++++++++++ + .../auto/qml/qmlformat/data/dontRemoveComments.qml | 13 +++++++++++++ + tests/auto/qml/qmlformat/tst_qmlformat.cpp | 3 +++ + 4 files changed, 31 insertions(+) + create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml + create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.qml + +diff --git x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp +index bb76f8f772..3dfacfc84e 100644 +--- x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp ++++ y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp +@@ -301,6 +301,7 @@ protected: + for (PatternPropertyList *it = ast; it; it = it->next) { + PatternProperty *assignment = AST::cast(it->property); + if (assignment) { ++ preVisit(assignment); + bool isStringLike = AST::cast(assignment->name) + || cast(assignment->name); + if (isStringLike) +@@ -316,6 +317,7 @@ protected: + accept(assignment->initializer); + if (it->next) + newLine(); ++ postVisit(assignment); + continue; + } + PatternPropertyList *getterSetter = AST::cast(it->next); +diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml +new file mode 100644 +index 0000000000..0c7a2829c9 +--- /dev/null ++++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml +@@ -0,0 +1,13 @@ ++Item { ++ property var test: [{ ++ // Testing ++ "foo": "bar" ++ }] ++ ++ onTestChanged: { ++ fooBar(test, { ++ // Testing ++ "foo": "bar" ++ }); ++ } ++} +diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml +new file mode 100644 +index 0000000000..1797834879 +--- /dev/null ++++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml +@@ -0,0 +1,13 @@ ++Item { ++ property var test: [{ ++// Testing ++ "foo": "bar" ++ }] ++ ++ onTestChanged: { ++ fooBar(test, { ++ // Testing ++ "foo": "bar" ++ }); ++ } ++} +diff --git x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp +index 9d7beb23a7..7755095acd 100644 +--- x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp ++++ y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp +@@ -276,6 +276,9 @@ void TestQmlformat::testFormat_data() + QTest::newRow("forWithLet") + << "forWithLet.qml" + << "forWithLet.formatted.qml" << QStringList {} << RunOption::OnCopy; ++ QTest::newRow("dontRemoveComments") ++ << "dontRemoveComments.qml" ++ << "dontRemoveComments.formatted.qml" << QStringList {} << RunOption::OnCopy; + } + + void TestQmlformat::testFormat() diff --git a/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch b/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch new file mode 100644 index 0000000..fb4f590 --- /dev/null +++ b/libs/patches/qtdeclarative-0002-QQuickItem-item-stays-pressed-after-DoubleClicks.patch @@ -0,0 +1,119 @@ +From 26cac8dada39c83cfcebd8b0bbcacf92f1ce9e9f Mon Sep 17 00:00:00 2001 +From: Sami Shalayel +Date: Mon, 17 Apr 2023 18:03:09 +0200 +Subject: QQuickItem: item stays pressed after DoubleClicks + +Amends 72651a50f83aa72998822312c7b5c6235d28978f. +This commit decided to ignore double clicks in the virtual +QQuickItem::mouseDoubleClickEvent(). +If a subclass inheriting from QQuickItem wants to not ignore +a double click, it should override mouseDoubleClickEvent() +and handle the double click event accordingly. + +Fix QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) to *not* +call the base implementation in QQuickItem after handling a double +click, because QQuickItem sets that double-click MouseEvent back to +the ignored state. + +This was leading to weird behavior on platforms with touch +screens like Android or IOS where buttons "got stuck" after +a double click. + +Fixes: QTBUG-112434 +Fixes: QTBUG-109393 +Pick-to: 6.5 +Change-Id: I774189fbcb356b07336f35f053e05a12c34ce602 +Reviewed-by: Qt CI Bot +Reviewed-by: Ivan Solovev +(cherry picked from commit d7fac6923a6d4e4ac7dc22458256366968acbdb3) +--- + src/quick/items/qquickmousearea.cpp | 5 ++++ + .../data/doubleClickInMouseArea.qml | 23 +++++++++++++++++++ + .../tst_mousearea_interop.cpp | 21 +++++++++++++++++ + 3 files changed, 49 insertions(+) + create mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml + +diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp +index 75b67d01e3..db338c7ae5 100644 +--- x/qtdeclarative/src/quick/items/qquickmousearea.cpp ++++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp +@@ -795,6 +795,11 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) + d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick); + if (d->pressed) + d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); ++ ++ // do not call the base implementation if the event is accepted ++ // because it will revert the event back to ignored state ++ if (me.isAccepted()) ++ return; + } + QQuickItem::mouseDoubleClickEvent(event); + } +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml +new file mode 100644 +index 0000000000..e43a2f3160 +--- /dev/null ++++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml +@@ -0,0 +1,23 @@ ++import QtQuick ++import QtQuick.Controls ++import QtQuick.Window ++ ++Rectangle { ++ width: 200; height: 200 ++ color: mouseArea.pressed ? "red" : "orange" ++ ++ Popup { ++ visible: true ++ closePolicy: Popup.NoAutoClose ++ width: 100 ++ height: 100 ++ contentItem: MouseArea { ++ id: mouseArea ++ ++ anchors.fill: parent ++ } ++ background: Rectangle { ++ color: "green" ++ } ++ } ++} +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +index c4059a1fbd..bc0dfbc736 100644 +--- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp ++++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +@@ -31,6 +31,7 @@ private slots: + void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); + void hoverHandlerDoesntHoverOnPress(); + void doubleClickInMouseAreaWithDragHandlerInGrandparent(); ++ void doubleClickInMouseArea(); + + private: + void createView(QScopedPointer &window, const char *fileName); +@@ -203,6 +204,26 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent() + QCOMPARE(dragActiveSpy.count(), 0); + } + ++void tst_MouseAreaInterop::doubleClickInMouseArea() ++{ ++ QQuickView window; ++ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); ++ ++ auto *ma = window.rootObject()->findChild(); ++ QVERIFY(ma); ++ QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); ++ QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); ++ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); ++ ++ // check with normal double click ++ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); ++ QCOMPARE(doubleClickSpy.count(), 1); ++ ++ // wait enough time for a wrong long press to happen ++ QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); ++ QCOMPARE(longPressSpy.count(), 0); ++} ++ + QTEST_MAIN(tst_MouseAreaInterop) + + #include "tst_mousearea_interop.moc" diff --git a/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch b/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch new file mode 100644 index 0000000..c35b191 --- /dev/null +++ b/libs/patches/qtdeclarative-0003-MouseArea-don-t-ignore-double-click-events.patch @@ -0,0 +1,283 @@ +From 65fd0af4aece6028e82e018c50583aed706dd525 Mon Sep 17 00:00:00 2001 +From: Shawn Rutledge +Date: Mon, 12 Jun 2023 22:53:23 +0200 +Subject: MouseArea: don't ignore double-click events + +In 72651a50f83aa72998822312c7b5c6235d28978f +QQuickItem::mouseDoubleClickEvent() started to ignore double-clicks by +default, which is consistent with the fact that it ignores the other +pointer event types. But now we have to worry about subclasses that +override mouseDoubleClickEvent() and call the base class implementation. + +d7fac6923a6d4e4ac7dc22458256366968acbdb3 tried to fix it but neglected +the case when the MouseArea does not have an onDoubleClicked signal +handling script. Since the QQuickMouseEvent object that we emit to QML +won't be accepted if isDoubleClickConnected() is false, and since the +code before 72651a50f83aa72998822312c7b5c6235d28978f was leaving the +event accepted regardless of whether QQuickMouseEvent was accepted, we +should not need to check it now either. Perhaps we should care about the +case when onDoubleClicked sets accepted to false, but so far that +doesn't seem very useful either: if you accept the press, a parent +MouseArea will not see either the press or the double-click; if you +ignore the press, you won't see the double-click, and a parent MouseArea +will see both by default. tst_QQuickMouseArea::clickThrough() tests +accepted = false in onDoubleClicked but not onPressed, and only with +mouse, not touch. + +Added tst_QQuickMouseArea::doubleTap(); also moved the autotest from +d7fac6923a6d4e4ac7dc22458256366968acbdb3 which has nothing to do with +pointer handlers. + +Fixes: QTBUG-112434 +Fixes: QTBUG-109393 +Pick-to: 6.6 6.5 6.5.2 +Change-Id: I426827c20cdb2373e77744987dffba59cd941edc +Reviewed-by: Fabian Kosmale +Reviewed-by: Doris Verria +(cherry picked from commit 35b5511189f0f9dbb8cfd8b3ec97cca2c65b3e2e) +--- + src/quick/items/qquickmousearea.cpp | 6 +- + .../data/doubleClickInMouseArea.qml | 23 -------- + .../tst_mousearea_interop.cpp | 21 ------- + .../qquickmousearea/tst_qquickmousearea.cpp | 56 +++++++++++++++++++ + .../data/doubleClickInMouseArea.qml | 23 ++++++++ + .../qquickpopup/tst_qquickpopup.cpp | 22 ++++++++ + 6 files changed, 103 insertions(+), 48 deletions(-) + delete mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml + create mode 100644 tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml + +diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp +index db338c7ae5..de283672cc 100644 +--- x/qtdeclarative/src/quick/items/qquickmousearea.cpp ++++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp +@@ -796,10 +796,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) + if (d->pressed) + d->doubleClick = d->isDoubleClickConnected() || me.isAccepted(); + +- // do not call the base implementation if the event is accepted +- // because it will revert the event back to ignored state +- if (me.isAccepted()) +- return; ++ // Do not call the base implementation: we don't want to call event->ignore(). ++ return; + } + QQuickItem::mouseDoubleClickEvent(event); + } +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml +deleted file mode 100644 +index e43a2f3160..0000000000 +--- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml ++++ /dev/null +@@ -1,23 +0,0 @@ +-import QtQuick +-import QtQuick.Controls +-import QtQuick.Window +- +-Rectangle { +- width: 200; height: 200 +- color: mouseArea.pressed ? "red" : "orange" +- +- Popup { +- visible: true +- closePolicy: Popup.NoAutoClose +- width: 100 +- height: 100 +- contentItem: MouseArea { +- id: mouseArea +- +- anchors.fill: parent +- } +- background: Rectangle { +- color: "green" +- } +- } +-} +diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +index bc0dfbc736..c4059a1fbd 100644 +--- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp ++++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp +@@ -31,7 +31,6 @@ private slots: + void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch(); + void hoverHandlerDoesntHoverOnPress(); + void doubleClickInMouseAreaWithDragHandlerInGrandparent(); +- void doubleClickInMouseArea(); + + private: + void createView(QScopedPointer &window, const char *fileName); +@@ -204,26 +203,6 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent() + QCOMPARE(dragActiveSpy.count(), 0); + } + +-void tst_MouseAreaInterop::doubleClickInMouseArea() +-{ +- QQuickView window; +- QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); +- +- auto *ma = window.rootObject()->findChild(); +- QVERIFY(ma); +- QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); +- QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); +- QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); +- +- // check with normal double click +- QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); +- QCOMPARE(doubleClickSpy.count(), 1); +- +- // wait enough time for a wrong long press to happen +- QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); +- QCOMPARE(longPressSpy.count(), 0); +-} +- + QTEST_MAIN(tst_MouseAreaInterop) + + #include "tst_mousearea_interop.moc" +diff --git x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +index 7da0913e0c..0c7528320e 100644 +--- x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp ++++ y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +@@ -95,6 +95,7 @@ private slots: + void pressedCanceledOnWindowDeactivate(); + void doubleClick_data() { acceptedButton_data(); } + void doubleClick(); ++ void doubleTap(); + void clickTwice_data() { acceptedButton_data(); } + void clickTwice(); + void invalidClick_data() { rejectedButton_data(); } +@@ -929,6 +930,61 @@ void tst_QQuickMouseArea::doubleClick() + QCOMPARE(window.rootObject()->property("released").toInt(), 2); + } + ++void tst_QQuickMouseArea::doubleTap() // QTBUG-112434 ++{ ++ QQuickView window; ++ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleclick.qml"))); ++ ++ QQuickMouseArea *mouseArea = window.rootObject()->findChild("mousearea"); ++ QVERIFY(mouseArea); ++ QPoint p1 = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint(); ++ ++ QTest::touchEvent(&window, device).press(0, p1); ++ QQuickTouchUtils::flush(&window); ++ QTest::touchEvent(&window, device).release(0, p1); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 1); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); ++ ++ p1 += QPoint(1, -1); // movement less than QPlatformTheme::TouchDoubleTapDistance ++ QTest::touchEvent(&window, device).press(1, p1); // touchpoint ID is different the second time ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(mouseArea->isPressed(), true); ++ // at this time QQuickDeliveryAgentPrivate::deliverTouchAsMouse() synthesizes the double-click event ++ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); ++ ++ QTest::touchEvent(&window, device).release(1, p1); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 2); ++ QCOMPARE(mouseArea->isPressed(), false); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); ++ ++ // now tap with two fingers simultaneously: only one of them generates synth-mouse ++ QPoint p2 = p1 + QPoint(50, 5); ++ QTest::touchEvent(&window, device).press(2, p1).press(3, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(mouseArea->isPressed(), true); ++ QTest::touchEvent(&window, device).release(2, p1).release(3, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 3); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); ++ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1); ++ QCOMPARE(mouseArea->isPressed(), false); ++ ++ // tap with two fingers simultaneously again: get another double-click from one point ++ p1 -= QPoint(1, -1); ++ p2 += QPoint(1, -1); ++ QTest::touchEvent(&window, device).press(4, p1).press(5, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(mouseArea->isPressed(), true); ++ QTest::touchEvent(&window, device).release(4, p1).release(5, p2); ++ QQuickTouchUtils::flush(&window); ++ QCOMPARE(window.rootObject()->property("released").toInt(), 4); ++ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2); ++ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 2); ++ QCOMPARE(mouseArea->isPressed(), false); // make sure it doesn't get stuck ++} ++ + // QTBUG-14832 + void tst_QQuickMouseArea::clickTwice() + { +diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml +new file mode 100644 +index 0000000000..e43a2f3160 +--- /dev/null ++++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml +@@ -0,0 +1,23 @@ ++import QtQuick ++import QtQuick.Controls ++import QtQuick.Window ++ ++Rectangle { ++ width: 200; height: 200 ++ color: mouseArea.pressed ? "red" : "orange" ++ ++ Popup { ++ visible: true ++ closePolicy: Popup.NoAutoClose ++ width: 100 ++ height: 100 ++ contentItem: MouseArea { ++ id: mouseArea ++ ++ anchors.fill: parent ++ } ++ background: Rectangle { ++ color: "green" ++ } ++ } ++} +diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp +index ab20bd71b4..0e8ee05725 100644 +--- x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp ++++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -89,6 +90,7 @@ private slots: + void dimmerContainmentMask(); + void shrinkPopupThatWasLargerThanWindow_data(); + void shrinkPopupThatWasLargerThanWindow(); ++ void doubleClickInMouseArea(); + + private: + static bool hasWindowActivation(); +@@ -1928,6 +1930,26 @@ void tst_QQuickPopup::shrinkPopupThatWasLargerThanWindow() + .arg(popup->height()).arg(window->height()))); + } + ++void tst_QQuickPopup::doubleClickInMouseArea() ++{ ++ QQuickView window; ++ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml"))); ++ ++ auto *ma = window.rootObject()->findChild(); ++ QVERIFY(ma); ++ QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked); ++ QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold); ++ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint(); ++ ++ // check with normal double click ++ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p); ++ QCOMPARE(doubleClickSpy.count(), 1); ++ ++ // wait enough time for a wrong long press to happen ++ QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10); ++ QCOMPARE(longPressSpy.count(), 0); ++} ++ + QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup) + + #include "tst_qquickpopup.moc" diff --git a/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch b/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch new file mode 100644 index 0000000..362eba1 --- /dev/null +++ b/libs/patches/qtscxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch @@ -0,0 +1,20 @@ +From abe6296550b5531a129b7d4a21466cdc50dbb2e0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +Date: Tue, 12 Apr 2022 10:21:19 +0200 +Subject: Make qtdeclarative optional for CONTAINER_SDK + +Change-Id: Ia25b91ea5e3716aef4cb096de1052267b70e343d +--- + dependencies.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git x/qtscxml/dependencies.yaml y/qtscxml/dependencies.yaml +index ee6f92e0..73755512 100644 +--- x/qtscxml/dependencies.yaml ++++ y/qtscxml/dependencies.yaml +@@ -4,4 +4,4 @@ dependencies: + required: true + ../qtdeclarative: + ref: a514640b2a38391fceaaac3ca01b390ad3d62f31 +- required: true ++ required: false diff --git a/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch b/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch new file mode 100644 index 0000000..864deee --- /dev/null +++ b/libs/patches/qtscxml-0002-Disable-qtscxml-library.patch @@ -0,0 +1,35 @@ +From 2fa2cbc5c55e862cee7fc495edc444c46d4193ee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= +Date: Tue, 12 Apr 2022 11:39:12 +0200 +Subject: Disable qtscxml library + +--- + src/CMakeLists.txt | 4 ++-- + tools/CMakeLists.txt | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git x/qtscxml/src/CMakeLists.txt y/qtscxml/src/CMakeLists.txt +index f1b7c2b9..7e28acc2 100644 +--- x/qtscxml/src/CMakeLists.txt ++++ y/qtscxml/src/CMakeLists.txt +@@ -1,8 +1,8 @@ + +-add_subdirectory(scxml) ++#add_subdirectory(scxml) + add_subdirectory(statemachine) + if(TARGET Qt::Qml) + add_subdirectory(statemachineqml) +- add_subdirectory(scxmlqml) ++# add_subdirectory(scxmlqml) + endif() + add_subdirectory(plugins) +diff --git x/qtscxml/tools/CMakeLists.txt y/qtscxml/tools/CMakeLists.txt +index 9726a783..956f9048 100644 +--- x/qtscxml/tools/CMakeLists.txt ++++ y/qtscxml/tools/CMakeLists.txt +@@ -1,4 +1,4 @@ + + if(QT_FEATURE_commandlineparser) +- add_subdirectory(qscxmlc) ++ #add_subdirectory(qscxmlc) + endif() diff --git a/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch b/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch new file mode 100644 index 0000000..e8f0d75 --- /dev/null +++ b/libs/patches/qtsvg-0001-QSvgFont-Initialize-used-member-remove-unused.patch @@ -0,0 +1,56 @@ +From c3b8e687ca723262f15f31b181a3e5db847afb68 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Robert=20L=C3=B6hning?= +Date: Mon, 24 Apr 2023 15:27:17 +0200 +Subject: QSvgFont: Initialize used member, remove unused + +Credit to OSS-Fuzz + +[ChangeLog][QtSvg] Fixed undefined behavior from using uninitialized +variable. + +Pick-to: 6.5 6.2 5.15 +Coverity-Id: 22618 +Change-Id: Id52277bb0e2845f4d342e187dbb8093e9276b70c +Reviewed-by: Eskil Abrahamsen Blomfeldt +(cherry picked from commit ff22c3ccf8ccf813fdcfda23f7740ba73ba5ce0a) +--- + src/svg/qsvgfont_p.h | 5 ++--- + src/svg/qsvghandler.cpp | 2 +- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git x/qtsvg/src/svg/qsvgfont_p.h y/qtsvg/src/svg/qsvgfont_p.h +index a7cc98b..9cf3dfe 100644 +--- x/qtsvg/src/svg/qsvgfont_p.h ++++ y/qtsvg/src/svg/qsvgfont_p.h +@@ -38,6 +38,7 @@ public: + class Q_SVG_PRIVATE_EXPORT QSvgFont : public QSvgRefCounted + { + public: ++ static constexpr qreal DEFAULT_UNITS_PER_EM = 1000; + QSvgFont(qreal horizAdvX); + + void setFamilyName(const QString &name); +@@ -50,9 +51,7 @@ public: + void draw(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const; + public: + QString m_familyName; +- qreal m_unitsPerEm; +- qreal m_ascent; +- qreal m_descent; ++ qreal m_unitsPerEm = DEFAULT_UNITS_PER_EM; + qreal m_horizAdvX; + QHash m_glyphs; + }; +diff --git x/qtsvg/src/svg/qsvghandler.cpp y/qtsvg/src/svg/qsvghandler.cpp +index e88e83b..1e2b2fc 100644 +--- x/qtsvg/src/svg/qsvghandler.cpp ++++ y/qtsvg/src/svg/qsvghandler.cpp +@@ -2622,7 +2622,7 @@ static bool parseFontFaceNode(QSvgStyleProperty *parent, + + qreal unitsPerEm = toDouble(unitsPerEmStr); + if (!unitsPerEm) +- unitsPerEm = 1000; ++ unitsPerEm = QSvgFont::DEFAULT_UNITS_PER_EM; + + if (!name.isEmpty()) + font->setFamilyName(name); diff --git a/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch new file mode 100644 index 0000000..0f8e56d --- /dev/null +++ b/libs/patches/qttools-0001-Disable-linguist-but-keep-translation-tools.patch @@ -0,0 +1,24 @@ +From d52894c2b13954d13ff940ba6b36e5cab7fbf3ac Mon Sep 17 00:00:00 2001 +From: Jan Moeller +Date: Mon, 14 Feb 2022 13:46:46 +0100 +Subject: Disable linguist but keep translation tools + +Change-Id: I1c54eb0e7bb86ec0861b54b5abe753c86bb57dd9 +--- + src/linguist/CMakeLists.txt | 3 --- + 1 file changed, 3 deletions(-) + +diff --git x/qttools/src/linguist/CMakeLists.txt y/qttools/src/linguist/CMakeLists.txt +index 16ff9f559..fde23b0c4 100644 +--- x/qttools/src/linguist/CMakeLists.txt ++++ y/qttools/src/linguist/CMakeLists.txt +@@ -14,9 +14,6 @@ add_subdirectory(lrelease) + add_subdirectory(lrelease-pro) + add_subdirectory(lupdate) + add_subdirectory(lupdate-pro) +-if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png) +- add_subdirectory(linguist) +-endif() + + # special case begin + # Create a fake module that would emulate the Qt5::LinguistTools CMake Config package diff --git a/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch b/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch new file mode 100644 index 0000000..6186504 --- /dev/null +++ b/libs/patches/qttools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch @@ -0,0 +1,3230 @@ +From 2cbc188e4facb12153f37a501f14384ec733c944 Mon Sep 17 00:00:00 2001 +From: Lars Schmertmann +Date: Wed, 9 Nov 2022 09:49:38 +0100 +Subject: Revert "Move UiTools and UiPlugin modules to a upper level + sub-directory" + +This partially reverts commit 6af882fa2f45f73ec2ba4066d5ae3ad072d0c5ee. + +Change-Id: I247e2189577b74d813a210ace0b49d672a90975e +--- + src/CMakeLists.txt | 5 - + src/designer/src/CMakeLists.txt | 2 + + .../src/designer/doc/qtdesigner.qdocconf | 4 +- + src/designer/src/uiplugin/CMakeLists.txt | 27 + + src/designer/src/uiplugin/customwidget.h | 62 ++ + src/designer/src/uiplugin/customwidget.qdoc | 269 ++++++ + .../src/uiplugin/qdesignerexportwidget.h | 24 + + src/designer/src/uitools/CMakeLists.txt | 46 + + src/designer/src/uitools/qtuitoolsglobal.h | 23 + + src/designer/src/uitools/quiloader.cpp | 914 ++++++++++++++++++ + src/designer/src/uitools/quiloader.h | 61 ++ + src/designer/src/uitools/quiloader_p.h | 77 ++ + src/uiplugin/CMakeLists.txt | 27 - + src/uiplugin/customwidget.h | 62 -- + src/uiplugin/customwidget.qdoc | 269 ------ + src/uiplugin/qdesignerexportwidget.h | 24 - + src/uitools/CMakeLists.txt | 47 - + src/uitools/qtuitoolsglobal.h | 24 - + src/uitools/quiloader.cpp | 914 ------------------ + src/uitools/quiloader.h | 61 -- + src/uitools/quiloader_p.h | 77 -- + sync.profile | 4 +- + 22 files changed, 1509 insertions(+), 1514 deletions(-) + create mode 100644 src/designer/src/uiplugin/CMakeLists.txt + create mode 100644 src/designer/src/uiplugin/customwidget.h + create mode 100644 src/designer/src/uiplugin/customwidget.qdoc + create mode 100644 src/designer/src/uiplugin/qdesignerexportwidget.h + create mode 100644 src/designer/src/uitools/CMakeLists.txt + create mode 100644 src/designer/src/uitools/qtuitoolsglobal.h + create mode 100644 src/designer/src/uitools/quiloader.cpp + create mode 100644 src/designer/src/uitools/quiloader.h + create mode 100644 src/designer/src/uitools/quiloader_p.h + delete mode 100644 src/uiplugin/CMakeLists.txt + delete mode 100644 src/uiplugin/customwidget.h + delete mode 100644 src/uiplugin/customwidget.qdoc + delete mode 100644 src/uiplugin/qdesignerexportwidget.h + delete mode 100644 src/uitools/CMakeLists.txt + delete mode 100644 src/uitools/qtuitoolsglobal.h + delete mode 100644 src/uitools/quiloader.cpp + delete mode 100644 src/uitools/quiloader.h + delete mode 100644 src/uitools/quiloader_p.h + +diff --git x/qttools/src/CMakeLists.txt y/qttools/src/CMakeLists.txt +index b42cd4946..cb0c21a70 100644 +--- x/qttools/src/CMakeLists.txt ++++ y/qttools/src/CMakeLists.txt +@@ -21,11 +21,6 @@ qt_exclude_tool_directories_from_default_target( + qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake") + # special case end + +-if(TARGET Qt::Widgets) +- add_subdirectory(uiplugin) +- add_subdirectory(uitools) +-endif() +- + add_subdirectory(global) # special case add as first directory + if(QT_FEATURE_linguist) + add_subdirectory(linguist) +diff --git x/qttools/src/designer/src/CMakeLists.txt y/qttools/src/designer/src/CMakeLists.txt +index 31fc1734e..32fb45160 100644 +--- x/qttools/src/designer/src/CMakeLists.txt ++++ y/qttools/src/designer/src/CMakeLists.txt +@@ -8,6 +8,8 @@ qt_exclude_tool_directories_from_default_target( + plugins + ) + ++add_subdirectory(uiplugin) ++add_subdirectory(uitools) + if(QT_FEATURE_process) + add_subdirectory(lib) + add_subdirectory(components) +diff --git x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf +index 75c8c78dd..964fb47ed 100644 +--- x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf ++++ y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf +@@ -28,11 +28,11 @@ qhp.QtDesigner.subprojects.classes.sortPages = true + language = Cpp + + headerdirs += .. \ +- ../../../../uiplugin \ ++ ../../uiplugin \ + ../../lib + + sourcedirs = .. \ +- ../../../../uiplugin \ ++ ../../uiplugin \ + ../../lib + + exampledirs = ../../../../../examples/designer \ +diff --git x/qttools/src/designer/src/uiplugin/CMakeLists.txt y/qttools/src/designer/src/uiplugin/CMakeLists.txt +new file mode 100644 +index 000000000..4fedf8e33 +--- /dev/null ++++ y/qttools/src/designer/src/uiplugin/CMakeLists.txt +@@ -0,0 +1,27 @@ ++# Generated from uiplugin.pro. ++ ++##################################################################### ++## UiPlugin Module: ++##################################################################### ++ ++qt_internal_add_module(UiPlugin ++ NO_PRIVATE_MODULE ++ HEADER_MODULE ++ QMAKE_MODULE_CONFIG designer_defines ++ PUBLIC_LIBRARIES ++ Qt::Core ++ Qt::Gui ++ Qt::Widgets ++) ++ ++# special case begin ++set(is_plugin "$") ++target_compile_definitions( ++ UiPlugin ++ INTERFACE ++ $<$:QDESIGNER_EXPORT_WIDGETS> ++) ++# special case end ++ ++#### Keys ignored in scope 1:.:.:uiplugin.pro:: ++# MODULE_CONFIG = "designer_defines" +diff --git x/qttools/src/designer/src/uiplugin/customwidget.h y/qttools/src/designer/src/uiplugin/customwidget.h +new file mode 100644 +index 000000000..2a47a32f8 +--- /dev/null ++++ y/qttools/src/designer/src/uiplugin/customwidget.h +@@ -0,0 +1,62 @@ ++// Copyright (C) 2016 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 ++ ++#ifndef CUSTOMWIDGET_H ++#define CUSTOMWIDGET_H ++ ++#include ++#include ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++class QWidget; ++class QDesignerFormEditorInterface; ++ ++class QDesignerCustomWidgetInterface ++{ ++public: ++ virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable ++ ++ virtual QString name() const = 0; ++ virtual QString group() const = 0; ++ virtual QString toolTip() const = 0; ++ virtual QString whatsThis() const = 0; ++ virtual QString includeFile() const = 0; ++ virtual QIcon icon() const = 0; ++ ++ virtual bool isContainer() const = 0; ++ ++ virtual QWidget *createWidget(QWidget *parent) = 0; ++ ++ virtual bool isInitialized() const { return false; } ++ virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); } ++ ++ virtual QString domXml() const ++ { ++ return QString::fromUtf8("") ++ .arg(name()).arg(name().toLower()); ++ } ++ ++ virtual QString codeTemplate() const { return QString(); } ++}; ++ ++#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface" ++ ++Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid) ++ ++class QDesignerCustomWidgetCollectionInterface ++{ ++public: ++ virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable ++ ++ virtual QList customWidgets() const = 0; ++}; ++ ++#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface" ++ ++Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid) ++ ++QT_END_NAMESPACE ++ ++#endif // CUSTOMWIDGET_H +diff --git x/qttools/src/designer/src/uiplugin/customwidget.qdoc y/qttools/src/designer/src/uiplugin/customwidget.qdoc +new file mode 100644 +index 000000000..557e9a454 +--- /dev/null ++++ y/qttools/src/designer/src/uiplugin/customwidget.qdoc +@@ -0,0 +1,269 @@ ++// Copyright (C) 2016 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only ++ ++/*! ++ \class QDesignerCustomWidgetInterface ++ ++ \brief The QDesignerCustomWidgetInterface class enables Qt Designer ++ to access and construct custom widgets. ++ ++ \inmodule QtDesigner ++ ++ QDesignerCustomWidgetInterface provides a custom widget with an ++ interface. The class contains a set of functions that must be subclassed ++ to return basic information about the widget, such as its class name and ++ the name of its header file. Other functions must be implemented to ++ initialize the plugin when it is loaded, and to construct instances of ++ the custom widget for \QD to use. ++ ++ When implementing a custom widget you must subclass ++ QDesignerCustomWidgetInterface to expose your widget to \QD. For ++ example, this is the declaration for the plugin used in the ++ \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that ++ enables an analog clock custom widget to be used by \QD: ++ ++ \snippet customwidgetplugin/customwidgetplugin.h 0 ++ ++ Note that the only part of the class definition that is specific ++ to this particular custom widget is the class name. In addition, ++ since we are implementing an interface, we must ensure that it's ++ made known to the meta object system using the Q_INTERFACES() ++ macro. This enables \QD to use the qobject_cast() function to ++ query for supported interfaces using nothing but a QObject ++ pointer. ++ ++ After \QD loads a custom widget plugin, it calls the interface's ++ initialize() function to enable it to set up any resources that it ++ may need. This function is called with a QDesignerFormEditorInterface ++ parameter that provides the plugin with a gateway to all of \QD's API. ++ ++ \QD constructs instances of the custom widget by calling the plugin's ++ createWidget() function with a suitable parent widget. Plugins must ++ construct and return an instance of a custom widget with the specified ++ parent widget. ++ ++ Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA() ++ macro. For example, if a library called \c libcustomwidgetplugin.so ++ (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget ++ class called \c MyCustomWidget, we can export it by adding the ++ following line to the file containing the plugin header: ++ ++ \snippet plugins/doc_src_qtdesigner.cpp 14 ++ ++ This macro ensures that \QD can access and construct the custom widget. ++ Without this macro, there is no way for \QD to use it. ++ ++ When implementing a custom widget plugin, you build it as a ++ separate library. If you want to include several custom widget ++ plugins in the same library, you must in addition subclass ++ QDesignerCustomWidgetCollectionInterface. ++ ++ \warning If your custom widget plugin contains QVariant ++ properties, be aware that only the following \l ++ {QVariant::Type}{types} are supported: ++ ++ \list ++ \li QVariant::ByteArray ++ \li QVariant::Bool ++ \li QVariant::Color ++ \li QVariant::Cursor ++ \li QVariant::Date ++ \li QVariant::DateTime ++ \li QVariant::Double ++ \li QVariant::Int ++ \li QVariant::Point ++ \li QVariant::Rect ++ \li QVariant::Size ++ \li QVariant::SizePolicy ++ \li QVariant::String ++ \li QVariant::Time ++ \li QVariant::UInt ++ \endlist ++ ++ For a complete example using the QDesignerCustomWidgetInterface ++ class, see the \l {customwidgetplugin}{Custom Widget ++ Example}. The example shows how to create a custom widget plugin ++ for \QD. ++ ++ \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer} ++*/ ++ ++/*! ++ \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface() ++ ++ Destroys the custom widget interface. ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::name() const ++ ++ Returns the class name of the custom widget supplied by the interface. ++ ++ The name returned \e must be identical to the class name used for the ++ custom widget. ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::group() const ++ ++ Returns the name of the group to which the custom widget belongs. ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::toolTip() const ++ ++ Returns a short description of the widget that can be used by \QD ++ in a tool tip. ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::whatsThis() const ++ ++ Returns a description of the widget that can be used by \QD in ++ "What's This?" help for the widget. ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::includeFile() const ++ ++ Returns the path to the include file that \l uic uses when ++ creating code for the custom widget. ++*/ ++ ++/*! ++ \fn QIcon QDesignerCustomWidgetInterface::icon() const ++ ++ Returns the icon used to represent the custom widget in \QD's ++ widget box. ++*/ ++ ++/*! ++ \fn bool QDesignerCustomWidgetInterface::isContainer() const ++ ++ Returns true if the custom widget is intended to be used as a ++ container; otherwise returns false. ++ ++ Most custom widgets are not used to hold other widgets, so their ++ implementations of this function will return false, but custom ++ containers will return true to ensure that they behave correctly ++ in \QD. ++*/ ++ ++/*! ++ \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent) ++ ++ Returns a new instance of the custom widget, with the given \a ++ parent. ++*/ ++ ++/*! ++ \fn bool QDesignerCustomWidgetInterface::isInitialized() const ++ ++ Returns true if the widget has been initialized; otherwise returns ++ false. ++ ++ \sa initialize() ++*/ ++ ++/*! ++ \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) ++ ++ Initializes the widget for use with the specified \a formEditor ++ interface. ++ ++ \sa isInitialized() ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::domXml() const ++ ++ Returns the XML that is used to describe the custom widget's ++ properties to \QD. ++*/ ++ ++/*! ++ \fn QString QDesignerCustomWidgetInterface::codeTemplate() const ++ ++ This function is reserved for future use by \QD. ++ ++ \omit ++ Returns the code template that \QD includes in forms that contain ++ the custom widget when they are saved. ++ \endomit ++*/ ++ ++/*! ++ \macro QDESIGNER_WIDGET_EXPORT ++ \relates QDesignerCustomWidgetInterface ++ \since 4.1 ++ ++ This macro is used when defining custom widgets to ensure that they are ++ correctly exported from plugins for use with \QD. ++ ++ On some platforms, the symbols required by \QD to create new widgets ++ are removed from plugins by the build system, making them unusable. ++ Using this macro ensures that the symbols are retained on those platforms, ++ and has no side effects on other platforms. ++ ++ For example, the \l{worldtimeclockplugin}{World Time Clock Plugin} ++ example exports a custom widget class with the following declaration: ++ ++ \snippet worldtimeclockplugin/worldtimeclock.h 0 ++ \dots ++ \snippet worldtimeclockplugin/worldtimeclock.h 2 ++ ++ \sa {Creating Custom Widgets for Qt Designer} ++*/ ++ ++ ++ ++ ++ ++/*! ++ \class QDesignerCustomWidgetCollectionInterface ++ ++ \brief The QDesignerCustomWidgetCollectionInterface class allows ++ you to include several custom widgets in one single library. ++ ++ \inmodule QtDesigner ++ ++ When implementing a custom widget plugin, you build it as a ++ separate library. If you want to include several custom widget ++ plugins in the same library, you must in addition subclass ++ QDesignerCustomWidgetCollectionInterface. ++ ++ QDesignerCustomWidgetCollectionInterface contains one single ++ function returning a list of the collection's ++ QDesignerCustomWidgetInterface objects. For example, if you have ++ several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and ++ \c CustomWidgetThree, the class definition may look like this: ++ ++ \snippet plugins/doc_src_qtdesigner.cpp 12 ++ ++ In the class constructor you add the interfaces to your custom ++ widgets to the list which you return in the customWidgets() ++ function: ++ ++ \snippet plugins/doc_src_qtdesigner.cpp 13 ++ ++ Note that instead of exporting each custom widget plugin using the ++ Q_PLUGIN_METADATA() macro, you export the entire collection. The ++ Q_PLUGIN_METADATA() macro ensures that \QD can access and construct ++ the custom widgets. Without this macro, there is no way for \QD to ++ use them. ++ ++ \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for ++ Qt Designer} ++*/ ++ ++/*! ++ \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() { ++ ++ Destroys the custom widget collection interface. ++*/ ++ ++/*! ++ \fn QList QDesignerCustomWidgetCollectionInterface::customWidgets() const ++ ++ Returns a list of interfaces to the collection's custom widgets. ++*/ +diff --git x/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h +new file mode 100644 +index 000000000..d90e9b217 +--- /dev/null ++++ y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h +@@ -0,0 +1,24 @@ ++// Copyright (C) 2016 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 ++ ++#ifndef QDESIGNEREXPORTWIDGET_H ++#define QDESIGNEREXPORTWIDGET_H ++ ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++#if 0 ++// pragma for syncqt, don't remove. ++#pragma qt_class(QDesignerExportWidget) ++#endif ++ ++#if defined(QDESIGNER_EXPORT_WIDGETS) ++# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT ++#else ++# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT ++#endif ++ ++QT_END_NAMESPACE ++ ++#endif //QDESIGNEREXPORTWIDGET_H +diff --git x/qttools/src/designer/src/uitools/CMakeLists.txt y/qttools/src/designer/src/uitools/CMakeLists.txt +new file mode 100644 +index 000000000..6040ac71d +--- /dev/null ++++ y/qttools/src/designer/src/uitools/CMakeLists.txt +@@ -0,0 +1,46 @@ ++# Generated from uitools.pro. ++ ++##################################################################### ++## UiTools Module: ++##################################################################### ++ ++qt_internal_add_module(UiTools ++ SOURCES ++ ../lib/uilib/abstractformbuilder.cpp ../lib/uilib/abstractformbuilder.h ++ ../lib/uilib/formbuilder.cpp ../lib/uilib/formbuilder.h ++ ../lib/uilib/formbuilderextra.cpp ../lib/uilib/formbuilderextra_p.h ++ ../lib/uilib/properties.cpp ../lib/uilib/properties_p.h ++ ../lib/uilib/resourcebuilder.cpp ../lib/uilib/resourcebuilder_p.h ++ ../lib/uilib/textbuilder.cpp ../lib/uilib/textbuilder_p.h ++ ../lib/uilib/ui4.cpp ../lib/uilib/ui4_p.h ++ quiloader.cpp quiloader.h ++ DEFINES ++ QFORMINTERNAL_NAMESPACE ++ QT_DESIGNER ++ QT_DESIGNER_STATIC ++ QT_USE_QSTRINGBUILDER ++ INCLUDE_DIRECTORIES ++ ../lib/uilib ++ LIBRARIES ++ Qt::UiPlugin ++ PUBLIC_LIBRARIES ++ Qt::Core ++ Qt::Gui ++ Qt::Widgets ++) ++ ++## Scopes: ++##################################################################### ++ ++qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets ++ PUBLIC_LIBRARIES ++ Qt::OpenGLWidgets ++) ++ ++qt_internal_extend_target(UiTools CONDITION QT_FEATURE_opengl ++ LIBRARIES ++ Qt::OpenGL ++) ++qt_internal_add_docs(UiTools ++ doc/qtuitools.qdocconf ++) +diff --git x/qttools/src/designer/src/uitools/qtuitoolsglobal.h y/qttools/src/designer/src/uitools/qtuitoolsglobal.h +new file mode 100644 +index 000000000..6874fb15b +--- /dev/null ++++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h +@@ -0,0 +1,23 @@ ++// Copyright (C) 2020 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++#ifndef QTUITOOLSGLOBAL_H ++#define QTUITOOLSGLOBAL_H ++ ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++#ifndef QT_STATIC ++# if defined(QT_BUILD_UITOOLS_LIB) ++# define Q_UITOOLS_EXPORT Q_DECL_EXPORT ++# else ++# define Q_UITOOLS_EXPORT Q_DECL_IMPORT ++# endif ++#else ++# define Q_UITOOLS_EXPORT ++#endif ++ ++QT_END_NAMESPACE ++ ++#endif // QTUITOOLSGLOBAL_H +diff --git x/qttools/src/designer/src/uitools/quiloader.cpp y/qttools/src/designer/src/uitools/quiloader.cpp +new file mode 100644 +index 000000000..a06d4717b +--- /dev/null ++++ y/qttools/src/designer/src/uitools/quiloader.cpp +@@ -0,0 +1,914 @@ ++// Copyright (C) 2020 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++ ++#include "quiloader.h" ++#include "quiloader_p.h" ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++typedef QMap widget_map; ++Q_GLOBAL_STATIC(widget_map, g_widgets) ++ ++class QUiLoader; ++class QUiLoaderPrivate; ++ ++#ifndef QT_NO_DATASTREAM ++// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based ++// mime data when dragging items in views with QAbstractItemView::InternalMove. ++QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) ++{ ++ out << s.qualifier() << s.value(); ++ return out; ++} ++ ++QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) ++{ ++ QByteArray qualifier, value; ++ in >> qualifier >> value; ++ s.setQualifier(qualifier); ++ s.setValue(value); ++ return in; ++} ++#endif // QT_NO_DATASTREAM ++ ++QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const ++{ ++ return idBased ++ ? qtTrId(m_qualifier.constData()) ++ : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData()); ++} ++ ++#ifdef QFORMINTERNAL_NAMESPACE ++namespace QFormInternal ++{ ++#endif ++ ++class TranslatingTextBuilder : public QTextBuilder ++{ ++public: ++ explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) : ++ m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {} ++ ++ QVariant loadText(const DomProperty *icon) const override; ++ ++ QVariant toNativeValue(const QVariant &value) const override; ++ ++ bool idBased() const { return m_idBased; } ++ ++private: ++ bool m_idBased; ++ bool m_trEnabled; ++ QByteArray m_className; ++}; ++ ++QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const ++{ ++ const DomString *str = text->elementString(); ++ if (!str) ++ return QVariant(); ++ if (str->hasAttributeNotr()) { ++ const QString notr = str->attributeNotr(); ++ if (notr == QStringLiteral("true") || notr == QStringLiteral("yes")) ++ return QVariant::fromValue(str->text()); ++ } ++ QUiTranslatableStringValue strVal; ++ strVal.setValue(str->text().toUtf8()); ++ if (m_idBased) ++ strVal.setQualifier(str->attributeId().toUtf8()); ++ else if (str->hasAttributeComment()) ++ strVal.setQualifier(str->attributeComment().toUtf8()); ++ return QVariant::fromValue(strVal); ++} ++ ++QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const ++{ ++ if (value.canConvert()) { ++ QUiTranslatableStringValue tsv = qvariant_cast(value); ++ if (!m_trEnabled) ++ return QString::fromUtf8(tsv.value().constData()); ++ return QVariant::fromValue(tsv.translate(m_className, m_idBased)); ++ } ++ if (value.canConvert()) ++ return QVariant::fromValue(qvariant_cast(value)); ++ return value; ++} ++ ++// This is "exported" to linguist ++const QUiItemRolePair qUiItemRoles[] = { ++ { Qt::DisplayRole, Qt::DisplayPropertyRole }, ++#if QT_CONFIG(tooltip) ++ { Qt::ToolTipRole, Qt::ToolTipPropertyRole }, ++#endif ++#if QT_CONFIG(statustip) ++ { Qt::StatusTipRole, Qt::StatusTipPropertyRole }, ++#endif ++#if QT_CONFIG(whatsthis) ++ { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole }, ++#endif ++ { -1 , -1 } ++}; ++ ++static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased) ++{ ++ const QUiItemRolePair *irs = qUiItemRoles; ++ ++ int cnt = item->columnCount(); ++ for (int i = 0; i < cnt; ++i) { ++ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { ++ QVariant v = item->data(i, irs[j].shadowRole); ++ if (v.isValid()) { ++ QUiTranslatableStringValue tsv = qvariant_cast(v); ++ item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased)); ++ } ++ } ++ } ++ ++ cnt = item->childCount(); ++ for (int i = 0; i < cnt; ++i) ++ recursiveReTranslate(item->child(i), class_name, idBased); ++} ++ ++template ++static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased) ++{ ++ const QUiItemRolePair *irs = qUiItemRoles; ++ ++ for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { ++ QVariant v = item->data(irs[j].shadowRole); ++ if (v.isValid()) { ++ QUiTranslatableStringValue tsv = qvariant_cast(v); ++ item->setData(irs[j].realRole, tsv.translate(class_name, idBased)); ++ } ++ } ++} ++ ++static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased) ++{ ++ if (item) ++ reTranslateWidgetItem(item, class_name, idBased); ++} ++ ++#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \ ++ do { \ ++ QVariant v = mainWidget->widget(i)->property(propName); \ ++ if (v.isValid()) { \ ++ QUiTranslatableStringValue tsv = qvariant_cast(v); \ ++ mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \ ++ } \ ++ } while (0) ++ ++class TranslationWatcher: public QObject ++{ ++ Q_OBJECT ++ ++public: ++ explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased): ++ QObject(parent), ++ m_className(className), ++ m_idBased(idBased) ++ { ++ } ++ ++ bool eventFilter(QObject *o, QEvent *event) override ++ { ++ if (event->type() == QEvent::LanguageChange) { ++ const auto &dynamicPropertyNames = o->dynamicPropertyNames(); ++ for (const QByteArray &prop : dynamicPropertyNames) { ++ if (prop.startsWith(PROP_GENERIC_PREFIX)) { ++ const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); ++ const QUiTranslatableStringValue tsv = ++ qvariant_cast(o->property(prop)); ++ o->setProperty(propName, tsv.translate(m_className, m_idBased)); ++ } ++ } ++ if (0) { ++#if QT_CONFIG(tabwidget) ++ } else if (QTabWidget *tabw = qobject_cast(o)) { ++ const int cnt = tabw->count(); ++ for (int i = 0; i < cnt; ++i) { ++ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT); ++#if QT_CONFIG(tooltip) ++ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP); ++# endif ++#if QT_CONFIG(whatsthis) ++ RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); ++# endif ++ } ++#endif ++#if QT_CONFIG(listwidget) ++ } else if (QListWidget *listw = qobject_cast(o)) { ++ const int cnt = listw->count(); ++ for (int i = 0; i < cnt; ++i) ++ reTranslateWidgetItem(listw->item(i), m_className, m_idBased); ++#endif ++#if QT_CONFIG(treewidget) ++ } else if (QTreeWidget *treew = qobject_cast(o)) { ++ if (QTreeWidgetItem *item = treew->headerItem()) ++ recursiveReTranslate(item, m_className, m_idBased); ++ const int cnt = treew->topLevelItemCount(); ++ for (int i = 0; i < cnt; ++i) { ++ QTreeWidgetItem *item = treew->topLevelItem(i); ++ recursiveReTranslate(item, m_className, m_idBased); ++ } ++#endif ++#if QT_CONFIG(tablewidget) ++ } else if (QTableWidget *tablew = qobject_cast(o)) { ++ const int row_cnt = tablew->rowCount(); ++ const int col_cnt = tablew->columnCount(); ++ for (int j = 0; j < col_cnt; ++j) ++ reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased); ++ for (int i = 0; i < row_cnt; ++i) { ++ reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased); ++ for (int j = 0; j < col_cnt; ++j) ++ reTranslateTableItem(tablew->item(i, j), m_className, m_idBased); ++ } ++#endif ++#if QT_CONFIG(combobox) ++ } else if (QComboBox *combow = qobject_cast(o)) { ++ if (!qobject_cast(o)) { ++ const int cnt = combow->count(); ++ for (int i = 0; i < cnt; ++i) { ++ const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole); ++ if (v.isValid()) { ++ QUiTranslatableStringValue tsv = qvariant_cast(v); ++ combow->setItemText(i, tsv.translate(m_className, m_idBased)); ++ } ++ } ++ } ++#endif ++#if QT_CONFIG(toolbox) ++ } else if (QToolBox *toolw = qobject_cast(o)) { ++ const int cnt = toolw->count(); ++ for (int i = 0; i < cnt; ++i) { ++ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT); ++#if QT_CONFIG(tooltip) ++ RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP); ++# endif ++ } ++#endif ++ } ++ } ++ return false; ++ } ++ ++private: ++ QByteArray m_className; ++ bool m_idBased; ++}; ++ ++class FormBuilderPrivate: public QFormBuilder ++{ ++ friend class QT_PREPEND_NAMESPACE(QUiLoader); ++ friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate); ++ using ParentClass = QFormBuilder; ++ ++public: ++ QUiLoader *loader = nullptr; ++ ++ bool dynamicTr = false; ++ bool trEnabled = true; ++ ++ FormBuilderPrivate() = default; ++ ++ QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name) ++ { ++ return ParentClass::createWidget(className, parent, name); ++ } ++ ++ QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name) ++ { ++ return ParentClass::createLayout(className, parent, name); ++ } ++ ++ QAction *defaultCreateAction(QObject *parent, const QString &name) ++ { ++ return ParentClass::createAction(parent, name); ++ } ++ ++ QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name) ++ { ++ return ParentClass::createActionGroup(parent, name); ++ } ++ ++ QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override ++ { ++ if (QWidget *widget = loader->createWidget(className, parent, name)) { ++ widget->setObjectName(name); ++ return widget; ++ } ++ ++ return nullptr; ++ } ++ ++ QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override ++ { ++ if (QLayout *layout = loader->createLayout(className, parent, name)) { ++ layout->setObjectName(name); ++ return layout; ++ } ++ ++ return nullptr; ++ } ++ ++ QActionGroup *createActionGroup(QObject *parent, const QString &name) override ++ { ++ if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) { ++ actionGroup->setObjectName(name); ++ return actionGroup; ++ } ++ ++ return nullptr; ++ } ++ ++ QAction *createAction(QObject *parent, const QString &name) override ++ { ++ if (QAction *action = loader->createAction(parent, name)) { ++ action->setObjectName(name); ++ return action; ++ } ++ ++ return nullptr; ++ } ++ ++ void applyProperties(QObject *o, const QList &properties) override; ++ QWidget *create(DomUI *ui, QWidget *parentWidget) override; ++ QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override; ++ bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override; ++ ++private: ++ QByteArray m_class; ++ TranslationWatcher *m_trwatch = nullptr; ++ bool m_idBased = false; ++}; ++ ++static QString convertTranslatable(const DomProperty *p, const QByteArray &className, ++ bool idBased, QUiTranslatableStringValue *strVal) ++{ ++ if (p->kind() != DomProperty::String) ++ return QString(); ++ const DomString *dom_str = p->elementString(); ++ if (!dom_str) ++ return QString(); ++ if (dom_str->hasAttributeNotr()) { ++ const QString notr = dom_str->attributeNotr(); ++ if (notr == QStringLiteral("yes") || notr == QStringLiteral("true")) ++ return QString(); ++ } ++ strVal->setValue(dom_str->text().toUtf8()); ++ strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8()); ++ if (strVal->value().isEmpty() && strVal->qualifier().isEmpty()) ++ return QString(); ++ return strVal->translate(className, idBased); ++} ++ ++void FormBuilderPrivate::applyProperties(QObject *o, const QList &properties) ++{ ++ QFormBuilder::applyProperties(o, properties); ++ ++ if (!m_trwatch) ++ m_trwatch = new TranslationWatcher(o, m_class, m_idBased); ++ ++ if (properties.isEmpty()) ++ return; ++ ++ // Unlike string item roles, string properties are not loaded via the textBuilder ++ // (as they are "shadowed" by the property sheets in designer). So do the initial ++ // translation here. ++ bool anyTrs = false; ++ for (const DomProperty *p : properties) { ++ QUiTranslatableStringValue strVal; ++ const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); ++ if (text.isEmpty()) ++ continue; ++ const QByteArray name = p->attributeName().toUtf8(); ++ if (dynamicTr) { ++ const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name); ++ o->setProperty(dynname, QVariant::fromValue(strVal)); ++ anyTrs = trEnabled; ++ } ++ if (p->elementString()->text() != text) ++ o->setProperty(name, text); ++ } ++ if (anyTrs) ++ o->installEventFilter(m_trwatch); ++} ++ ++QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget) ++{ ++ m_class = ui->elementClass().toUtf8(); ++ m_trwatch = nullptr; ++ m_idBased = ui->attributeIdbasedtr(); ++ setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class)); ++ return QFormBuilder::create(ui, parentWidget); ++} ++ ++QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget) ++{ ++ QWidget *w = QFormBuilder::create(ui_widget, parentWidget); ++ if (w == nullptr) ++ return nullptr; ++ ++ if (0) { ++#if QT_CONFIG(tabwidget) ++ } else if (qobject_cast(w)) { ++#endif ++#if QT_CONFIG(listwidget) ++ } else if (qobject_cast(w)) { ++#endif ++#if QT_CONFIG(treewidget) ++ } else if (qobject_cast(w)) { ++#endif ++#if QT_CONFIG(tablewidget) ++ } else if (qobject_cast(w)) { ++#endif ++#if QT_CONFIG(combobox) ++ } else if (qobject_cast(w)) { ++ if (qobject_cast(w)) ++ return w; ++#endif ++#if QT_CONFIG(toolbox) ++ } else if (qobject_cast(w)) { ++#endif ++ } else { ++ return w; ++ } ++ if (dynamicTr && trEnabled) ++ w->installEventFilter(m_trwatch); ++ return w; ++} ++ ++#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \ ++ do { \ ++ if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \ ++ QUiTranslatableStringValue strVal; \ ++ const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \ ++ if (!text.isEmpty()) { \ ++ if (dynamicTr) \ ++ mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \ ++ mainWidget->setter(i, text); \ ++ } \ ++ } \ ++ } while (0) ++ ++bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) ++{ ++ if (parentWidget == nullptr) ++ return true; ++ ++ if (!ParentClass::addItem(ui_widget, widget, parentWidget)) ++ return false; ++ ++ // Check special cases. First: Custom container ++ const QString className = QLatin1String(parentWidget->metaObject()->className()); ++ if (!d->customWidgetAddPageMethod(className).isEmpty()) ++ return true; ++ ++ const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); ++ ++ if (0) { ++#if QT_CONFIG(tabwidget) ++ } else if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { ++ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); ++ const int i = tabWidget->count() - 1; ++ TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT); ++#if QT_CONFIG(tooltip) ++ TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP); ++# endif ++#if QT_CONFIG(whatsthis) ++ TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); ++# endif ++#endif ++#if QT_CONFIG(toolbox) ++ } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { ++ const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); ++ const int i = toolBox->count() - 1; ++ TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT); ++#if QT_CONFIG(tooltip) ++ TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP); ++# endif ++#endif ++ } ++ ++ return true; ++} ++ ++#ifdef QFORMINTERNAL_NAMESPACE ++} ++#endif ++ ++class QUiLoaderPrivate ++{ ++public: ++#ifdef QFORMINTERNAL_NAMESPACE ++ QFormInternal::FormBuilderPrivate builder; ++#else ++ FormBuilderPrivate builder; ++#endif ++ ++ void setupWidgetMap() const; ++}; ++ ++void QUiLoaderPrivate::setupWidgetMap() const ++{ ++ if (!g_widgets()->isEmpty()) ++ return; ++ ++#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true); ++#define DECLARE_LAYOUT(a, b) ++ ++#include "widgets.table" ++ ++#undef DECLARE_WIDGET ++#undef DECLARE_WIDGET_1 ++#undef DECLARE_LAYOUT ++} ++ ++/*! ++ \class QUiLoader ++ \inmodule QtUiTools ++ ++ \brief The QUiLoader class enables standalone applications to ++ dynamically create user interfaces at run-time using the ++ information stored in UI files or specified in plugin paths. ++ ++ In addition, you can customize or create your own user interface by ++ deriving your own loader class. ++ ++ If you have a custom component or an application that embeds \QD, you can ++ also use the QFormBuilder class provided by the QtDesigner module to create ++ user interfaces from UI files. ++ ++ The QUiLoader class provides a collection of functions allowing you to ++ create widgets based on the information stored in UI files (created ++ with \QD) or available in the specified plugin paths. The specified plugin ++ paths can be retrieved using the pluginPaths() function. Similarly, the ++ contents of a UI file can be retrieved using the load() function. For ++ example: ++ ++ \snippet quiloader/mywidget.cpp 0 ++ ++ \if !defined(qtforpython) ++ By including the user interface in the form's resources (\c myform.qrc), we ++ ensure that it will be present at run-time: ++ ++ \quotefile quiloader/mywidget.qrc ++ \endif ++ ++ The availableWidgets() function returns a QStringList with the class names ++ of the widgets available in the specified plugin paths. To create these ++ widgets, simply use the createWidget() function. For example: ++ ++ \snippet quiloader/main.cpp 0 ++ ++ To make a custom widget available to the loader, you can use the ++ addPluginPath() function; to remove all available widgets, you can call ++ the clearPluginPaths() function. ++ ++ The createAction(), createActionGroup(), createLayout(), and createWidget() ++ functions are used internally by the QUiLoader class whenever it has to ++ create an action, action group, layout, or widget respectively. For that ++ reason, you can subclass the QUiLoader class and reimplement these ++ functions to intervene the process of constructing a user interface. For ++ example, you might want to have a list of the actions created when loading ++ a form or creating a custom widget. ++ ++ For a complete example using the QUiLoader class, see the ++ \l{Calculator Builder Example}. ++ ++ \sa {Qt UI Tools}, QFormBuilder ++*/ ++ ++/*! ++ Creates a form loader with the given \a parent. ++*/ ++QUiLoader::QUiLoader(QObject *parent) ++ : QObject(parent), d_ptr(new QUiLoaderPrivate) ++{ ++ Q_D(QUiLoader); ++ ++#ifndef QT_NO_DATASTREAM ++ static int metaTypeId = 0; ++ if (!metaTypeId) { ++ metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); ++ } ++#endif // QT_NO_DATASTREAM ++ d->builder.loader = this; ++ ++#if QT_CONFIG(library) ++ QStringList paths; ++ const QStringList &libraryPaths = QApplication::libraryPaths(); ++ for (const QString &path : libraryPaths) { ++ QString libPath = path; ++ libPath += QDir::separator(); ++ libPath += QStringLiteral("designer"); ++ paths.append(libPath); ++ } ++ ++ d->builder.setPluginPath(paths); ++#endif // QT_CONFIG(library) ++} ++ ++/*! ++ Destroys the loader. ++*/ ++QUiLoader::~QUiLoader() = default; ++ ++/*! ++ Loads a form from the given \a device and creates a new widget with the ++ given \a parentWidget to hold its contents. ++ ++ \sa createWidget(), errorString() ++*/ ++QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) ++{ ++ Q_D(QUiLoader); ++ // QXmlStreamReader will report errors on open failure. ++ if (!device->isOpen()) ++ device->open(QIODevice::ReadOnly|QIODevice::Text); ++ return d->builder.load(device, parentWidget); ++} ++ ++/*! ++ Returns a list naming the paths in which the loader will search when ++ locating custom widget plugins. ++ ++ \sa addPluginPath(), clearPluginPaths() ++*/ ++QStringList QUiLoader::pluginPaths() const ++{ ++ Q_D(const QUiLoader); ++ return d->builder.pluginPaths(); ++} ++ ++/*! ++ Clears the list of paths in which the loader will search when locating ++ plugins. ++ ++ \sa addPluginPath(), pluginPaths() ++*/ ++void QUiLoader::clearPluginPaths() ++{ ++ Q_D(QUiLoader); ++ d->builder.clearPluginPaths(); ++} ++ ++/*! ++ Adds the given \a path to the list of paths in which the loader will search ++ when locating plugins. ++ ++ \sa pluginPaths(), clearPluginPaths() ++*/ ++void QUiLoader::addPluginPath(const QString &path) ++{ ++ Q_D(QUiLoader); ++ d->builder.addPluginPath(path); ++} ++ ++/*! ++ Creates a new widget with the given \a parent and \a name using the class ++ specified by \a className. You can use this function to create any of the ++ widgets returned by the availableWidgets() function. ++ ++ The function is also used internally by the QUiLoader class whenever it ++ creates a widget. Hence, you can subclass QUiLoader and reimplement this ++ function to intervene process of constructing a user interface or widget. ++ However, in your implementation, ensure that you call QUiLoader's version ++ first. ++ ++ \sa availableWidgets(), load() ++*/ ++QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) ++{ ++ Q_D(QUiLoader); ++ return d->builder.defaultCreateWidget(className, parent, name); ++} ++ ++/*! ++ Creates a new layout with the given \a parent and \a name using the class ++ specified by \a className. ++ ++ The function is also used internally by the QUiLoader class whenever it ++ creates a widget. Hence, you can subclass QUiLoader and reimplement this ++ function to intervene process of constructing a user interface or widget. ++ However, in your implementation, ensure that you call QUiLoader's version ++ first. ++ ++ \sa createWidget(), load() ++*/ ++QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) ++{ ++ Q_D(QUiLoader); ++ return d->builder.defaultCreateLayout(className, parent, name); ++} ++ ++/*! ++ Creates a new action group with the given \a parent and \a name. ++ ++ The function is also used internally by the QUiLoader class whenever it ++ creates a widget. Hence, you can subclass QUiLoader and reimplement this ++ function to intervene process of constructing a user interface or widget. ++ However, in your implementation, ensure that you call QUiLoader's version ++ first. ++ ++ \sa createAction(), createWidget(), load() ++ */ ++QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) ++{ ++ Q_D(QUiLoader); ++ return d->builder.defaultCreateActionGroup(parent, name); ++} ++ ++/*! ++ Creates a new action with the given \a parent and \a name. ++ ++ The function is also used internally by the QUiLoader class whenever it ++ creates a widget. Hence, you can subclass QUiLoader and reimplement this ++ function to intervene process of constructing a user interface or widget. ++ However, in your implementation, ensure that you call QUiLoader's version ++ first. ++ ++ \sa createActionGroup(), createWidget(), load() ++*/ ++QAction *QUiLoader::createAction(QObject *parent, const QString &name) ++{ ++ Q_D(QUiLoader); ++ return d->builder.defaultCreateAction(parent, name); ++} ++ ++/*! ++ Returns a list naming all available widgets that can be built using the ++ createWidget() function, i.e all the widgets specified within the given ++ plugin paths. ++ ++ \sa pluginPaths(), createWidget() ++ ++*/ ++QStringList QUiLoader::availableWidgets() const ++{ ++ Q_D(const QUiLoader); ++ ++ d->setupWidgetMap(); ++ widget_map available = *g_widgets(); ++ ++ const auto &customWidgets = d->builder.customWidgets(); ++ for (QDesignerCustomWidgetInterface *plugin : customWidgets) ++ available.insert(plugin->name(), true); ++ ++ return available.keys(); ++} ++ ++ ++/*! ++ \since 4.5 ++ Returns a list naming all available layouts that can be built using the ++ createLayout() function ++ ++ \sa createLayout() ++*/ ++ ++QStringList QUiLoader::availableLayouts() const ++{ ++ QStringList rc; ++#define DECLARE_WIDGET(a, b) ++#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a)); ++ ++#include "widgets.table" ++ ++#undef DECLARE_WIDGET ++#undef DECLARE_LAYOUT ++ return rc; ++} ++ ++/*! ++ Sets the working directory of the loader to \a dir. The loader will look ++ for other resources, such as icons and resource files, in paths relative to ++ this directory. ++ ++ \sa workingDirectory() ++*/ ++ ++void QUiLoader::setWorkingDirectory(const QDir &dir) ++{ ++ Q_D(QUiLoader); ++ d->builder.setWorkingDirectory(dir); ++} ++ ++/*! ++ Returns the working directory of the loader. ++ ++ \sa setWorkingDirectory() ++*/ ++ ++QDir QUiLoader::workingDirectory() const ++{ ++ Q_D(const QUiLoader); ++ return d->builder.workingDirectory(); ++} ++/*! ++ \since 4.5 ++ ++ If \a enabled is true, user interfaces loaded by this loader will ++ automatically retranslate themselves upon receiving a language change ++ event. Otherwise, the user interfaces will not be retranslated. ++ ++ \sa isLanguageChangeEnabled() ++*/ ++ ++void QUiLoader::setLanguageChangeEnabled(bool enabled) ++{ ++ Q_D(QUiLoader); ++ d->builder.dynamicTr = enabled; ++} ++ ++/*! ++ \since 4.5 ++ ++ Returns true if dynamic retranslation on language change is enabled; ++ returns false otherwise. ++ ++ \sa setLanguageChangeEnabled() ++*/ ++ ++bool QUiLoader::isLanguageChangeEnabled() const ++{ ++ Q_D(const QUiLoader); ++ return d->builder.dynamicTr; ++} ++ ++/*! ++ \internal ++ \since 4.5 ++ ++ If \a enabled is true, user interfaces loaded by this loader will be ++ translated. Otherwise, the user interfaces will not be translated. ++ ++ \note This is orthogonal to languageChangeEnabled. ++ ++ \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() ++*/ ++ ++void QUiLoader::setTranslationEnabled(bool enabled) ++{ ++ Q_D(QUiLoader); ++ d->builder.trEnabled = enabled; ++} ++ ++/*! ++ \internal ++ \since 4.5 ++ ++ Returns true if translation is enabled; returns false otherwise. ++ ++ \sa setTranslationEnabled() ++*/ ++ ++bool QUiLoader::isTranslationEnabled() const ++{ ++ Q_D(const QUiLoader); ++ return d->builder.trEnabled; ++} ++ ++/*! ++ Returns a human-readable description of the last error occurred in load(). ++ ++ \since 5.0 ++ \sa load() ++*/ ++ ++QString QUiLoader::errorString() const ++{ ++ Q_D(const QUiLoader); ++ return d->builder.errorString(); ++} ++ ++QT_END_NAMESPACE ++ ++#include "quiloader.moc" +diff --git x/qttools/src/designer/src/uitools/quiloader.h y/qttools/src/designer/src/uitools/quiloader.h +new file mode 100644 +index 000000000..742b5606f +--- /dev/null ++++ y/qttools/src/designer/src/uitools/quiloader.h +@@ -0,0 +1,61 @@ ++// Copyright (C) 2020 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++#ifndef QUILOADER_H ++#define QUILOADER_H ++ ++#include ++#include ++#include ++ ++QT_BEGIN_NAMESPACE ++ ++class QWidget; ++class QLayout; ++class QAction; ++class QActionGroup; ++class QString; ++class QIODevice; ++class QDir; ++ ++class QUiLoaderPrivate; ++class Q_UITOOLS_EXPORT QUiLoader : public QObject ++{ ++ Q_OBJECT ++public: ++ explicit QUiLoader(QObject *parent = nullptr); ++ ~QUiLoader() override; ++ ++ QStringList pluginPaths() const; ++ void clearPluginPaths(); ++ void addPluginPath(const QString &path); ++ ++ QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr); ++ QStringList availableWidgets() const; ++ QStringList availableLayouts() const; ++ ++ virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString()); ++ virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString()); ++ virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString()); ++ virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString()); ++ ++ void setWorkingDirectory(const QDir &dir); ++ QDir workingDirectory() const; ++ ++ void setLanguageChangeEnabled(bool enabled); ++ bool isLanguageChangeEnabled() const; ++ ++ void setTranslationEnabled(bool enabled); ++ bool isTranslationEnabled() const; ++ ++ QString errorString() const; ++ ++private: ++ QScopedPointer d_ptr; ++ Q_DECLARE_PRIVATE(QUiLoader) ++ Q_DISABLE_COPY_MOVE(QUiLoader) ++}; ++ ++QT_END_NAMESPACE ++ ++#endif // QUILOADER_H +diff --git x/qttools/src/designer/src/uitools/quiloader_p.h y/qttools/src/designer/src/uitools/quiloader_p.h +new file mode 100644 +index 000000000..efd943217 +--- /dev/null ++++ y/qttools/src/designer/src/uitools/quiloader_p.h +@@ -0,0 +1,77 @@ ++// Copyright (C) 2020 The Qt Company Ltd. ++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ++ ++#ifndef QUILOADER_P_H ++#define QUILOADER_P_H ++ ++// ++// W A R N I N G ++// ------------- ++// ++// This file is not part of the Qt API. It exists purely as an ++// implementation detail. This header file may change from version to ++// version without notice, or even be removed. ++// ++// We mean it. ++// ++ ++#include ++#include ++#include ++ ++QT_FORWARD_DECLARE_CLASS(QDataStream) ++ ++// This file is here for use by the form preview in Linguist. If you change anything ++// here or in the code which uses it, remember to adapt Linguist accordingly. ++ ++#define PROP_GENERIC_PREFIX "_q_notr_" ++#define PROP_TOOLITEMTEXT "_q_toolItemText_notr" ++#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr" ++#define PROP_TABPAGETEXT "_q_tabPageText_notr" ++#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr" ++#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr" ++ ++QT_BEGIN_NAMESPACE ++ ++class Q_UITOOLS_EXPORT QUiTranslatableStringValue ++{ ++public: ++ QByteArray value() const { return m_value; } ++ void setValue(const QByteArray &value) { m_value = value; } ++ QByteArray qualifier() const { return m_qualifier; } ++ void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; } ++ ++ QString translate(const QByteArray &className, bool idBased) const; ++ ++private: ++ QByteArray m_value; ++ QByteArray m_qualifier; // Comment or ID for id-based tr(). ++}; ++ ++#ifndef QT_NO_DATASTREAM ++Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); ++Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); ++#endif // QT_NO_DATASTREAM ++ ++struct QUiItemRolePair { ++ int realRole; ++ int shadowRole; ++}; ++ ++#ifdef QFORMINTERNAL_NAMESPACE ++namespace QFormInternal ++{ ++#endif ++ ++extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; ++ ++#ifdef QFORMINTERNAL_NAMESPACE ++} ++#endif ++ ++QT_END_NAMESPACE ++ ++Q_DECLARE_METATYPE(QUiTranslatableStringValue) ++ ++ ++#endif // QUILOADER_P_H +diff --git x/qttools/src/uiplugin/CMakeLists.txt y/qttools/src/uiplugin/CMakeLists.txt +deleted file mode 100644 +index 4fedf8e33..000000000 +--- x/qttools/src/uiplugin/CMakeLists.txt ++++ /dev/null +@@ -1,27 +0,0 @@ +-# Generated from uiplugin.pro. +- +-##################################################################### +-## UiPlugin Module: +-##################################################################### +- +-qt_internal_add_module(UiPlugin +- NO_PRIVATE_MODULE +- HEADER_MODULE +- QMAKE_MODULE_CONFIG designer_defines +- PUBLIC_LIBRARIES +- Qt::Core +- Qt::Gui +- Qt::Widgets +-) +- +-# special case begin +-set(is_plugin "$") +-target_compile_definitions( +- UiPlugin +- INTERFACE +- $<$:QDESIGNER_EXPORT_WIDGETS> +-) +-# special case end +- +-#### Keys ignored in scope 1:.:.:uiplugin.pro:: +-# MODULE_CONFIG = "designer_defines" +diff --git x/qttools/src/uiplugin/customwidget.h y/qttools/src/uiplugin/customwidget.h +deleted file mode 100644 +index 2a47a32f8..000000000 +--- x/qttools/src/uiplugin/customwidget.h ++++ /dev/null +@@ -1,62 +0,0 @@ +-// Copyright (C) 2016 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +- +-#ifndef CUSTOMWIDGET_H +-#define CUSTOMWIDGET_H +- +-#include +-#include +-#include +- +-QT_BEGIN_NAMESPACE +- +-class QWidget; +-class QDesignerFormEditorInterface; +- +-class QDesignerCustomWidgetInterface +-{ +-public: +- virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable +- +- virtual QString name() const = 0; +- virtual QString group() const = 0; +- virtual QString toolTip() const = 0; +- virtual QString whatsThis() const = 0; +- virtual QString includeFile() const = 0; +- virtual QIcon icon() const = 0; +- +- virtual bool isContainer() const = 0; +- +- virtual QWidget *createWidget(QWidget *parent) = 0; +- +- virtual bool isInitialized() const { return false; } +- virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); } +- +- virtual QString domXml() const +- { +- return QString::fromUtf8("") +- .arg(name()).arg(name().toLower()); +- } +- +- virtual QString codeTemplate() const { return QString(); } +-}; +- +-#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface" +- +-Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid) +- +-class QDesignerCustomWidgetCollectionInterface +-{ +-public: +- virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable +- +- virtual QList customWidgets() const = 0; +-}; +- +-#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface" +- +-Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid) +- +-QT_END_NAMESPACE +- +-#endif // CUSTOMWIDGET_H +diff --git x/qttools/src/uiplugin/customwidget.qdoc y/qttools/src/uiplugin/customwidget.qdoc +deleted file mode 100644 +index 557e9a454..000000000 +--- x/qttools/src/uiplugin/customwidget.qdoc ++++ /dev/null +@@ -1,269 +0,0 @@ +-// Copyright (C) 2016 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only +- +-/*! +- \class QDesignerCustomWidgetInterface +- +- \brief The QDesignerCustomWidgetInterface class enables Qt Designer +- to access and construct custom widgets. +- +- \inmodule QtDesigner +- +- QDesignerCustomWidgetInterface provides a custom widget with an +- interface. The class contains a set of functions that must be subclassed +- to return basic information about the widget, such as its class name and +- the name of its header file. Other functions must be implemented to +- initialize the plugin when it is loaded, and to construct instances of +- the custom widget for \QD to use. +- +- When implementing a custom widget you must subclass +- QDesignerCustomWidgetInterface to expose your widget to \QD. For +- example, this is the declaration for the plugin used in the +- \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that +- enables an analog clock custom widget to be used by \QD: +- +- \snippet customwidgetplugin/customwidgetplugin.h 0 +- +- Note that the only part of the class definition that is specific +- to this particular custom widget is the class name. In addition, +- since we are implementing an interface, we must ensure that it's +- made known to the meta object system using the Q_INTERFACES() +- macro. This enables \QD to use the qobject_cast() function to +- query for supported interfaces using nothing but a QObject +- pointer. +- +- After \QD loads a custom widget plugin, it calls the interface's +- initialize() function to enable it to set up any resources that it +- may need. This function is called with a QDesignerFormEditorInterface +- parameter that provides the plugin with a gateway to all of \QD's API. +- +- \QD constructs instances of the custom widget by calling the plugin's +- createWidget() function with a suitable parent widget. Plugins must +- construct and return an instance of a custom widget with the specified +- parent widget. +- +- Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA() +- macro. For example, if a library called \c libcustomwidgetplugin.so +- (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget +- class called \c MyCustomWidget, we can export it by adding the +- following line to the file containing the plugin header: +- +- \snippet plugins/doc_src_qtdesigner.cpp 14 +- +- This macro ensures that \QD can access and construct the custom widget. +- Without this macro, there is no way for \QD to use it. +- +- When implementing a custom widget plugin, you build it as a +- separate library. If you want to include several custom widget +- plugins in the same library, you must in addition subclass +- QDesignerCustomWidgetCollectionInterface. +- +- \warning If your custom widget plugin contains QVariant +- properties, be aware that only the following \l +- {QVariant::Type}{types} are supported: +- +- \list +- \li QVariant::ByteArray +- \li QVariant::Bool +- \li QVariant::Color +- \li QVariant::Cursor +- \li QVariant::Date +- \li QVariant::DateTime +- \li QVariant::Double +- \li QVariant::Int +- \li QVariant::Point +- \li QVariant::Rect +- \li QVariant::Size +- \li QVariant::SizePolicy +- \li QVariant::String +- \li QVariant::Time +- \li QVariant::UInt +- \endlist +- +- For a complete example using the QDesignerCustomWidgetInterface +- class, see the \l {customwidgetplugin}{Custom Widget +- Example}. The example shows how to create a custom widget plugin +- for \QD. +- +- \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer} +-*/ +- +-/*! +- \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface() +- +- Destroys the custom widget interface. +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::name() const +- +- Returns the class name of the custom widget supplied by the interface. +- +- The name returned \e must be identical to the class name used for the +- custom widget. +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::group() const +- +- Returns the name of the group to which the custom widget belongs. +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::toolTip() const +- +- Returns a short description of the widget that can be used by \QD +- in a tool tip. +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::whatsThis() const +- +- Returns a description of the widget that can be used by \QD in +- "What's This?" help for the widget. +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::includeFile() const +- +- Returns the path to the include file that \l uic uses when +- creating code for the custom widget. +-*/ +- +-/*! +- \fn QIcon QDesignerCustomWidgetInterface::icon() const +- +- Returns the icon used to represent the custom widget in \QD's +- widget box. +-*/ +- +-/*! +- \fn bool QDesignerCustomWidgetInterface::isContainer() const +- +- Returns true if the custom widget is intended to be used as a +- container; otherwise returns false. +- +- Most custom widgets are not used to hold other widgets, so their +- implementations of this function will return false, but custom +- containers will return true to ensure that they behave correctly +- in \QD. +-*/ +- +-/*! +- \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent) +- +- Returns a new instance of the custom widget, with the given \a +- parent. +-*/ +- +-/*! +- \fn bool QDesignerCustomWidgetInterface::isInitialized() const +- +- Returns true if the widget has been initialized; otherwise returns +- false. +- +- \sa initialize() +-*/ +- +-/*! +- \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) +- +- Initializes the widget for use with the specified \a formEditor +- interface. +- +- \sa isInitialized() +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::domXml() const +- +- Returns the XML that is used to describe the custom widget's +- properties to \QD. +-*/ +- +-/*! +- \fn QString QDesignerCustomWidgetInterface::codeTemplate() const +- +- This function is reserved for future use by \QD. +- +- \omit +- Returns the code template that \QD includes in forms that contain +- the custom widget when they are saved. +- \endomit +-*/ +- +-/*! +- \macro QDESIGNER_WIDGET_EXPORT +- \relates QDesignerCustomWidgetInterface +- \since 4.1 +- +- This macro is used when defining custom widgets to ensure that they are +- correctly exported from plugins for use with \QD. +- +- On some platforms, the symbols required by \QD to create new widgets +- are removed from plugins by the build system, making them unusable. +- Using this macro ensures that the symbols are retained on those platforms, +- and has no side effects on other platforms. +- +- For example, the \l{worldtimeclockplugin}{World Time Clock Plugin} +- example exports a custom widget class with the following declaration: +- +- \snippet worldtimeclockplugin/worldtimeclock.h 0 +- \dots +- \snippet worldtimeclockplugin/worldtimeclock.h 2 +- +- \sa {Creating Custom Widgets for Qt Designer} +-*/ +- +- +- +- +- +-/*! +- \class QDesignerCustomWidgetCollectionInterface +- +- \brief The QDesignerCustomWidgetCollectionInterface class allows +- you to include several custom widgets in one single library. +- +- \inmodule QtDesigner +- +- When implementing a custom widget plugin, you build it as a +- separate library. If you want to include several custom widget +- plugins in the same library, you must in addition subclass +- QDesignerCustomWidgetCollectionInterface. +- +- QDesignerCustomWidgetCollectionInterface contains one single +- function returning a list of the collection's +- QDesignerCustomWidgetInterface objects. For example, if you have +- several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and +- \c CustomWidgetThree, the class definition may look like this: +- +- \snippet plugins/doc_src_qtdesigner.cpp 12 +- +- In the class constructor you add the interfaces to your custom +- widgets to the list which you return in the customWidgets() +- function: +- +- \snippet plugins/doc_src_qtdesigner.cpp 13 +- +- Note that instead of exporting each custom widget plugin using the +- Q_PLUGIN_METADATA() macro, you export the entire collection. The +- Q_PLUGIN_METADATA() macro ensures that \QD can access and construct +- the custom widgets. Without this macro, there is no way for \QD to +- use them. +- +- \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for +- Qt Designer} +-*/ +- +-/*! +- \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() { +- +- Destroys the custom widget collection interface. +-*/ +- +-/*! +- \fn QList QDesignerCustomWidgetCollectionInterface::customWidgets() const +- +- Returns a list of interfaces to the collection's custom widgets. +-*/ +diff --git x/qttools/src/uiplugin/qdesignerexportwidget.h y/qttools/src/uiplugin/qdesignerexportwidget.h +deleted file mode 100644 +index d90e9b217..000000000 +--- x/qttools/src/uiplugin/qdesignerexportwidget.h ++++ /dev/null +@@ -1,24 +0,0 @@ +-// Copyright (C) 2016 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +- +-#ifndef QDESIGNEREXPORTWIDGET_H +-#define QDESIGNEREXPORTWIDGET_H +- +-#include +- +-QT_BEGIN_NAMESPACE +- +-#if 0 +-// pragma for syncqt, don't remove. +-#pragma qt_class(QDesignerExportWidget) +-#endif +- +-#if defined(QDESIGNER_EXPORT_WIDGETS) +-# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT +-#else +-# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT +-#endif +- +-QT_END_NAMESPACE +- +-#endif //QDESIGNEREXPORTWIDGET_H +diff --git x/qttools/src/uitools/CMakeLists.txt y/qttools/src/uitools/CMakeLists.txt +deleted file mode 100644 +index 448bd1840..000000000 +--- x/qttools/src/uitools/CMakeLists.txt ++++ /dev/null +@@ -1,47 +0,0 @@ +-# Generated from uitools.pro. +- +-##################################################################### +-## UiTools Module: +-##################################################################### +- +-qt_internal_add_module(UiTools +- SOURCES +- ../designer/src/lib/uilib/abstractformbuilder.cpp ../designer/src/lib/uilib/abstractformbuilder.h +- ../designer/src/lib/uilib/formbuilder.cpp ../designer/src/lib/uilib/formbuilder.h +- ../designer/src/lib/uilib/formbuilderextra.cpp ../designer/src/lib/uilib/formbuilderextra_p.h +- ../designer/src/lib/uilib/properties.cpp ../designer/src/lib/uilib/properties_p.h +- ../designer/src/lib/uilib/resourcebuilder.cpp ../designer/src/lib/uilib/resourcebuilder_p.h +- ../designer/src/lib/uilib/textbuilder.cpp ../designer/src/lib/uilib/textbuilder_p.h +- ../designer/src/lib/uilib/ui4.cpp ../designer/src/lib/uilib/ui4_p.h +- quiloader.cpp quiloader.h +- DEFINES +- QFORMINTERNAL_NAMESPACE +- QT_DESIGNER +- QT_DESIGNER_STATIC +- QT_USE_QSTRINGBUILDER +- INCLUDE_DIRECTORIES +- ../designer/src/lib/uilib +- LIBRARIES +- Qt::UiPlugin +- PUBLIC_LIBRARIES +- Qt::Core +- Qt::Gui +- Qt::Widgets +-) +- +-## Scopes: +-##################################################################### +- +-qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets +- PUBLIC_LIBRARIES +- Qt::OpenGLWidgets +-) +- +-qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGL +- LIBRARIES +- Qt::OpenGL +-) +-qt_internal_add_docs(UiTools +- doc/qtuitools.qdocconf +-) +- +diff --git x/qttools/src/uitools/qtuitoolsglobal.h y/qttools/src/uitools/qtuitoolsglobal.h +deleted file mode 100644 +index a2f967dee..000000000 +--- x/qttools/src/uitools/qtuitoolsglobal.h ++++ /dev/null +@@ -1,24 +0,0 @@ +-// Copyright (C) 2020 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +- +-#ifndef QTUITOOLSGLOBAL_H +-#define QTUITOOLSGLOBAL_H +- +-#include +- +-QT_BEGIN_NAMESPACE +- +-#ifndef QT_STATIC +-# if defined(QT_BUILD_UITOOLS_LIB) +-# define Q_UITOOLS_EXPORT Q_DECL_EXPORT +-# else +-# define Q_UITOOLS_EXPORT Q_DECL_IMPORT +-# endif +-#else +-# define Q_UITOOLS_EXPORT +-#endif +- +-QT_END_NAMESPACE +- +-#endif // QTUITOOLSGLOBAL_H +- +diff --git x/qttools/src/uitools/quiloader.cpp y/qttools/src/uitools/quiloader.cpp +deleted file mode 100644 +index a06d4717b..000000000 +--- x/qttools/src/uitools/quiloader.cpp ++++ /dev/null +@@ -1,914 +0,0 @@ +-// Copyright (C) 2020 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +- +- +-#include "quiloader.h" +-#include "quiloader_p.h" +- +-#include +- +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +- +-QT_BEGIN_NAMESPACE +- +-typedef QMap widget_map; +-Q_GLOBAL_STATIC(widget_map, g_widgets) +- +-class QUiLoader; +-class QUiLoaderPrivate; +- +-#ifndef QT_NO_DATASTREAM +-// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based +-// mime data when dragging items in views with QAbstractItemView::InternalMove. +-QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) +-{ +- out << s.qualifier() << s.value(); +- return out; +-} +- +-QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) +-{ +- QByteArray qualifier, value; +- in >> qualifier >> value; +- s.setQualifier(qualifier); +- s.setValue(value); +- return in; +-} +-#endif // QT_NO_DATASTREAM +- +-QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const +-{ +- return idBased +- ? qtTrId(m_qualifier.constData()) +- : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData()); +-} +- +-#ifdef QFORMINTERNAL_NAMESPACE +-namespace QFormInternal +-{ +-#endif +- +-class TranslatingTextBuilder : public QTextBuilder +-{ +-public: +- explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) : +- m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {} +- +- QVariant loadText(const DomProperty *icon) const override; +- +- QVariant toNativeValue(const QVariant &value) const override; +- +- bool idBased() const { return m_idBased; } +- +-private: +- bool m_idBased; +- bool m_trEnabled; +- QByteArray m_className; +-}; +- +-QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const +-{ +- const DomString *str = text->elementString(); +- if (!str) +- return QVariant(); +- if (str->hasAttributeNotr()) { +- const QString notr = str->attributeNotr(); +- if (notr == QStringLiteral("true") || notr == QStringLiteral("yes")) +- return QVariant::fromValue(str->text()); +- } +- QUiTranslatableStringValue strVal; +- strVal.setValue(str->text().toUtf8()); +- if (m_idBased) +- strVal.setQualifier(str->attributeId().toUtf8()); +- else if (str->hasAttributeComment()) +- strVal.setQualifier(str->attributeComment().toUtf8()); +- return QVariant::fromValue(strVal); +-} +- +-QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const +-{ +- if (value.canConvert()) { +- QUiTranslatableStringValue tsv = qvariant_cast(value); +- if (!m_trEnabled) +- return QString::fromUtf8(tsv.value().constData()); +- return QVariant::fromValue(tsv.translate(m_className, m_idBased)); +- } +- if (value.canConvert()) +- return QVariant::fromValue(qvariant_cast(value)); +- return value; +-} +- +-// This is "exported" to linguist +-const QUiItemRolePair qUiItemRoles[] = { +- { Qt::DisplayRole, Qt::DisplayPropertyRole }, +-#if QT_CONFIG(tooltip) +- { Qt::ToolTipRole, Qt::ToolTipPropertyRole }, +-#endif +-#if QT_CONFIG(statustip) +- { Qt::StatusTipRole, Qt::StatusTipPropertyRole }, +-#endif +-#if QT_CONFIG(whatsthis) +- { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole }, +-#endif +- { -1 , -1 } +-}; +- +-static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased) +-{ +- const QUiItemRolePair *irs = qUiItemRoles; +- +- int cnt = item->columnCount(); +- for (int i = 0; i < cnt; ++i) { +- for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { +- QVariant v = item->data(i, irs[j].shadowRole); +- if (v.isValid()) { +- QUiTranslatableStringValue tsv = qvariant_cast(v); +- item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased)); +- } +- } +- } +- +- cnt = item->childCount(); +- for (int i = 0; i < cnt; ++i) +- recursiveReTranslate(item->child(i), class_name, idBased); +-} +- +-template +-static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased) +-{ +- const QUiItemRolePair *irs = qUiItemRoles; +- +- for (unsigned j = 0; irs[j].shadowRole >= 0; j++) { +- QVariant v = item->data(irs[j].shadowRole); +- if (v.isValid()) { +- QUiTranslatableStringValue tsv = qvariant_cast(v); +- item->setData(irs[j].realRole, tsv.translate(class_name, idBased)); +- } +- } +-} +- +-static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased) +-{ +- if (item) +- reTranslateWidgetItem(item, class_name, idBased); +-} +- +-#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \ +- do { \ +- QVariant v = mainWidget->widget(i)->property(propName); \ +- if (v.isValid()) { \ +- QUiTranslatableStringValue tsv = qvariant_cast(v); \ +- mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \ +- } \ +- } while (0) +- +-class TranslationWatcher: public QObject +-{ +- Q_OBJECT +- +-public: +- explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased): +- QObject(parent), +- m_className(className), +- m_idBased(idBased) +- { +- } +- +- bool eventFilter(QObject *o, QEvent *event) override +- { +- if (event->type() == QEvent::LanguageChange) { +- const auto &dynamicPropertyNames = o->dynamicPropertyNames(); +- for (const QByteArray &prop : dynamicPropertyNames) { +- if (prop.startsWith(PROP_GENERIC_PREFIX)) { +- const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); +- const QUiTranslatableStringValue tsv = +- qvariant_cast(o->property(prop)); +- o->setProperty(propName, tsv.translate(m_className, m_idBased)); +- } +- } +- if (0) { +-#if QT_CONFIG(tabwidget) +- } else if (QTabWidget *tabw = qobject_cast(o)) { +- const int cnt = tabw->count(); +- for (int i = 0; i < cnt; ++i) { +- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT); +-#if QT_CONFIG(tooltip) +- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP); +-# endif +-#if QT_CONFIG(whatsthis) +- RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); +-# endif +- } +-#endif +-#if QT_CONFIG(listwidget) +- } else if (QListWidget *listw = qobject_cast(o)) { +- const int cnt = listw->count(); +- for (int i = 0; i < cnt; ++i) +- reTranslateWidgetItem(listw->item(i), m_className, m_idBased); +-#endif +-#if QT_CONFIG(treewidget) +- } else if (QTreeWidget *treew = qobject_cast(o)) { +- if (QTreeWidgetItem *item = treew->headerItem()) +- recursiveReTranslate(item, m_className, m_idBased); +- const int cnt = treew->topLevelItemCount(); +- for (int i = 0; i < cnt; ++i) { +- QTreeWidgetItem *item = treew->topLevelItem(i); +- recursiveReTranslate(item, m_className, m_idBased); +- } +-#endif +-#if QT_CONFIG(tablewidget) +- } else if (QTableWidget *tablew = qobject_cast(o)) { +- const int row_cnt = tablew->rowCount(); +- const int col_cnt = tablew->columnCount(); +- for (int j = 0; j < col_cnt; ++j) +- reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased); +- for (int i = 0; i < row_cnt; ++i) { +- reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased); +- for (int j = 0; j < col_cnt; ++j) +- reTranslateTableItem(tablew->item(i, j), m_className, m_idBased); +- } +-#endif +-#if QT_CONFIG(combobox) +- } else if (QComboBox *combow = qobject_cast(o)) { +- if (!qobject_cast(o)) { +- const int cnt = combow->count(); +- for (int i = 0; i < cnt; ++i) { +- const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole); +- if (v.isValid()) { +- QUiTranslatableStringValue tsv = qvariant_cast(v); +- combow->setItemText(i, tsv.translate(m_className, m_idBased)); +- } +- } +- } +-#endif +-#if QT_CONFIG(toolbox) +- } else if (QToolBox *toolw = qobject_cast(o)) { +- const int cnt = toolw->count(); +- for (int i = 0; i < cnt; ++i) { +- RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT); +-#if QT_CONFIG(tooltip) +- RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP); +-# endif +- } +-#endif +- } +- } +- return false; +- } +- +-private: +- QByteArray m_className; +- bool m_idBased; +-}; +- +-class FormBuilderPrivate: public QFormBuilder +-{ +- friend class QT_PREPEND_NAMESPACE(QUiLoader); +- friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate); +- using ParentClass = QFormBuilder; +- +-public: +- QUiLoader *loader = nullptr; +- +- bool dynamicTr = false; +- bool trEnabled = true; +- +- FormBuilderPrivate() = default; +- +- QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name) +- { +- return ParentClass::createWidget(className, parent, name); +- } +- +- QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name) +- { +- return ParentClass::createLayout(className, parent, name); +- } +- +- QAction *defaultCreateAction(QObject *parent, const QString &name) +- { +- return ParentClass::createAction(parent, name); +- } +- +- QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name) +- { +- return ParentClass::createActionGroup(parent, name); +- } +- +- QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override +- { +- if (QWidget *widget = loader->createWidget(className, parent, name)) { +- widget->setObjectName(name); +- return widget; +- } +- +- return nullptr; +- } +- +- QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override +- { +- if (QLayout *layout = loader->createLayout(className, parent, name)) { +- layout->setObjectName(name); +- return layout; +- } +- +- return nullptr; +- } +- +- QActionGroup *createActionGroup(QObject *parent, const QString &name) override +- { +- if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) { +- actionGroup->setObjectName(name); +- return actionGroup; +- } +- +- return nullptr; +- } +- +- QAction *createAction(QObject *parent, const QString &name) override +- { +- if (QAction *action = loader->createAction(parent, name)) { +- action->setObjectName(name); +- return action; +- } +- +- return nullptr; +- } +- +- void applyProperties(QObject *o, const QList &properties) override; +- QWidget *create(DomUI *ui, QWidget *parentWidget) override; +- QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override; +- bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override; +- +-private: +- QByteArray m_class; +- TranslationWatcher *m_trwatch = nullptr; +- bool m_idBased = false; +-}; +- +-static QString convertTranslatable(const DomProperty *p, const QByteArray &className, +- bool idBased, QUiTranslatableStringValue *strVal) +-{ +- if (p->kind() != DomProperty::String) +- return QString(); +- const DomString *dom_str = p->elementString(); +- if (!dom_str) +- return QString(); +- if (dom_str->hasAttributeNotr()) { +- const QString notr = dom_str->attributeNotr(); +- if (notr == QStringLiteral("yes") || notr == QStringLiteral("true")) +- return QString(); +- } +- strVal->setValue(dom_str->text().toUtf8()); +- strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8()); +- if (strVal->value().isEmpty() && strVal->qualifier().isEmpty()) +- return QString(); +- return strVal->translate(className, idBased); +-} +- +-void FormBuilderPrivate::applyProperties(QObject *o, const QList &properties) +-{ +- QFormBuilder::applyProperties(o, properties); +- +- if (!m_trwatch) +- m_trwatch = new TranslationWatcher(o, m_class, m_idBased); +- +- if (properties.isEmpty()) +- return; +- +- // Unlike string item roles, string properties are not loaded via the textBuilder +- // (as they are "shadowed" by the property sheets in designer). So do the initial +- // translation here. +- bool anyTrs = false; +- for (const DomProperty *p : properties) { +- QUiTranslatableStringValue strVal; +- const QString text = convertTranslatable(p, m_class, m_idBased, &strVal); +- if (text.isEmpty()) +- continue; +- const QByteArray name = p->attributeName().toUtf8(); +- if (dynamicTr) { +- const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name); +- o->setProperty(dynname, QVariant::fromValue(strVal)); +- anyTrs = trEnabled; +- } +- if (p->elementString()->text() != text) +- o->setProperty(name, text); +- } +- if (anyTrs) +- o->installEventFilter(m_trwatch); +-} +- +-QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget) +-{ +- m_class = ui->elementClass().toUtf8(); +- m_trwatch = nullptr; +- m_idBased = ui->attributeIdbasedtr(); +- setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class)); +- return QFormBuilder::create(ui, parentWidget); +-} +- +-QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget) +-{ +- QWidget *w = QFormBuilder::create(ui_widget, parentWidget); +- if (w == nullptr) +- return nullptr; +- +- if (0) { +-#if QT_CONFIG(tabwidget) +- } else if (qobject_cast(w)) { +-#endif +-#if QT_CONFIG(listwidget) +- } else if (qobject_cast(w)) { +-#endif +-#if QT_CONFIG(treewidget) +- } else if (qobject_cast(w)) { +-#endif +-#if QT_CONFIG(tablewidget) +- } else if (qobject_cast(w)) { +-#endif +-#if QT_CONFIG(combobox) +- } else if (qobject_cast(w)) { +- if (qobject_cast(w)) +- return w; +-#endif +-#if QT_CONFIG(toolbox) +- } else if (qobject_cast(w)) { +-#endif +- } else { +- return w; +- } +- if (dynamicTr && trEnabled) +- w->installEventFilter(m_trwatch); +- return w; +-} +- +-#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \ +- do { \ +- if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \ +- QUiTranslatableStringValue strVal; \ +- const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \ +- if (!text.isEmpty()) { \ +- if (dynamicTr) \ +- mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \ +- mainWidget->setter(i, text); \ +- } \ +- } \ +- } while (0) +- +-bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +-{ +- if (parentWidget == nullptr) +- return true; +- +- if (!ParentClass::addItem(ui_widget, widget, parentWidget)) +- return false; +- +- // Check special cases. First: Custom container +- const QString className = QLatin1String(parentWidget->metaObject()->className()); +- if (!d->customWidgetAddPageMethod(className).isEmpty()) +- return true; +- +- const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); +- +- if (0) { +-#if QT_CONFIG(tabwidget) +- } else if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { +- const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); +- const int i = tabWidget->count() - 1; +- TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT); +-#if QT_CONFIG(tooltip) +- TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP); +-# endif +-#if QT_CONFIG(whatsthis) +- TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS); +-# endif +-#endif +-#if QT_CONFIG(toolbox) +- } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { +- const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); +- const int i = toolBox->count() - 1; +- TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT); +-#if QT_CONFIG(tooltip) +- TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP); +-# endif +-#endif +- } +- +- return true; +-} +- +-#ifdef QFORMINTERNAL_NAMESPACE +-} +-#endif +- +-class QUiLoaderPrivate +-{ +-public: +-#ifdef QFORMINTERNAL_NAMESPACE +- QFormInternal::FormBuilderPrivate builder; +-#else +- FormBuilderPrivate builder; +-#endif +- +- void setupWidgetMap() const; +-}; +- +-void QUiLoaderPrivate::setupWidgetMap() const +-{ +- if (!g_widgets()->isEmpty()) +- return; +- +-#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true); +-#define DECLARE_LAYOUT(a, b) +- +-#include "widgets.table" +- +-#undef DECLARE_WIDGET +-#undef DECLARE_WIDGET_1 +-#undef DECLARE_LAYOUT +-} +- +-/*! +- \class QUiLoader +- \inmodule QtUiTools +- +- \brief The QUiLoader class enables standalone applications to +- dynamically create user interfaces at run-time using the +- information stored in UI files or specified in plugin paths. +- +- In addition, you can customize or create your own user interface by +- deriving your own loader class. +- +- If you have a custom component or an application that embeds \QD, you can +- also use the QFormBuilder class provided by the QtDesigner module to create +- user interfaces from UI files. +- +- The QUiLoader class provides a collection of functions allowing you to +- create widgets based on the information stored in UI files (created +- with \QD) or available in the specified plugin paths. The specified plugin +- paths can be retrieved using the pluginPaths() function. Similarly, the +- contents of a UI file can be retrieved using the load() function. For +- example: +- +- \snippet quiloader/mywidget.cpp 0 +- +- \if !defined(qtforpython) +- By including the user interface in the form's resources (\c myform.qrc), we +- ensure that it will be present at run-time: +- +- \quotefile quiloader/mywidget.qrc +- \endif +- +- The availableWidgets() function returns a QStringList with the class names +- of the widgets available in the specified plugin paths. To create these +- widgets, simply use the createWidget() function. For example: +- +- \snippet quiloader/main.cpp 0 +- +- To make a custom widget available to the loader, you can use the +- addPluginPath() function; to remove all available widgets, you can call +- the clearPluginPaths() function. +- +- The createAction(), createActionGroup(), createLayout(), and createWidget() +- functions are used internally by the QUiLoader class whenever it has to +- create an action, action group, layout, or widget respectively. For that +- reason, you can subclass the QUiLoader class and reimplement these +- functions to intervene the process of constructing a user interface. For +- example, you might want to have a list of the actions created when loading +- a form or creating a custom widget. +- +- For a complete example using the QUiLoader class, see the +- \l{Calculator Builder Example}. +- +- \sa {Qt UI Tools}, QFormBuilder +-*/ +- +-/*! +- Creates a form loader with the given \a parent. +-*/ +-QUiLoader::QUiLoader(QObject *parent) +- : QObject(parent), d_ptr(new QUiLoaderPrivate) +-{ +- Q_D(QUiLoader); +- +-#ifndef QT_NO_DATASTREAM +- static int metaTypeId = 0; +- if (!metaTypeId) { +- metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); +- } +-#endif // QT_NO_DATASTREAM +- d->builder.loader = this; +- +-#if QT_CONFIG(library) +- QStringList paths; +- const QStringList &libraryPaths = QApplication::libraryPaths(); +- for (const QString &path : libraryPaths) { +- QString libPath = path; +- libPath += QDir::separator(); +- libPath += QStringLiteral("designer"); +- paths.append(libPath); +- } +- +- d->builder.setPluginPath(paths); +-#endif // QT_CONFIG(library) +-} +- +-/*! +- Destroys the loader. +-*/ +-QUiLoader::~QUiLoader() = default; +- +-/*! +- Loads a form from the given \a device and creates a new widget with the +- given \a parentWidget to hold its contents. +- +- \sa createWidget(), errorString() +-*/ +-QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget) +-{ +- Q_D(QUiLoader); +- // QXmlStreamReader will report errors on open failure. +- if (!device->isOpen()) +- device->open(QIODevice::ReadOnly|QIODevice::Text); +- return d->builder.load(device, parentWidget); +-} +- +-/*! +- Returns a list naming the paths in which the loader will search when +- locating custom widget plugins. +- +- \sa addPluginPath(), clearPluginPaths() +-*/ +-QStringList QUiLoader::pluginPaths() const +-{ +- Q_D(const QUiLoader); +- return d->builder.pluginPaths(); +-} +- +-/*! +- Clears the list of paths in which the loader will search when locating +- plugins. +- +- \sa addPluginPath(), pluginPaths() +-*/ +-void QUiLoader::clearPluginPaths() +-{ +- Q_D(QUiLoader); +- d->builder.clearPluginPaths(); +-} +- +-/*! +- Adds the given \a path to the list of paths in which the loader will search +- when locating plugins. +- +- \sa pluginPaths(), clearPluginPaths() +-*/ +-void QUiLoader::addPluginPath(const QString &path) +-{ +- Q_D(QUiLoader); +- d->builder.addPluginPath(path); +-} +- +-/*! +- Creates a new widget with the given \a parent and \a name using the class +- specified by \a className. You can use this function to create any of the +- widgets returned by the availableWidgets() function. +- +- The function is also used internally by the QUiLoader class whenever it +- creates a widget. Hence, you can subclass QUiLoader and reimplement this +- function to intervene process of constructing a user interface or widget. +- However, in your implementation, ensure that you call QUiLoader's version +- first. +- +- \sa availableWidgets(), load() +-*/ +-QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name) +-{ +- Q_D(QUiLoader); +- return d->builder.defaultCreateWidget(className, parent, name); +-} +- +-/*! +- Creates a new layout with the given \a parent and \a name using the class +- specified by \a className. +- +- The function is also used internally by the QUiLoader class whenever it +- creates a widget. Hence, you can subclass QUiLoader and reimplement this +- function to intervene process of constructing a user interface or widget. +- However, in your implementation, ensure that you call QUiLoader's version +- first. +- +- \sa createWidget(), load() +-*/ +-QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name) +-{ +- Q_D(QUiLoader); +- return d->builder.defaultCreateLayout(className, parent, name); +-} +- +-/*! +- Creates a new action group with the given \a parent and \a name. +- +- The function is also used internally by the QUiLoader class whenever it +- creates a widget. Hence, you can subclass QUiLoader and reimplement this +- function to intervene process of constructing a user interface or widget. +- However, in your implementation, ensure that you call QUiLoader's version +- first. +- +- \sa createAction(), createWidget(), load() +- */ +-QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name) +-{ +- Q_D(QUiLoader); +- return d->builder.defaultCreateActionGroup(parent, name); +-} +- +-/*! +- Creates a new action with the given \a parent and \a name. +- +- The function is also used internally by the QUiLoader class whenever it +- creates a widget. Hence, you can subclass QUiLoader and reimplement this +- function to intervene process of constructing a user interface or widget. +- However, in your implementation, ensure that you call QUiLoader's version +- first. +- +- \sa createActionGroup(), createWidget(), load() +-*/ +-QAction *QUiLoader::createAction(QObject *parent, const QString &name) +-{ +- Q_D(QUiLoader); +- return d->builder.defaultCreateAction(parent, name); +-} +- +-/*! +- Returns a list naming all available widgets that can be built using the +- createWidget() function, i.e all the widgets specified within the given +- plugin paths. +- +- \sa pluginPaths(), createWidget() +- +-*/ +-QStringList QUiLoader::availableWidgets() const +-{ +- Q_D(const QUiLoader); +- +- d->setupWidgetMap(); +- widget_map available = *g_widgets(); +- +- const auto &customWidgets = d->builder.customWidgets(); +- for (QDesignerCustomWidgetInterface *plugin : customWidgets) +- available.insert(plugin->name(), true); +- +- return available.keys(); +-} +- +- +-/*! +- \since 4.5 +- Returns a list naming all available layouts that can be built using the +- createLayout() function +- +- \sa createLayout() +-*/ +- +-QStringList QUiLoader::availableLayouts() const +-{ +- QStringList rc; +-#define DECLARE_WIDGET(a, b) +-#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a)); +- +-#include "widgets.table" +- +-#undef DECLARE_WIDGET +-#undef DECLARE_LAYOUT +- return rc; +-} +- +-/*! +- Sets the working directory of the loader to \a dir. The loader will look +- for other resources, such as icons and resource files, in paths relative to +- this directory. +- +- \sa workingDirectory() +-*/ +- +-void QUiLoader::setWorkingDirectory(const QDir &dir) +-{ +- Q_D(QUiLoader); +- d->builder.setWorkingDirectory(dir); +-} +- +-/*! +- Returns the working directory of the loader. +- +- \sa setWorkingDirectory() +-*/ +- +-QDir QUiLoader::workingDirectory() const +-{ +- Q_D(const QUiLoader); +- return d->builder.workingDirectory(); +-} +-/*! +- \since 4.5 +- +- If \a enabled is true, user interfaces loaded by this loader will +- automatically retranslate themselves upon receiving a language change +- event. Otherwise, the user interfaces will not be retranslated. +- +- \sa isLanguageChangeEnabled() +-*/ +- +-void QUiLoader::setLanguageChangeEnabled(bool enabled) +-{ +- Q_D(QUiLoader); +- d->builder.dynamicTr = enabled; +-} +- +-/*! +- \since 4.5 +- +- Returns true if dynamic retranslation on language change is enabled; +- returns false otherwise. +- +- \sa setLanguageChangeEnabled() +-*/ +- +-bool QUiLoader::isLanguageChangeEnabled() const +-{ +- Q_D(const QUiLoader); +- return d->builder.dynamicTr; +-} +- +-/*! +- \internal +- \since 4.5 +- +- If \a enabled is true, user interfaces loaded by this loader will be +- translated. Otherwise, the user interfaces will not be translated. +- +- \note This is orthogonal to languageChangeEnabled. +- +- \sa isLanguageChangeEnabled(), setLanguageChangeEnabled() +-*/ +- +-void QUiLoader::setTranslationEnabled(bool enabled) +-{ +- Q_D(QUiLoader); +- d->builder.trEnabled = enabled; +-} +- +-/*! +- \internal +- \since 4.5 +- +- Returns true if translation is enabled; returns false otherwise. +- +- \sa setTranslationEnabled() +-*/ +- +-bool QUiLoader::isTranslationEnabled() const +-{ +- Q_D(const QUiLoader); +- return d->builder.trEnabled; +-} +- +-/*! +- Returns a human-readable description of the last error occurred in load(). +- +- \since 5.0 +- \sa load() +-*/ +- +-QString QUiLoader::errorString() const +-{ +- Q_D(const QUiLoader); +- return d->builder.errorString(); +-} +- +-QT_END_NAMESPACE +- +-#include "quiloader.moc" +diff --git x/qttools/src/uitools/quiloader.h y/qttools/src/uitools/quiloader.h +deleted file mode 100644 +index 742b5606f..000000000 +--- x/qttools/src/uitools/quiloader.h ++++ /dev/null +@@ -1,61 +0,0 @@ +-// Copyright (C) 2020 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +- +-#ifndef QUILOADER_H +-#define QUILOADER_H +- +-#include +-#include +-#include +- +-QT_BEGIN_NAMESPACE +- +-class QWidget; +-class QLayout; +-class QAction; +-class QActionGroup; +-class QString; +-class QIODevice; +-class QDir; +- +-class QUiLoaderPrivate; +-class Q_UITOOLS_EXPORT QUiLoader : public QObject +-{ +- Q_OBJECT +-public: +- explicit QUiLoader(QObject *parent = nullptr); +- ~QUiLoader() override; +- +- QStringList pluginPaths() const; +- void clearPluginPaths(); +- void addPluginPath(const QString &path); +- +- QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr); +- QStringList availableWidgets() const; +- QStringList availableLayouts() const; +- +- virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString()); +- virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString()); +- virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString()); +- virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString()); +- +- void setWorkingDirectory(const QDir &dir); +- QDir workingDirectory() const; +- +- void setLanguageChangeEnabled(bool enabled); +- bool isLanguageChangeEnabled() const; +- +- void setTranslationEnabled(bool enabled); +- bool isTranslationEnabled() const; +- +- QString errorString() const; +- +-private: +- QScopedPointer d_ptr; +- Q_DECLARE_PRIVATE(QUiLoader) +- Q_DISABLE_COPY_MOVE(QUiLoader) +-}; +- +-QT_END_NAMESPACE +- +-#endif // QUILOADER_H +diff --git x/qttools/src/uitools/quiloader_p.h y/qttools/src/uitools/quiloader_p.h +deleted file mode 100644 +index efd943217..000000000 +--- x/qttools/src/uitools/quiloader_p.h ++++ /dev/null +@@ -1,77 +0,0 @@ +-// Copyright (C) 2020 The Qt Company Ltd. +-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +- +-#ifndef QUILOADER_P_H +-#define QUILOADER_P_H +- +-// +-// W A R N I N G +-// ------------- +-// +-// This file is not part of the Qt API. It exists purely as an +-// implementation detail. This header file may change from version to +-// version without notice, or even be removed. +-// +-// We mean it. +-// +- +-#include +-#include +-#include +- +-QT_FORWARD_DECLARE_CLASS(QDataStream) +- +-// This file is here for use by the form preview in Linguist. If you change anything +-// here or in the code which uses it, remember to adapt Linguist accordingly. +- +-#define PROP_GENERIC_PREFIX "_q_notr_" +-#define PROP_TOOLITEMTEXT "_q_toolItemText_notr" +-#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr" +-#define PROP_TABPAGETEXT "_q_tabPageText_notr" +-#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr" +-#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr" +- +-QT_BEGIN_NAMESPACE +- +-class Q_UITOOLS_EXPORT QUiTranslatableStringValue +-{ +-public: +- QByteArray value() const { return m_value; } +- void setValue(const QByteArray &value) { m_value = value; } +- QByteArray qualifier() const { return m_qualifier; } +- void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; } +- +- QString translate(const QByteArray &className, bool idBased) const; +- +-private: +- QByteArray m_value; +- QByteArray m_qualifier; // Comment or ID for id-based tr(). +-}; +- +-#ifndef QT_NO_DATASTREAM +-Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); +-Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); +-#endif // QT_NO_DATASTREAM +- +-struct QUiItemRolePair { +- int realRole; +- int shadowRole; +-}; +- +-#ifdef QFORMINTERNAL_NAMESPACE +-namespace QFormInternal +-{ +-#endif +- +-extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; +- +-#ifdef QFORMINTERNAL_NAMESPACE +-} +-#endif +- +-QT_END_NAMESPACE +- +-Q_DECLARE_METATYPE(QUiTranslatableStringValue) +- +- +-#endif // QUILOADER_P_H +diff --git x/qttools/sync.profile y/qttools/sync.profile +index caa7ed5ad..de4261afc 100644 +--- x/qttools/sync.profile ++++ y/qttools/sync.profile +@@ -1,8 +1,8 @@ + %modules = ( # path to module name map + "QtTools" => "$basedir/src/global", + "QtHelp" => "$basedir/src/assistant/help", +- "QtUiTools" => "$basedir/src/uitools", +- "QtUiPlugin" => "$basedir/src/uiplugin", ++ "QtUiTools" => "$basedir/src/designer/src/uitools", ++ "QtUiPlugin" => "$basedir/src/designer/src/uiplugin", + "QtDesigner" => "$basedir/src/designer/src/lib", + "QtDesignerComponents" => "$basedir/src/designer/src/components/lib", + ); diff --git a/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch b/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch new file mode 100644 index 0000000..2aa8020 --- /dev/null +++ b/libs/patches/qtwebengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch @@ -0,0 +1,36 @@ +From a120b53dcef4aebd5e7bea35bc6fc6c462e748f1 Mon Sep 17 00:00:00 2001 +From: Alexey Edelev +Date: Wed, 23 Nov 2022 12:40:45 +0100 +Subject: Fix Linux build with CMake versions >= 3.25 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 'LINUX' variable exists in CMake since the version 3.25. This +variable previously was undefined while preparsing the configure.cmake +files. Since the CMake script that defines the 'check_for_ulimit' +function is not included while evaluating configure.cmake first time +we need to add a stub. + +Change-Id: I25bdec4f4a1b6af23174507a8f0f9cbf01f0c398 +Reviewed-by: Jörg Bornemann +(cherry picked from commit 240e71877865ed07e4c8d5bd4553aa0772c2adf4) +Reviewed-by: Qt Cherry-pick Bot +(cherry picked from commit 517d0890f9e95c841bea3421f2455651ca0d8070) +--- + configure.cmake | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git x/qtwebengine/configure.cmake y/qtwebengine/configure.cmake +index f485c1b4b..fff76d54a 100644 +--- x/qtwebengine/configure.cmake ++++ y/qtwebengine/configure.cmake +@@ -3,6 +3,8 @@ if(QT_CONFIGURE_RUNNING) + endfunction() + function(add_check_for_support) + endfunction() ++ function(check_for_ulimit) ++ endfunction() + else() + find_package(Ninja 1.7.2) + find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT) diff --git a/libs/patches.cmake b/libs/patches.cmake new file mode 100644 index 0000000..fcedd53 --- /dev/null +++ b/libs/patches.cmake @@ -0,0 +1,223 @@ +cmake_minimum_required(VERSION 3.19.0) + +# How to use +# +# Create an empty directory and provide it by -DREPOSITORY_DIR or set +# REPOSITORY_DIR as environment variable. +# +# - Apply existing patches +# $ cmake -DCMD=apply -P libs/patches.cmake +# 1. This will clone all repositores to REPOSITORY_DIR. +# 2. Checkout git tag from Versions.cmake to a new ausweisap_ branch. +# It will delete that branch if it exist. +# 3. Apply all patches to the new branch. +# +# - Generate patches from repositories +# $ cmake -DCMD=generate -P libs/patches.cmake +# 1. All existing patches in "patches" directory will be deleted. +# 2. Branch of current Version on all repositories in REPOSITORY_DIR will be scanned. +# 3. All changesets from the latest tag will be exported to "patches" dir. +# +# If you need a new repository you can clone it into REPOSITORY_DIR. +# Checkout the release tag of used Version.cmake and cherry-pick or add +# changesets to it. It will be exported with "generate". +# If you need to remove patches, just delete the changesets or the whole clone. +# +# - Upgrade Qt or OpenSSL +# 1. Apply all patches with this script and do the following on each repository. +# The version is an example and should be adjusted! +# 2. git checkout ausweisapp_6.4.3 -b ausweisapp_6.6.0 +# 3. git rebase --onto v6.6.0 v6.4.3 HEAD +# 4. Bump version in Versions.cmake and use this script to generate the patches. + +if(NOT CMAKE_SCRIPT_MODE_FILE OR NOT CMD) + message(FATAL_ERROR "Usage: cmake -DCMD=apply|generate -P libs/patches.cmake") +endif() + +find_package(Git REQUIRED) + +if(NOT REPOSITORY_DIR) + set(REPOSITORY_DIR $ENV{REPOSITORY_DIR}) + if(NOT REPOSITORY_DIR) + message(FATAL_ERROR "Define REPOSITORY_DIR for local repositories") + endif() + if(NOT EXISTS "${REPOSITORY_DIR}") + message(FATAL_ERROR "REPOSITORY_DIR ${REPOSITORY_DIR} does not exist") + endif() +endif() + +get_filename_component(libs_dir "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY) +set(patch_dir "${libs_dir}/patches") +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../cmake;${libs_dir}") +include(Versions) + +function(execute_dir dir) + execute_process(COMMAND ${GIT_EXECUTABLE} ${ARGN} + WORKING_DIRECTORY "${REPOSITORY_DIR}/${dir}" + RESULT_VARIABLE _result) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "git failed: ${_result}") + endif() +endfunction() + +function(execute) + execute_dir("" ${ARGN}) +endfunction() + +function(git_clone prefix) + if(NOT EXISTS "${REPOSITORY_DIR}/${prefix}") + message(STATUS "Repository not found: ${prefix}") + if(prefix STREQUAL "openssl") + execute(clone "https://github.com/openssl/openssl" "${prefix}") + elseif(prefix MATCHES "qt") + execute(clone "https://code.qt.io/qt/${prefix}.git" "${prefix}") + endif() + endif() +endfunction() + +function(git_checkout prefix) + get_version_branch("${prefix}" version tmp_branch) + execute_dir("${prefix}" fetch) + execute_dir("${prefix}" checkout -q ${version}) + execute_process(COMMAND ${GIT_EXECUTABLE} branch -D ${tmp_branch} WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix}) + execute_process(COMMAND ${GIT_EXECUTABLE} am --abort WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix} OUTPUT_QUIET ERROR_QUIET) + execute_dir("${prefix}" checkout ${version} -b ${tmp_branch}) +endfunction() + +function(get_version_branch prefix _version _branch) + set(tmp_branch ausweisapp) + if(prefix STREQUAL "openssl") + set(version openssl-${OPENSSL}) + set(tmp_branch ${tmp_branch}_${OPENSSL}) + elseif(prefix MATCHES "qt") + set(version v${QT}) + set(tmp_branch ${tmp_branch}_${QT}) + endif() + + set(${_version} "${version}" PARENT_SCOPE) + set(${_branch} "${tmp_branch}" PARENT_SCOPE) +endfunction() + +function(apply_patches) + file(GLOB PATCHES "${patch_dir}/*.patch") + foreach(patch ${PATCHES}) + get_filename_component(filename "${patch}" NAME) + string(REGEX MATCH "([a-z|-]+)-[0-9]+.+" _unused "${filename}") + set(prefix ${CMAKE_MATCH_1}) + + list(APPEND prefixes "${prefix}") + list(APPEND "${prefix}" "${patch}") + + if(NOT (prefix STREQUAL "openssl" OR prefix MATCHES "qt")) + message(FATAL_ERROR "Prefix unknown: ${prefix}") + endif() + endforeach() + + list(REMOVE_DUPLICATES prefixes) + foreach(prefix ${prefixes}) + message(STATUS "Apply component: ${prefix}") + git_clone(${prefix}) + git_checkout(${prefix}) + + foreach(patch ${${prefix}}) + if(prefix STREQUAL "openssl") + set(p 1) + elseif(prefix MATCHES "qt") + set(p 2) + endif() + + execute_process(COMMAND ${CMAKE_COMMAND} -E env GIT_COMMITTER_NAME="Governikus" GIT_COMMITTER_EMAIL="" -- + ${GIT_EXECUTABLE} am --whitespace=fix --no-gpg-sign --committer-date-is-author-date -p${p} "${patch}" + WORKING_DIRECTORY "${REPOSITORY_DIR}/${prefix}" + RESULT_VARIABLE _result) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "cannot apply patch: ${_result}") + endif() + endforeach() + endforeach() +endfunction() + + +function(get_latest_tag _out repo) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 + WORKING_DIRECTORY ${repo} + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(${_result} EQUAL 0) + set(${_out} "${_output}" PARENT_SCOPE) + endif() +endfunction() + +function(get_current_branch _out repo) + execute_process(COMMAND ${GIT_EXECUTABLE} branch --show-current + WORKING_DIRECTORY ${repo} + OUTPUT_VARIABLE _output + RESULT_VARIABLE _result + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(NOT "${_result}" EQUAL 0) + message(FATAL_ERROR "git failed: ${_result}") + endif() + set(${_out} "${_output}" PARENT_SCOPE) +endfunction() + +function(rename_patches component) + file(GLOB PATCHES "${patch_dir}/*.patch") + foreach(patch ${PATCHES}) + get_filename_component(filename "${patch}" NAME) + if(filename MATCHES "^[0-9]+.*") + file(RENAME "${patch}" "${patch_dir}/${component}-${filename}") + endif() + endforeach() +endfunction() + +function(generate_patches) + file(GLOB PATCHES "${patch_dir}/*.patch") + if(PATCHES) + file(REMOVE ${PATCHES}) + endif() + + list(APPEND prefixes openssl qt) + foreach(prefix ${prefixes}) + file(GLOB REPOS "${REPOSITORY_DIR}/${prefix}*") + foreach(repo ${REPOS}) + get_filename_component(dirname "${repo}" NAME) + get_version_branch("${prefix}" version tmp_branch) + execute_process(COMMAND ${GIT_EXECUTABLE} checkout -q ${tmp_branch} WORKING_DIRECTORY ${repo} OUTPUT_QUIET ERROR_QUIET) + get_current_branch(current_branch "${repo}") + if(current_branch STREQUAL tmp_branch) + get_latest_tag(latesttag "${repo}") + message(STATUS "Generate patches of ${dirname} since tag ${latesttag}") + + if(dirname STREQUAL "openssl") + set(component "") + else() + set(component "${dirname}/") + endif() + + execute_dir("${dirname}" format-patch --no-signature --no-renames --no-binary --src-prefix=x/${component} --dst-prefix=y/${component} -k ${latesttag}..HEAD -o "${patch_dir}") + rename_patches(${dirname}) + else() + message(STATUS "Skip patches of ${dirname} and branch ${current_branch}") + endif() + endforeach() + endforeach() +endfunction() + + + +if(CMD STREQUAL "generate") + message(STATUS "Generate patches!") + generate_patches() +elseif(CMD STREQUAL "apply") + message(STATUS "Apply patches!") + apply_patches() +else() + message(FATAL_ERROR "Unknown CMD: ${CMD}") +endif() diff --git a/resources/ausweisapp_android.qrc b/resources/ausweisapp_android.qrc index e8a5f78..47d5d95 100644 --- a/resources/ausweisapp_android.qrc +++ b/resources/ausweisapp_android.qrc @@ -1,6 +1,5 @@ - images/android/material_phone_android.svg images/android/material_share.svg diff --git a/resources/ausweisapp_desktop.qrc b/resources/ausweisapp_desktop.qrc index 02422ee..90d7d0e 100644 --- a/resources/ausweisapp_desktop.qrc +++ b/resources/ausweisapp_desktop.qrc @@ -1,6 +1,7 @@ images/macos/appIcon.svg + images/desktop/info_white.svg images/desktop/titlebar_arrow.svg images/desktop/material_assistant.svg images/desktop/material_bug_report.svg @@ -13,6 +14,8 @@ images/desktop/material_question_answer.svg images/desktop/material_highlight.svg images/desktop/material_menu_book.svg + images/desktop/material_menu_book_white.svg + images/desktop/material_settings_white.svg images/desktop/material_open_in_browser.svg images/desktop/material_a11y.svg images/desktop/material_privacy.svg diff --git a/resources/ausweisapp_ios.qrc b/resources/ausweisapp_ios.qrc index 1827418..401170d 100644 --- a/resources/ausweisapp_ios.qrc +++ b/resources/ausweisapp_ios.qrc @@ -1,6 +1,5 @@ - images/ios/material_phone_iphone.svg images/ios/share.svg diff --git a/resources/ausweisapp_mobile.qrc b/resources/ausweisapp_mobile.qrc index a6ba903..f861f5d 100644 --- a/resources/ausweisapp_mobile.qrc +++ b/resources/ausweisapp_mobile.qrc @@ -1,224 +1,220 @@ - qtquickcontrols2.conf - images/mobile/device.svg - images/mobile/icon_nfc.svg - images/mobile/icon_smart.svg - images/mobile/icon_remote.svg - images/mobile/icon_simulator.svg - images/mobile/material_arrow_right.svg - images/mobile/material_arrow_back.svg - images/mobile/material_backspace.svg - images/mobile/material_view_headline.svg - images/mobile/material_home.svg - images/mobile/phone_smart.svg - images/mobile/phone_nfc.svg - images/mobile/phone_nfc_with_card.svg - images/mobile/phone_remote.svg - images/mobile/phone_simulator.svg - images/mobile/generic_id_card.svg images/android/stay_primary_landscape-24px.svg images/android/stay_primary_portrait-24px.svg images/ios/material_arrow_left.svg images/ios/material_cancel.svg images/ios/material_more_horiz.svg + images/material_add.svg + images/mobile/device.svg + images/mobile/generic_id_card.svg + images/mobile/icon_nfc.svg + images/mobile/icon_remote.svg + images/mobile/icon_simulator.svg + images/mobile/icon_smart.svg + images/mobile/material_arrow_back.svg + images/mobile/material_arrow_right.svg + images/mobile/material_backspace.svg + images/mobile/material_home.svg + images/mobile/material_view_headline.svg + images/mobile/phone_card_reader.svg + images/mobile/phone_nfc.svg + images/mobile/phone_nfc_with_card.svg + images/mobile/phone_remote.svg + images/mobile/phone_simulator.svg + images/mobile/phone_smart.svg + images/provider/ios/citizen.svg + images/provider/citizen_bg.svg + images/provider/citizen_button.svg + images/provider/default_bg.svg + images/provider/ios/finance.svg + images/provider/finance_bg.svg + images/provider/finance_button.svg images/provider/ios/general.svg - images/provider/ios/citizen.svg - images/provider/ios/finance.svg + images/provider/general_bg.svg + images/provider/general_button.svg images/provider/ios/insurance.svg + images/provider/insurance_bg.svg + images/provider/insurance_button.svg images/provider/ios/other.svg - images/provider/default_bg.svg - images/provider/citizen_button.svg - images/provider/finance_button.svg - images/provider/general_button.svg - images/provider/insurance_button.svg + images/provider/other_bg.svg images/provider/other_button.svg - images/provider/citizen_bg.svg - images/provider/finance_bg.svg - images/provider/general_bg.svg - images/provider/insurance_bg.svg - images/provider/other_bg.svg - images/tutorial/main_menu_what_caret.svg - images/tutorial/main_menu_where_caret.svg - images/tutorial/main_menu_how_caret.svg - images/tutorial/main_menu_important_caret.svg + images/tutorial/arrow_blue.svg + images/tutorial/arrows.svg images/tutorial/background_icon_how.svg + images/tutorial/background_icon_important.svg images/tutorial/background_icon_where.svg - images/tutorial/background_icon_important.svg + images/tutorial/button_de.png + images/tutorial/button_en.png + images/tutorial/button_en.png + images/tutorial/button_en.png + images/tutorial/bva.svg + images/tutorial/check.svg + images/tutorial/circle-1.svg + images/tutorial/circle-2.svg + images/tutorial/circle-3.svg + images/tutorial/circle-4.svg + images/tutorial/circle-lock-2.svg + images/tutorial/circle-lock.svg + images/tutorial/click.svg + images/tutorial/cross.svg + images/tutorial/desktop.svg + images/tutorial/hand.svg + images/tutorial/hint.svg + images/tutorial/how_desktop.svg + images/tutorial/how_device_lineup.svg + images/tutorial/how_form_no_fun.svg + images/tutorial/how_method_nfc.svg + images/tutorial/how_method_sac_desktop.svg + images/tutorial/how_method_sac_mobile.svg + images/tutorial/how_questions_everywhere.svg images/tutorial/icon_box.svg images/tutorial/icon_circle.svg images/tutorial/icon_diamond.svg images/tutorial/icon_star.svg - images/tutorial/arrow_blue.svg - images/tutorial/arrows.svg - images/tutorial/button_de.png - images/tutorial/button_en.png images/tutorial/identify.svg - images/tutorial/questionmark.svg - images/tutorial/hint.svg - images/tutorial/thumb_up.svg - images/tutorial/hand.svg - images/tutorial/check.svg - images/tutorial/cross.svg - images/tutorial/click.svg - images/tutorial/save.svg - images/tutorial/bva.svg - images/tutorial/provider_home.svg - images/tutorial/rectangles.svg + images/tutorial/important_lets_go.svg + images/tutorial/important_pin5.svg + images/tutorial/important_pin6.svg + images/tutorial/important_space_questionmark.svg images/tutorial/laptop.svg - images/tutorial/tablet.svg - images/tutorial/tablet-nfc.svg - images/tutorial/tablet-no-nfc.svg - images/tutorial/reader.svg - images/tutorial/desktop.svg + images/tutorial/letters.svg + images/tutorial/main_menu_how_caret.svg + images/tutorial/main_menu_important_caret.svg + images/tutorial/main_menu_what_caret.svg + images/tutorial/main_menu_where_caret.svg + images/tutorial/nfc.svg + images/tutorial/no-nfc.svg images/tutorial/phone.svg images/tutorial/phone_border.svg images/tutorial/phone_list.svg images/tutorial/phone_screen.svg - images/tutorial/nfc.svg - images/tutorial/no-nfc.svg - images/tutorial/wifi.svg - images/tutorial/letters.svg - images/tutorial/usb.svg - images/tutorial/circle-1.svg - images/tutorial/circle-2.svg - images/tutorial/circle-3.svg - images/tutorial/circle-4.svg - images/tutorial/circle-lock.svg - images/tutorial/circle-lock-2.svg - images/tutorial/up_icon.svg images/tutorial/phone_screen_de.png images/tutorial/phone_screen_en.png + images/tutorial/phone_screen_en.png + images/tutorial/phone_screen_en.png images/tutorial/pin-5@2x.png images/tutorial/pin-6@2x.png - images/tutorial/user-tine@3x.png + images/tutorial/play_movie.png + images/tutorial/provider_home.svg images/tutorial/providericons.png - images/tutorial/play_movie.png - images/tutorial/screenshot_check_id_card_android_de.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_de.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_cert_android_de.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_de.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_providerlist_android_de.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_de.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_de.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_remoteservice_ios_de.png - images/tutorial/screenshot_pairing_de.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_choose_reader_android_de.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_de.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_android_de.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_pin_management_menu_ios_de.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_android_de.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/screenshot_start_ios_de.png - images/tutorial/screenshot_selfauthentication_android_de.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_de.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/section_seperator_what.svg - images/tutorial/section_seperator_where.svg - images/tutorial/section_seperator_how.svg - images/tutorial/section_seperator_important.svg - images/tutorial/where_overview_question.svg - images/tutorial/where_identify_now_de.svg - images/tutorial/where_identify_now_en.svg - images/tutorial/where_userdata_example_de.svg - images/tutorial/where_userdata_example_en.svg - images/tutorial/where_lay_down_id.svg - images/tutorial/where_pin6.svg - images/tutorial/how_questions_everywhere.svg - images/tutorial/how_device_lineup.svg - images/tutorial/how_method_nfc.svg - images/tutorial/how_method_sac_desktop.svg - images/tutorial/how_method_sac_mobile.svg - images/tutorial/how_form_no_fun.svg - images/tutorial/how_desktop.svg - images/tutorial/important_pin5.svg - images/tutorial/important_pin6.svg - images/tutorial/important_lets_go.svg - images/tutorial/important_space_questionmark.svg + images/tutorial/questionmark.svg + images/tutorial/reader.svg + images/tutorial/reader_nfc_finished.svg + images/tutorial/reader_nfc_npa_on_smartphone.svg + images/tutorial/reader_nfc_pin6.svg images/tutorial/reader_nfc_provider_on_smartphone.svg - images/tutorial/reader_nfc_npa_on_smartphone.svg images/tutorial/reader_nfc_smartphone_nfc_position.svg - images/tutorial/reader_nfc_finished.svg - images/tutorial/reader_nfc_pin6.svg images/tutorial/reader_nfc_userdata_example_de.svg images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_provider_on_laptop.svg - images/tutorial/reader_sac_npa_on_laptop.svg + images/tutorial/reader_nfc_userdata_example_en.svg + images/tutorial/reader_nfc_userdata_example_en.svg images/tutorial/reader_sac_aa2_ok.svg images/tutorial/reader_sac_menu_android_de.svg images/tutorial/reader_sac_menu_android_en.svg + images/tutorial/reader_sac_menu_android_en.svg + images/tutorial/reader_sac_menu_android_en.svg images/tutorial/reader_sac_menu_ios_de.svg images/tutorial/reader_sac_menu_ios_en.svg + images/tutorial/reader_sac_menu_ios_en.svg + images/tutorial/reader_sac_menu_ios_en.svg images/tutorial/reader_sac_no_nfc_devices.svg images/tutorial/reader_sac_no_nfc_provider.svg - - - images/tutorial/button_en.png - images/tutorial/phone_screen_en.png + images/tutorial/reader_sac_npa_on_laptop.svg + images/tutorial/reader_sac_provider_on_laptop.svg + images/tutorial/rectangles.svg + images/tutorial/save.svg + images/tutorial/screenshot_cert_android_de.png + images/tutorial/screenshot_cert_android_en.png images/tutorial/screenshot_cert_android_en.png + images/tutorial/screenshot_cert_android_en.png + images/tutorial/screenshot_cert_ios_de.png + images/tutorial/screenshot_cert_ios_en.png images/tutorial/screenshot_cert_ios_en.png + images/tutorial/screenshot_cert_ios_en.png + images/tutorial/screenshot_check_id_card_android_de.png + images/tutorial/screenshot_check_id_card_android_en.png + images/tutorial/screenshot_check_id_card_android_en.png images/tutorial/screenshot_check_id_card_android_en.png + images/tutorial/screenshot_check_id_card_ios_de.png + images/tutorial/screenshot_check_id_card_ios_en.png + images/tutorial/screenshot_check_id_card_ios_en.png images/tutorial/screenshot_check_id_card_ios_en.png + images/tutorial/screenshot_choose_reader_android_de.png + images/tutorial/screenshot_choose_reader_android_en.png images/tutorial/screenshot_choose_reader_android_en.png + images/tutorial/screenshot_choose_reader_android_en.png + images/tutorial/screenshot_choose_reader_ios_de.png + images/tutorial/screenshot_choose_reader_ios_en.png images/tutorial/screenshot_choose_reader_ios_en.png + images/tutorial/screenshot_choose_reader_ios_en.png + images/tutorial/screenshot_pairing_de.png + images/tutorial/screenshot_pairing_en.png images/tutorial/screenshot_pairing_en.png + images/tutorial/screenshot_pairing_en.png + images/tutorial/screenshot_pin_management_menu_android_de.png + images/tutorial/screenshot_pin_management_menu_android_en.png + images/tutorial/screenshot_pin_management_menu_android_en.png images/tutorial/screenshot_pin_management_menu_android_en.png + images/tutorial/screenshot_pin_management_menu_ios_de.png + images/tutorial/screenshot_pin_management_menu_ios_en.png images/tutorial/screenshot_pin_management_menu_ios_en.png + images/tutorial/screenshot_pin_management_menu_ios_en.png + images/tutorial/screenshot_providerlist_android_de.png + images/tutorial/screenshot_providerlist_android_en.png + images/tutorial/screenshot_providerlist_android_en.png images/tutorial/screenshot_providerlist_android_en.png + images/tutorial/screenshot_providerlist_ios_de.png + images/tutorial/screenshot_providerlist_ios_en.png + images/tutorial/screenshot_providerlist_ios_en.png images/tutorial/screenshot_providerlist_ios_en.png + images/tutorial/screenshot_remoteservice_android_de.png + images/tutorial/screenshot_remoteservice_android_en.png images/tutorial/screenshot_remoteservice_android_en.png + images/tutorial/screenshot_remoteservice_android_en.png + images/tutorial/screenshot_remoteservice_ios_de.png + images/tutorial/screenshot_remoteservice_ios_en.png images/tutorial/screenshot_remoteservice_ios_en.png + images/tutorial/screenshot_remoteservice_ios_en.png + images/tutorial/screenshot_selfauthentication_android_de.png + images/tutorial/screenshot_selfauthentication_android_en.png + images/tutorial/screenshot_selfauthentication_android_en.png images/tutorial/screenshot_selfauthentication_android_en.png + images/tutorial/screenshot_selfauthentication_ios_de.png + images/tutorial/screenshot_selfauthentication_ios_en.png + images/tutorial/screenshot_selfauthentication_ios_en.png images/tutorial/screenshot_selfauthentication_ios_en.png + images/tutorial/screenshot_start_android_de.png + images/tutorial/screenshot_start_android_en.png images/tutorial/screenshot_start_android_en.png + images/tutorial/screenshot_start_android_en.png + images/tutorial/screenshot_start_ios_de.png + images/tutorial/screenshot_start_ios_en.png images/tutorial/screenshot_start_ios_en.png - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/src/phone_screen_en.svg + images/tutorial/screenshot_start_ios_en.png + images/tutorial/section_seperator_how.svg + images/tutorial/section_seperator_important.svg + images/tutorial/section_seperator_what.svg + images/tutorial/section_seperator_where.svg + images/tutorial/tablet-nfc.svg + images/tutorial/tablet-no-nfc.svg + images/tutorial/tablet.svg + images/tutorial/thumb_up.svg + images/tutorial/up_icon.svg + images/tutorial/usb.svg + images/tutorial/user-tine@3x.png + images/tutorial/where_identify_now_de.svg + images/tutorial/where_identify_now_en.svg images/tutorial/where_identify_now_en.svg + images/tutorial/where_identify_now_en.svg + images/tutorial/where_lay_down_id.svg + images/tutorial/where_overview_question.svg + images/tutorial/where_pin6.svg + images/tutorial/where_userdata_example_de.svg + images/tutorial/where_userdata_example_en.svg images/tutorial/where_userdata_example_en.svg - - - images/tutorial/button_en.png - images/tutorial/phone_screen_en.png - images/tutorial/screenshot_cert_android_en.png - images/tutorial/screenshot_cert_ios_en.png - images/tutorial/screenshot_check_id_card_android_en.png - images/tutorial/screenshot_check_id_card_ios_en.png - images/tutorial/screenshot_choose_reader_android_en.png - images/tutorial/screenshot_choose_reader_ios_en.png - images/tutorial/screenshot_pairing_en.png - images/tutorial/screenshot_pin_management_menu_android_en.png - images/tutorial/screenshot_pin_management_menu_ios_en.png - images/tutorial/screenshot_providerlist_android_en.png - images/tutorial/screenshot_providerlist_ios_en.png - images/tutorial/screenshot_remoteservice_android_en.png - images/tutorial/screenshot_remoteservice_ios_en.png - images/tutorial/screenshot_selfauthentication_android_en.png - images/tutorial/screenshot_selfauthentication_ios_en.png - images/tutorial/screenshot_start_android_en.png - images/tutorial/screenshot_start_ios_en.png - images/tutorial/reader_nfc_userdata_example_en.svg - images/tutorial/reader_sac_menu_android_en.svg - images/tutorial/reader_sac_menu_ios_en.svg - images/tutorial/src/phone_screen_en.svg - images/tutorial/where_identify_now_en.svg images/tutorial/where_userdata_example_en.svg + images/tutorial/wifi.svg + qtquickcontrols2.conf diff --git a/resources/images/android/adaptive_monochrome_beta.svg b/resources/images/android/adaptive_monochrome_beta.svg new file mode 100644 index 0000000..148445e --- /dev/null +++ b/resources/images/android/adaptive_monochrome_beta.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/adaptive_monochrome_preview.svg b/resources/images/android/adaptive_monochrome_preview.svg new file mode 100644 index 0000000..de08bb3 --- /dev/null +++ b/resources/images/android/adaptive_monochrome_preview.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/android/adaptive_monochrome_release.svg b/resources/images/android/adaptive_monochrome_release.svg new file mode 100644 index 0000000..6e8057b --- /dev/null +++ b/resources/images/android/adaptive_monochrome_release.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/resources/images/android/hdpi/monochrome_npa.png b/resources/images/android/hdpi/monochrome_npa.png new file mode 100644 index 0000000..a1f62c6 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa.png differ diff --git a/resources/images/android/hdpi/monochrome_npa_beta.png b/resources/images/android/hdpi/monochrome_npa_beta.png new file mode 100644 index 0000000..0b02ef3 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/hdpi/monochrome_npa_preview.png b/resources/images/android/hdpi/monochrome_npa_preview.png new file mode 100644 index 0000000..26762f8 Binary files /dev/null and b/resources/images/android/hdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/ldpi/monochrome_npa.png b/resources/images/android/ldpi/monochrome_npa.png new file mode 100644 index 0000000..21d3185 Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa.png differ diff --git a/resources/images/android/ldpi/monochrome_npa_beta.png b/resources/images/android/ldpi/monochrome_npa_beta.png new file mode 100644 index 0000000..cfe2267 Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/ldpi/monochrome_npa_preview.png b/resources/images/android/ldpi/monochrome_npa_preview.png new file mode 100644 index 0000000..6f7b4c1 Binary files /dev/null and b/resources/images/android/ldpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/material_phone_android.svg b/resources/images/android/material_phone_android.svg deleted file mode 100644 index b7a256b..0000000 --- a/resources/images/android/material_phone_android.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/resources/images/android/mdpi/monochrome_npa.png b/resources/images/android/mdpi/monochrome_npa.png new file mode 100644 index 0000000..1e08f0d Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa.png differ diff --git a/resources/images/android/mdpi/monochrome_npa_beta.png b/resources/images/android/mdpi/monochrome_npa_beta.png new file mode 100644 index 0000000..cf03b59 Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/mdpi/monochrome_npa_preview.png b/resources/images/android/mdpi/monochrome_npa_preview.png new file mode 100644 index 0000000..38a2f98 Binary files /dev/null and b/resources/images/android/mdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa.png b/resources/images/android/xhdpi/monochrome_npa.png new file mode 100644 index 0000000..e8acb11 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa_beta.png b/resources/images/android/xhdpi/monochrome_npa_beta.png new file mode 100644 index 0000000..5cb6373 Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xhdpi/monochrome_npa_preview.png b/resources/images/android/xhdpi/monochrome_npa_preview.png new file mode 100644 index 0000000..ac7309a Binary files /dev/null and b/resources/images/android/xhdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa.png b/resources/images/android/xxhdpi/monochrome_npa.png new file mode 100644 index 0000000..fd700d6 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa_beta.png b/resources/images/android/xxhdpi/monochrome_npa_beta.png new file mode 100644 index 0000000..c7647f0 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xxhdpi/monochrome_npa_preview.png b/resources/images/android/xxhdpi/monochrome_npa_preview.png new file mode 100644 index 0000000..6866745 Binary files /dev/null and b/resources/images/android/xxhdpi/monochrome_npa_preview.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa.png b/resources/images/android/xxxhdpi/monochrome_npa.png new file mode 100644 index 0000000..812653d Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa_beta.png b/resources/images/android/xxxhdpi/monochrome_npa_beta.png new file mode 100644 index 0000000..76abeeb Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa_beta.png differ diff --git a/resources/images/android/xxxhdpi/monochrome_npa_preview.png b/resources/images/android/xxxhdpi/monochrome_npa_preview.png new file mode 100644 index 0000000..fc43da6 Binary files /dev/null and b/resources/images/android/xxxhdpi/monochrome_npa_preview.png differ diff --git a/resources/images/desktop/info_white.svg b/resources/images/desktop/info_white.svg new file mode 100644 index 0000000..6725dee --- /dev/null +++ b/resources/images/desktop/info_white.svg @@ -0,0 +1,21 @@ + + + + diff --git a/resources/images/desktop/material_a11y.svg b/resources/images/desktop/material_a11y.svg index a87416f..3b02dc9 100644 --- a/resources/images/desktop/material_a11y.svg +++ b/resources/images/desktop/material_a11y.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/resources/images/desktop/material_assistant.svg b/resources/images/desktop/material_assistant.svg index a703345..fbfd819 100644 --- a/resources/images/desktop/material_assistant.svg +++ b/resources/images/desktop/material_assistant.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_bug_report.svg b/resources/images/desktop/material_bug_report.svg index 718f6b3..fb22e9d 100644 --- a/resources/images/desktop/material_bug_report.svg +++ b/resources/images/desktop/material_bug_report.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_highlight.svg b/resources/images/desktop/material_highlight.svg index ae74430..a9a7692 100644 --- a/resources/images/desktop/material_highlight.svg +++ b/resources/images/desktop/material_highlight.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_menu_book.svg b/resources/images/desktop/material_menu_book.svg index 0a9ef46..e2e3e95 100644 --- a/resources/images/desktop/material_menu_book.svg +++ b/resources/images/desktop/material_menu_book.svg @@ -1 +1 @@ - + diff --git a/resources/images/desktop/material_menu_book_white.svg b/resources/images/desktop/material_menu_book_white.svg new file mode 100644 index 0000000..0a9ef46 --- /dev/null +++ b/resources/images/desktop/material_menu_book_white.svg @@ -0,0 +1 @@ + diff --git a/resources/images/desktop/material_privacy.svg b/resources/images/desktop/material_privacy.svg index 2090184..75866ac 100644 --- a/resources/images/desktop/material_privacy.svg +++ b/resources/images/desktop/material_privacy.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/resources/images/desktop/material_settings_white.svg b/resources/images/desktop/material_settings_white.svg new file mode 100644 index 0000000..f7ca45a --- /dev/null +++ b/resources/images/desktop/material_settings_white.svg @@ -0,0 +1 @@ + diff --git a/resources/images/desktop/material_video.svg b/resources/images/desktop/material_video.svg index 1d5a32e..a753062 100644 --- a/resources/images/desktop/material_video.svg +++ b/resources/images/desktop/material_video.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/resources/images/desktop/material_view_list.svg b/resources/images/desktop/material_view_list.svg index 550b676..d7af03e 100644 --- a/resources/images/desktop/material_view_list.svg +++ b/resources/images/desktop/material_view_list.svg @@ -1 +1 @@ - + diff --git a/resources/images/info.svg b/resources/images/info.svg index 6725dee..81059ac 100644 --- a/resources/images/info.svg +++ b/resources/images/info.svg @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/resources/images/material_add.svg b/resources/images/material_add.svg new file mode 100644 index 0000000..70898c1 --- /dev/null +++ b/resources/images/material_add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/material_help.svg b/resources/images/material_help.svg index 7677f0e..85fb209 100644 --- a/resources/images/material_help.svg +++ b/resources/images/material_help.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_history.svg b/resources/images/material_history.svg index 6975ece..357da24 100644 --- a/resources/images/material_history.svg +++ b/resources/images/material_history.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_live_help.svg b/resources/images/material_live_help.svg index 06255c4..8f975fd 100644 --- a/resources/images/material_live_help.svg +++ b/resources/images/material_live_help.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_lock.svg b/resources/images/material_lock.svg index cfc8a0c..57dd76b 100644 --- a/resources/images/material_lock.svg +++ b/resources/images/material_lock.svg @@ -1 +1 @@ - + diff --git a/resources/images/material_settings.svg b/resources/images/material_settings.svg index f7ca45a..8198641 100644 --- a/resources/images/material_settings.svg +++ b/resources/images/material_settings.svg @@ -1 +1 @@ - + diff --git a/resources/images/mobile/phone_card_reader.svg b/resources/images/mobile/phone_card_reader.svg new file mode 100644 index 0000000..81d3e82 --- /dev/null +++ b/resources/images/mobile/phone_card_reader.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/resources/images/mydata.svg b/resources/images/mydata.svg index 4988d85..8d1a386 100644 --- a/resources/images/mydata.svg +++ b/resources/images/mydata.svg @@ -7,5 +7,5 @@ m 0 3 a 1 1 0 0 1 0 -2 h 9 a 1 1 0 0 1 0 2 z M 31.64 35.75 l -3 -6 a 6 6 0 1 1 2 -1 l 3 6 a 1.118 1.118 0 0 1 -2 1 z m -9.64 -11.8 a 5 5 0 0 0 10 0 a 5 5 0 0 0 -10 0 z - m 1.536 2 a 4 4 0 0 1 0 -4 h 6.928 a 4 4 0 0 1 0 4 z" fill="#ffffff"/> + m 1.536 2 a 4 4 0 0 1 0 -4 h 6.928 a 4 4 0 0 1 0 4 z" fill="#164a8c" /> diff --git a/resources/images/provider.svg b/resources/images/provider.svg index e7d8a8f..cc58a77 100644 --- a/resources/images/provider.svg +++ b/resources/images/provider.svg @@ -1,6 +1,6 @@ - + + + + + + + + + + + + + + + + + diff --git a/resources/packaging/android/full_backup_content.xml b/resources/packaging/android/full_backup_content.xml new file mode 100644 index 0000000..a06f20d --- /dev/null +++ b/resources/packaging/android/full_backup_content.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/packaging/android/lint.aar.xml b/resources/packaging/android/lint.aar.xml index db3ee10..3ce203f 100644 --- a/resources/packaging/android/lint.aar.xml +++ b/resources/packaging/android/lint.aar.xml @@ -1,21 +1,5 @@ - - - - - - - - - - - diff --git a/resources/packaging/android/lint.apk.xml b/resources/packaging/android/lint.apk.xml index 599146f..a0b50d4 100644 --- a/resources/packaging/android/lint.apk.xml +++ b/resources/packaging/android/lint.apk.xml @@ -1,21 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -148,12 +68,4 @@ - - - - - diff --git a/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml b/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml index 4c7b81f..065d6d9 100644 --- a/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml +++ b/resources/packaging/android/res/mipmap-anydpi-v26/npa.xml @@ -2,4 +2,5 @@ + diff --git a/resources/qml/+desktop/main.qml b/resources/qml/+desktop/main.qml index 0fa56a3..c5980ac 100644 --- a/resources/qml/+desktop/main.qml +++ b/resources/qml/+desktop/main.qml @@ -114,6 +114,11 @@ let initialSize = plugin.initialWindowSize; ApplicationModel.scaleFactor = Math.min(width / initialSize.width, height / initialSize.height); } + function showDetachedLogViewIfPresent() { + if (d.detachedLogView !== null) { + d.detachedLogView.show(); + } + } function showMainWindow() { d.suppressAbortWarning = false; if (active) { @@ -187,6 +192,7 @@ function onFireShowRequest(pModule) { d.showMainWindow(); d.closeOpenDialogs(); + d.showDetachedLogViewIfPresent(); switch (pModule) { case UiModule.CURRENT: break; @@ -236,6 +242,12 @@ onActivated: ApplicationModel.openOnlineHelp(menuBar.rightMostAction.helpTopic) } + Shortcut { + enabled: Qt.platform.os === "osx" + sequence: "Ctrl+W" + + onActivated: close() + } Image { anchors.centerIn: parent fillMode: Image.PreserveAspectFit @@ -414,6 +426,12 @@ d.detachedLogView = null; } + Shortcut { + enabled: Qt.platform.os === "osx" + sequence: "Ctrl+W" + + onActivated: close() + } DetachedLogView { anchors.fill: parent focus: true diff --git a/resources/qml/Governikus/AuthView/+desktop/AuthView.qml b/resources/qml/Governikus/AuthView/+desktop/AuthView.qml index 1c077c1..390ef57 100644 --- a/resources/qml/Governikus/AuthView/+desktop/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+desktop/AuthView.qml @@ -31,6 +31,7 @@ Progress, AccessRights, Workflow, + WorkflowError, Password, PasswordInfo, CardPosition, @@ -159,7 +160,23 @@ return Workflow.WaitingFor.None; } + onDeviceUnpaired: function (pDeviceName) { + deviceUnpairedView.deviceName = pDeviceName; + showWithPrecedingView(AuthView.SubViews.WorkflowError); + } onSettingsRequested: authView.showSettings() + } + ResultView { + id: deviceUnpairedView + + property string deviceName + + resultType: ResultView.Type.IsError + //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + visible: d.activeView === AuthView.SubViews.WorkflowError + + onNextView: d.view = AuthView.SubViews.Workflow } EnterPasswordView { id: enterPasswordView @@ -286,11 +303,11 @@ header: AuthModel.errorHeader hintButtonText: AuthModel.statusHintActionText hintText: AuthModel.statusHintText + mailButtonVisible: AuthModel.errorIsMasked popupText: AuthModel.errorText //: INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup. popupTitle: qsTr("Error code: %1").arg(AuthModel.statusCodeString) resultType: AuthModel.resultString ? ResultView.Type.IsError : ResultView.Type.IsSuccess - supportButtonsVisible: AuthModel.errorIsMasked text: AuthModel.resultString visible: d.activeView === AuthView.SubViews.Result diff --git a/resources/qml/Governikus/AuthView/+desktop/EditRights.qml b/resources/qml/Governikus/AuthView/+desktop/EditRights.qml index d2906ef..65d8fc5 100644 --- a/resources/qml/Governikus/AuthView/+desktop/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+desktop/EditRights.qml @@ -105,7 +105,7 @@ id: detailsButton Accessible.description: qsTr("Show more information about the service provider") activeFocusOnTab: true - icon.source: "qrc:///images/info.svg" + icon.source: "qrc:///images/desktop/info_white.svg" //: LABEL DESKTOP text: qsTr("Details about the provider") diff --git a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml index 5129a8f..40cbf79 100644 --- a/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+mobile/+phone/EditRights.qml @@ -19,6 +19,8 @@ property alias dataText: dataPasswordText.text property var workflowModel: AuthModel + signal rightsAccepted + //: LABEL IOS_PHONE ANDROID_PHONE title: qsTr("Identify") @@ -119,10 +121,7 @@ qsTr("PIN")) tintIcon: true - onClicked: { - ChatModel.transferAccessRights(); - workflowModel.continueWorkflow(); - } + onClicked: rightsAccepted() } GText { id: dataPasswordText @@ -138,7 +137,7 @@ //: LABEL IOS_PHONE ANDROID_PHONE title: qsTr("Transactional information") - visible: !!AuthModel.transactionInfo || (!writeData.visible && !readData.visible) + visible: !!workflowModel.transactionInfo || (!writeData.visible && !readData.visible) anchors { left: parent.left diff --git a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml b/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml index bc13e46..bbffaad 100644 --- a/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml +++ b/resources/qml/Governikus/AuthView/+mobile/+tablet/EditRights.qml @@ -19,6 +19,8 @@ property alias dataText: dataPasswordText.text property var workflowModel: AuthModel + signal rightsAccepted + //: LABEL ANDROID_TABLET IOS_TABLET title: qsTr("Identify") @@ -80,10 +82,7 @@ qsTr("PIN")) tintIcon: true - onClicked: { - ChatModel.transferAccessRights(); - workflowModel.continueWorkflow(); - } + onClicked: rightsAccepted() anchors { right: parent.right diff --git a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml index 941450c..89346e3 100644 --- a/resources/qml/Governikus/AuthView/+mobile/AuthView.qml +++ b/resources/qml/Governikus/AuthView/+mobile/AuthView.qml @@ -14,6 +14,7 @@ import Governikus.Workflow 1.0 import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.AuthModel 1.0 +import Governikus.Type.ChatModel 1.0 import Governikus.Type.LogModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PasswordType 1.0 @@ -81,6 +82,10 @@ Component { id: editRights EditRights { + onRightsAccepted: { + ChatModel.transferAccessRights(); + AuthModel.continueWorkflow(); + } } } Component { diff --git a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml index 3c23912..82e33d5 100644 --- a/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml +++ b/resources/qml/Governikus/ChangePinView/+desktop/ChangePinView.qml @@ -22,6 +22,7 @@ enum SubViews { Start, Workflow, + WorkflowError, Password, NoPassword, PasswordInfo, @@ -144,7 +145,23 @@ return Workflow.WaitingFor.None; } + onDeviceUnpaired: function (pDeviceName) { + deviceUnpairedView.deviceName = pDeviceName; + showWithPrecedingView(ChangePinView.SubViews.WorkflowError); + } onSettingsRequested: baseItem.showSettings() + } + ResultView { + id: deviceUnpairedView + + property string deviceName + + resultType: ResultView.Type.IsError + //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + visible: d.activeView === ChangePinView.SubViews.WorkflowError + + onNextView: d.view = ChangePinView.SubViews.Workflow } EnterPasswordView { id: enterPasswordView @@ -238,8 +255,8 @@ id: pinResult hintButtonText: ChangePinModel.statusHintActionText hintText: ChangePinModel.statusHintText + mailButtonVisible: ChangePinModel.errorIsMasked resultType: ChangePinModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess - supportButtonsVisible: ChangePinModel.errorIsMasked text: ChangePinModel.resultString visible: d.activeView === ChangePinView.SubViews.Result diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml index 22e9f8e..076fd46 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/EnterPasswordView.qml @@ -200,7 +200,7 @@ } if (passwordType === PasswordType.REMOTE_PIN) { //: INFO DESKTOP The pairing code needs to be supplied. - return qsTr("Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC)."); + return qsTr("Enter the pairing code shown on your smartphone."); } //: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. diff --git a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml index f96c4dd..6f80492 100644 --- a/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml +++ b/resources/qml/Governikus/EnterPasswordView/+desktop/NumberPad.qml @@ -63,6 +63,7 @@ enabled: baseItem.deleteEnabled fontScale: 0.75 text: "C" + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.deletePressed() } @@ -80,6 +81,7 @@ enabled: baseItem.submitEnabled fontScale: 0.75 text: "OK" + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.submitPressed() } diff --git a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml index e8a6dab..4ec9fcb 100644 --- a/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml +++ b/resources/qml/Governikus/EnterPasswordView/+mobile/NumberPad.qml @@ -56,6 +56,7 @@ enabled: baseItem.deleteEnabled icon.source: "qrc:///images/mobile/material_backspace.svg" text: qsTr("Delete last digit") + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.deletePressed() } @@ -74,6 +75,7 @@ enabled: baseItem.submitEnabled icon.source: "qrc:///images/material_check.svg" text: qsTr("Submit") + visualPrivacy: SettingsModel.visualPrivacy onClicked: baseItem.submitPressed() } diff --git a/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml b/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml index 4081d8d..69aa028 100644 --- a/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml +++ b/resources/qml/Governikus/Global/+mobile/IosBackGestureMouseArea.qml @@ -18,7 +18,7 @@ enabled: visible preventStealing: enabled - onPositionChanged: { + onPositionChanged: mouse => { let currentVelocity = mouse.x - previousPosX; velocity = (velocity + currentVelocity) / 2.0; previousPosX = mouse.x; @@ -33,7 +33,7 @@ mouse.accepted = false; } } - onReleased: { + onReleased: mouse => { let swipeDistance = mouse.x - startPosX; if (swipeDistance > minSwipeDistance && velocity > minVelocity) { backGestureTriggered(); diff --git a/resources/qml/Governikus/Global/StatusIcon.qml b/resources/qml/Governikus/Global/StatusIcon.qml index 8fd841f..14b27c5 100644 --- a/resources/qml/Governikus/Global/StatusIcon.qml +++ b/resources/qml/Governikus/Global/StatusIcon.qml @@ -11,8 +11,8 @@ property alias busy: busyIndicator.visible property alias contentBackgroundColor: content.color property alias source: image.source - property alias text: text.text - property alias textStyle: text.textStyle + property alias text: iconText.text + property alias textStyle: iconText.textStyle border.color: borderEnabled ? Style.color.accent : Style.color.transparent border.width: height / 40 @@ -48,7 +48,7 @@ visible: source.toString().length > 0 } GText { - id: text + id: iconText Accessible.ignored: true anchors.centerIn: parent textStyle: Style.text.title_accent diff --git a/resources/qml/Governikus/Global/Utils.qml b/resources/qml/Governikus/Global/Utils.qml index 8a91062..916ee91 100644 --- a/resources/qml/Governikus/Global/Utils.qml +++ b/resources/qml/Governikus/Global/Utils.qml @@ -4,10 +4,11 @@ pragma Singleton import QtQuick 2.15 import Governikus.Type.ApplicationModel 1.0 +import Governikus.Type.SettingsModel 1.0 QtObject { - function escapeHtml(str) { - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); + function escapeHtml(pStr) { + return String(pStr).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function helpTopicOf(pComponent, pDefaultHelpTopic) { if (pComponent && typeof (pComponent.helpTopic) !== "undefined") { @@ -16,23 +17,33 @@ return pDefaultHelpTopic; } } - function isSameDate(one, another) { - return one.getFullYear() === another.getFullYear() && one.getMonth() === another.getMonth() && one.getDate() === another.getDate(); + function historyDateString(pDate) { + //: LABEL ALL_PLATFORMS + return (isToday(pDate) ? qsTr("today") : + //: LABEL ALL_PLATFORMS + isYesterday(pDate) ? qsTr("yesterday") : + // dddd is without translation because we want the long day name with every language + isThisWeek(pDate) ? pDate.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + pDate.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))); } - function isThisWeek(date) { + function isSameDate(pOne, pAnother) { + return pOne.getFullYear() === pAnother.getFullYear() && pOne.getMonth() === pAnother.getMonth() && pOne.getDate() === pAnother.getDate(); + } + function isThisWeek(pDate) { var monday = new Date; monday.setDate(monday.getDate() - monday.getDay()); - date.setDate(date.getDate() - date.getDay()); - return isSameDate(monday, date); + pDate.setDate(pDate.getDate() - pDate.getDay()); + return isSameDate(monday, pDate); } - function isToday(date) { + function isToday(pDate) { var today = new Date; - return isSameDate(today, date); + return isSameDate(today, pDate); } - function isYesterday(date) { + function isYesterday(pDate) { var yesterday = new Date; yesterday.setDate(yesterday.getDate() - 1); - return isSameDate(yesterday, date); + return isSameDate(yesterday, pDate); } function scrollPageDown(pFlickable) { if (pFlickable.height >= pFlickable.contentHeight) { diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml index 1ea38ea..1af1d03 100644 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml +++ b/resources/qml/Governikus/HistoryView/+desktop/HistoryView.qml @@ -117,7 +117,7 @@ } sectionDelegate: TabbedPaneDelegateIconAndThreeLineText { footerText: model ? model.purpose : "" - headerText: (model ? (Utils.isToday(model.dateTime) ? qsTr("today") : Utils.isYesterday(model.dateTime) ? qsTr("yesterday") : Utils.isThisWeek(model.dateTime) ? model.dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : model.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) : "") + headerText: model ? Utils.historyDateString(model.dateTime) : "" iconPath: model ? model.providerIcon : "" sectionName: model ? model.subject : "" } diff --git a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml index fdc0ea0..aaa85d4 100644 --- a/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml +++ b/resources/qml/Governikus/HistoryView/+desktop/HistoryViewDetails.qml @@ -55,6 +55,7 @@ if (!historyModelItem) { return ""; } + //: LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")); } textUppercase: Font.AllUppercase diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml index f44c84c..f34fe53 100644 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml +++ b/resources/qml/Governikus/HistoryView/+mobile/HistoryListItem.qml @@ -10,11 +10,11 @@ ListItem { property var historyModelItem + //: LABEL ANDROID IOS Accessible.description: qsTr("Click to view details of history entry.") //: LABEL ANDROID IOS footerText: historyModelItem.purpose !== "" ? historyModelItem.purpose : qsTr("Tap for more details") - //: LABEL ANDROID IOS - headerText: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) + headerText: Utils.historyDateString(dateTime) height: 72 icon: providerIcon !== "" ? providerIcon : (historyModelItem ? Category.imageSource(historyModelItem.providerCategory) : Category.imageSource("unknown")) text: subject diff --git a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml b/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml index 99a1b0f..e684ef1 100644 --- a/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml +++ b/resources/qml/Governikus/HistoryView/+mobile/HistoryViewDetails.qml @@ -62,6 +62,7 @@ if (!historyModelItem) { return ""; } + //: LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")); } width: parent.width diff --git a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml index 144dfbb..64bbeae 100644 --- a/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml +++ b/resources/qml/Governikus/Navigation/+mobile/NavigationView.qml @@ -31,8 +31,8 @@ module: UiModule.PROVIDER } ListElement { - desc: QT_TR_NOOP("Remote") - image: "qrc:///images/mobile/platform_specific_phone.svg" + desc: QT_TR_NOOP("Card reader") + image: "qrc:///images/mobile/phone_card_reader.svg" module: UiModule.REMOTE_SERVICE } ListElement { diff --git a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml b/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml index 66ec310..85f434e 100644 --- a/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml +++ b/resources/qml/Governikus/Provider/+desktop/ProviderDetailHistoryItem.qml @@ -28,7 +28,7 @@ GText { id: date font.capitalization: Font.AllUppercase - text: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) + text: Utils.historyDateString(dateTime) textStyle: Style.text.normal } GridLayout { diff --git a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml index 418c62d..3a973ca 100644 --- a/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml +++ b/resources/qml/Governikus/Provider/+mobile/+tablet/ProviderDetailHistoryItem.qml @@ -23,9 +23,7 @@ contentMarginRight: 0 //: LABEL ANDROID IOS footerText: purposeText !== "" ? purposeText : qsTr("Touch for more details") - - //: LABEL ANDROID IOS - headerText: (Utils.isToday(dateTime) ? qsTr("today") : Utils.isYesterday(dateTime) ? qsTr("yesterday") : Utils.isThisWeek(dateTime) ? dateTime.toLocaleString(Qt.locale(SettingsModel.language), "dddd") : dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"))) + headerText: Utils.historyDateString(dateTime) height: 72 //: LABEL ANDROID IOS text: (!!providerName ? providerName : qsTr("Touch for more details")) diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml index 1693ad2..9030c3f 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/DevicesListDelegate.qml @@ -8,15 +8,19 @@ import Governikus.Style 1.0 MouseArea { + id: root + property alias description: descriptionText.text + property bool highlightTitle: false property alias linkInactive: linkQualityItem.inactive property alias linkQuality: linkQualityItem.percent + property alias linkQualityVisible: linkQualityItem.visible property alias title: titleText.text Accessible.name: qsTr("Device %1. %2.").arg(title).arg(description) Accessible.role: Accessible.ListItem - height: content.implicitHeight - width: content.implicitWidth + implicitHeight: content.implicitHeight + implicitWidth: content.implicitWidth Accessible.onPressAction: clicked(null) @@ -35,7 +39,7 @@ Layout.fillWidth: true elide: Text.ElideRight maximumLineCount: 1 - textStyle: Style.text.normal_accent + textStyle: root.highlightTitle ? Style.text.normal_accent_highlight : Style.text.normal_accent } GText { id: descriptionText @@ -44,6 +48,7 @@ elide: Text.ElideRight maximumLineCount: 1 textStyle: Style.text.hint_secondary + visible: text !== "" } } LinkQuality { diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml index 9b43638..a8de0a7 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/LocalNetworkInfo.qml @@ -13,7 +13,7 @@ GText { horizontalAlignment: Text.AlignHCenter //: INFO IOS Let user know to check the application settings for local network permission - text: qsTr("To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.") + text: qsTr("Ensure that access to the local network is allowed in your settings.") textStyle: Style.text.normal_secondary width: parent.width } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml new file mode 100644 index 0000000..a04e8b1 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingCodeInfoView.qml @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import Governikus.Global 1.0 +import Governikus.TitleBar 1.0 +import Governikus.Style 1.0 +import Governikus.View 1.0 +import Governikus.Type.ApplicationModel 1.0 + +SectionPage { + property alias text: description.text + + signal navActionClicked + + hiddenNavbarPadding: true + + //: LABEL ANDROID IOS + title: qsTr("Pairing Information") + + content: ColumnLayout { + anchors.left: parent.left + anchors.margins: Constants.pane_padding + anchors.right: parent.right + spacing: Constants.component_spacing + + Image { + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: Style.dimens.medium_icon_size + Layout.topMargin: Constants.pane_padding + fillMode: Image.PreserveAspectFit + source: "qrc:///images/phone_to_pc.svg" + sourceSize.height: Style.dimens.medium_icon_size + } + GText { + id: description + Layout.alignment: Qt.AlignCenter + Layout.topMargin: Constants.component_spacing + //: LABEL ANDROID IOS + textStyle: Style.text.header_accent + } + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + qsTr("Open %1 on your %2other device%3.").arg(Qt.application.name).arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + qsTr("On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + qsTr("Choose this smartphone in the list to pair it.")] + + RowLayout { + Layout.topMargin: Constants.component_spacing + spacing: Constants.text_spacing + width: parent.width + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + Layout.preferredWidth: Style.dimens.small_icon_size + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + text: modelData + } + } + } + RemoteServiceWifiInfo { + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + } + } + navigationAction: NavigationAction { + id: navAction + action: NavigationAction.Action.Back + + onClicked: navActionClicked() + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml new file mode 100644 index 0000000..ed089d9 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/PairingProcessInfo.qml @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import Governikus.Global 1.0 +import Governikus.Style 1.0 +import Governikus.Type.ApplicationModel 1.0 + +ColumnLayout { + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + qsTr("Open %1 on your smartphone as card reader.").arg(Qt.application.name), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + qsTr("On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + qsTr("Choose the smartphone in the list shown here to pair it.")] + + RowLayout { + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + spacing: Constants.text_spacing + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + Layout.preferredWidth: Style.dimens.small_icon_size + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + text: modelData + } + } + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml index 9c011a0..019c207 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceView.qml @@ -17,7 +17,7 @@ sectionPageFlickable: contentItem //: LABEL ANDROID IOS - title: qsTr("Remote service") + title: qsTr("Card reader") navigationAction: NavigationAction { action: RemoteServiceModel.running ? NavigationAction.Action.Cancel : NavigationAction.Action.None @@ -28,13 +28,9 @@ Connections { function onFireIsRunningChanged() { setLockedAndHidden(RemoteServiceModel.running); - pairingButton.didPairInSaKSession = false; - } - function onFirePairingCompleted() { - pairingButton.didPairInSaKSession = true; - } - //: ERROR ANDROID IOS An error occurred while pairing the device. + } function onFirePairingFailed() { + //: ERROR ANDROID IOS An error occurred while pairing the device. ApplicationModel.showFeedback(qsTr("Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code.")); } @@ -55,43 +51,22 @@ when: RemoteServiceModel.running && RemoteServiceModel.isPairing PropertyChanges { + target: knownDevices + visible: false + } + PropertyChanges { target: pairingCode visible: true } PropertyChanges { - target: wifiInfo + target: paringCodeLink visible: true - } - PropertyChanges { - target: networkPermissionText - visible: RemoteServiceModel.requiresLocalNetworkPermission - } - }, - State { - name: "UNCONNECTED" - when: RemoteServiceModel.running && !RemoteServiceModel.connectedToPairedDevice - - PropertyChanges { - target: pairingCode - visible: false - } - PropertyChanges { - target: wifiInfo - visible: true - } - PropertyChanges { - target: networkPermissionText - visible: RemoteServiceModel.requiresLocalNetworkPermission } }, State { name: "CONNECTED_OR_STOPPED" when: !RemoteServiceModel.running || (RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice) - PropertyChanges { - target: pairingCode - visible: false - } PropertyChanges { target: wifiInfo visible: false @@ -125,26 +100,119 @@ //: LABEL ANDROID IOS RemoteServiceModel.connectedToPairedDevice ? qsTr("Card access in progress") : //: LABEL ANDROID IOS - RemoteServiceModel.isPairing || RemoteServiceModel.running ? qsTr("Waiting for connection") : - //: LABEL ANDROID IOS - qsTr("Remote service ready") + RemoteServiceModel.isPairing ? qsTr("Waiting for pairing") : + //: LABEL ANDROID IOS + RemoteServiceModel.running ? qsTr("Waiting for connection") : "" textStyle: Style.text.header_accent } GText { + id: infoText + readonly property string currentPin: RemoteServiceModel.psk //: INFO ANDROID IOS - readonly property string enterCodeString: qsTr("Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC).") - - Accessible.name: RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) : text + readonly property string enterCodeString: qsTr("Enter the pairing code %1 in the %2 on your other device.") + + Accessible.name: text Layout.fillWidth: true Layout.topMargin: Constants.text_spacing horizontalAlignment: Text.AlignHCenter - text: !RemoteServiceModel.runnable ? RemoteServiceModel.errorMessage : RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice ? RemoteServiceModel.connectionInfo : RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin).arg(Qt.application.name) : //: INFO ANDROID IOS - RemoteServiceModel.running ? qsTr("Waiting for connection from a paired device...") : - //: INFO ANDROID IOS - qsTr("Start the remote access in order to make this smartphone visible and use it as a card reader (SaC).\n\nIf you have not already paired a device, start the pairing now to set up this smartphone as a card reader.") + text: qsTr("You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.\n\nTo do this you first have to pair that device with this smartphone.").arg(Qt.application.name) textStyle: RemoteServiceModel.runnable ? Style.text.normal_secondary : Style.text.normal_warning + + states: [ + State { + when: !RemoteServiceModel.runnable + + PropertyChanges { + target: infoText + text: RemoteServiceModel.errorMessage + } + }, + State { + when: RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice + + PropertyChanges { + target: infoText + text: RemoteServiceModel.connectionInfo + } + }, + State { + when: RemoteServiceModel.isPairing + + PropertyChanges { + Accessible.name: enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) + target: infoText + text: enterCodeString.arg(currentPin).arg(Qt.application.name) + } + }, + State { + when: !RemoteServiceModel.running && knownDeviceList.count > 0 + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.") + } + }, + State { + when: RemoteServiceModel.running && knownDeviceList.count > 0 + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Paired devices may use this Smartphone as a card reader now.") + } + }, + State { + when: RemoteServiceModel.running + + PropertyChanges { + target: infoText + //: INFO ANDROID IOS + text: qsTr("Waiting for connection from a paired device...") + } + } + ] + } + ColumnLayout { + id: knownDevices + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + Layout.topMargin: Constants.pane_padding + spacing: Constants.text_spacing + visible: RemoteServiceModel.runnable && knownDeviceList.count > 0 + + GText { + //: INFO ANDROID IOS + text: qsTr("Paired Devices") + textStyle: Style.text.header + } + Repeater { + id: knownDeviceList + model: RemoteServiceModel.allDevices + + delegate: DevicesListDelegate { + highlightTitle: isLastAddedDevice + linkQualityVisible: false + title: remoteDeviceName + } + } + GButton { + //: LABEL ANDROID IOS + Accessible.name: qsTr("Start pairing of a new device") + Layout.alignment: Qt.AlignLeft + Layout.topMargin: knownDevices.spacing + buttonColor: Style.color.transparent + icon.source: "qrc:///images/material_add.svg" + padding: 0 + //: LABEL ANDROID IOS + text: qsTr("Pair new device") + textStyle: Style.text.normal_accent_highlight + visible: !RemoteServiceModel.isPairing && !RemoteServiceModel.running + + onClicked: RemoteServiceModel.setRunning(!RemoteServiceModel.running, !RemoteServiceModel.isPairing) + } } GText { id: pairingCode @@ -161,82 +229,121 @@ textStyle: Style.text.title_accent visible: false } + MoreInformationLink { + id: paringCodeLink + Layout.alignment: Qt.AlignCenter + Layout.topMargin: Constants.component_spacing + //: LABEL ANDROID IOS + text: qsTr("Where do I enter the pairing code?") + visible: false + + onClicked: push(pairingCodeInfoView) + + Component { + id: pairingCodeInfoView + PairingCodeInfoView { + text: paringCodeLink.text + + onNavActionClicked: pop() + } + } + } GSpacer { Layout.fillHeight: true } - RowLayout { + RemoteServiceWifiInfo { id: wifiInfo Layout.fillWidth: true Layout.topMargin: Constants.component_spacing - spacing: Constants.text_spacing - - TintableIcon { - source: "qrc:/images/info.svg" - sourceSize.width: Style.dimens.small_icon_size - tintColor: Style.text.normal_secondary.textColor - } - GText { - Layout.fillWidth: true - - //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - text: qsTr("Both of your devices have to be connected to the same WiFi.") - textStyle: Style.text.normal_secondary - } } LocalNetworkInfo { id: networkPermissionText Layout.bottomMargin: Constants.text_spacing Layout.fillWidth: true Layout.topMargin: Constants.component_spacing - visible: false + visible: RemoteServiceModel.requiresLocalNetworkPermission + } + GProgressBar { + id: progressBar + Layout.fillWidth: true + Layout.topMargin: Constants.component_spacing + value: RemoteServiceModel.percentage + visible: progressText.visible + } + GText { + id: progressText + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Constants.text_spacing + text: RemoteServiceModel.displayText + textStyle: Style.text.normal_secondary + visible: text !== "" } GButton { - id: startButton - - readonly property int minButtonWidth: Math.max(Math.max(pairingButton.implicitWidth, startButton.implicitWidth), parent.width / 2) - + id: pairConnectButton Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: startButton.minButtonWidth - Layout.topMargin: Constants.component_spacing - buttonColor: (!ApplicationModel.wifiEnabled || RemoteServiceModel.canEnableNfc) ? Style.color.button : (RemoteServiceModel.running ? Constants.red : Constants.green) - enabled: (RemoteServiceModel.canEnableNfc || RemoteServiceModel.runnable || RemoteServiceModel.running || !ApplicationModel.wifiEnabled) && !RemoteServiceModel.isStarting - //: LABEL ANDROID IOS - text: !ApplicationModel.wifiEnabled ? qsTr("Enable WiFi") : - //: LABEL ANDROID IOS - RemoteServiceModel.canEnableNfc ? qsTr("Enable NFC") : - //: LABEL ANDROID IOS - RemoteServiceModel.running ? qsTr("Stop remote service") : - //: LABEL ANDROID IOS - qsTr("Start remote service") - - onClicked: { - if (!ApplicationModel.wifiEnabled) { - ApplicationModel.enableWifi(); - } else if (RemoteServiceModel.canEnableNfc) { - ApplicationModel.showSettings(ApplicationModel.SETTING_NFC); - } else { - RemoteServiceModel.setRunning(!RemoteServiceModel.running); - } - } - } - GButton { - id: pairingButton - - property bool didPairInSaKSession: false - - Layout.alignment: Qt.AlignHCenter - Layout.minimumWidth: startButton.minButtonWidth - Layout.topMargin: Constants.component_spacing - enabled: RemoteServiceModel.runnable && !RemoteServiceModel.connectedToPairedDevice && !RemoteServiceModel.isStarting && !didPairInSaKSession - - // Set opacity instead of visibility to hide button so it keeps its size - opacity: RemoteServiceModel.connectedToPairedDevice || didPairInSaKSession ? 0 : 1 - text: RemoteServiceModel.isPairing ? - //: LABEL ANDROID IOS - qsTr("Stop pairing") : - //: LABEL ANDROID IOS - qsTr("Start pairing") - visible: RemoteServiceModel.runnable + Layout.topMargin: Constants.component_spacing + enabled: !RemoteServiceModel.isStarting + visible: text !== "" + + states: [ + State { + when: !ApplicationModel.wifiEnabled + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable WiFi") + + onClicked: ApplicationModel.enableWifi() + } + }, + State { + when: RemoteServiceModel.canEnableNfc + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Enable NFC") + + onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_NFC) + } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count > 0 && !RemoteServiceModel.isPairing && !RemoteServiceModel.running + + PropertyChanges { + buttonColor: Constants.green + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Allow connection") + + onClicked: RemoteServiceModel.setRunning(true) + } + }, + State { + when: RemoteServiceModel.runnable && knownDeviceList.count < 1 && !RemoteServiceModel.isPairing + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Pair device") + + onClicked: RemoteServiceModel.setRunning(true, true) + } + }, + State { + when: RemoteServiceModel.isPairing + + PropertyChanges { + target: pairConnectButton + //: LABEL ANDROID IOS + text: qsTr("Cancel pairing") + visible: true + + onClicked: RemoteServiceModel.setRunning(false, false) + } + } + ] onClicked: RemoteServiceModel.setRunning(true, !RemoteServiceModel.isPairing) } diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml index a26871a..022420d 100644 --- a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceViewRemote.qml @@ -33,6 +33,7 @@ Column { spacing: Constants.component_spacing + visible: availablePairedDeviceList.count > 0 width: parent.usableWidth TitledSeparator { @@ -43,23 +44,49 @@ title: qsTr("Paired devices") width: parent.width } - GText { - Accessible.name: text - Accessible.role: Accessible.StaticText - - //: LABEL ANDROID IOS - text: qsTr("No device is paired.") - textStyle: Style.text.normal_secondary - visible: !knownDeviceList.visible - width: parent.width - } ListView { - id: knownDeviceList + id: availablePairedDeviceList height: childrenRect.height interactive: false - model: RemoteServiceModel.knownDevices + model: RemoteServiceModel.availablePairedDevices spacing: Constants.component_spacing - visible: count > 0 + width: parent.width + + delegate: DevicesListDelegate { + //: LABEL ANDROID IOS + description: qsTr("Available") + linkInactive: !isNetworkVisible + linkQuality: linkQualityInPercent + title: remoteDeviceName + width: availablePairedDeviceList.width + + onClicked: { + deleteDevicePopup.deviceId = deviceId; + deleteDevicePopup.deviceName = remoteDeviceName; + deleteDevicePopup.open(); + } + } + } + } + Column { + spacing: Constants.component_spacing + visible: unavailablePairedDeviceList.count > 0 + width: parent.usableWidth + + TitledSeparator { + contentMarginBottom: 0 + contentMarginLeft: 0 + contentMarginRight: 0 + //: LABEL ANDROID IOS + title: qsTr("Last connected") + width: parent.width + } + ListView { + id: unavailablePairedDeviceList + height: childrenRect.height + interactive: false + model: RemoteServiceModel.unavailablePairedDevices + spacing: Constants.component_spacing width: parent.width delegate: DevicesListDelegate { @@ -68,7 +95,7 @@ linkInactive: !isNetworkVisible linkQuality: linkQualityInPercent title: remoteDeviceName - width: knownDeviceList.width + width: unavailablePairedDeviceList.width onClicked: { deleteDevicePopup.deviceId = deviceId; @@ -102,40 +129,14 @@ contentMarginBottom: 0 contentMarginLeft: 0 contentMarginRight: 0 - - //: LABEL ANDROID IOS - title: qsTr("Available devices") - width: parent.width - } - GText { - text: ApplicationModel.wifiEnabled ? - //: INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - qsTr("No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi.") : - //: INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. - qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).") - textStyle: ApplicationModel.wifiEnabled ? Style.text.normal_secondary : Style.text.normal_warning - visible: !searchDeviceList.visible - width: parent.width - } - GButton { - anchors.horizontalCenter: parent.horizontalCenter - - //: LABEL ANDROID IOS - text: qsTr("Enable WiFi") - visible: !ApplicationModel.wifiEnabled - - onClicked: ApplicationModel.enableWifi() - } - LocalNetworkInfo { - topPadding: Constants.component_spacing - visible: RemoteServiceModel.requiresLocalNetworkPermission && !RemoteServiceModel.remoteReaderVisible - width: parent.width - } - ListView { + //: LABEL ANDROID IOS + title: qsTr("Add pairing") + width: parent.width + } + GListView { id: searchDeviceList height: childrenRect.height - interactive: false - model: RemoteServiceModel.availableRemoteDevices + model: RemoteServiceModel.availableDevicesInPairingMode spacing: Constants.component_spacing visible: ApplicationModel.wifiEnabled && count > 0 width: parent.width @@ -149,25 +150,42 @@ onClicked: { if (isSupported && RemoteServiceModel.rememberServer(deviceId)) { - informationPairingPopup.open(); + d.oldLockedAndHiddenStatus = getLockedAndHidden(); + setLockedAndHidden(); + push(enterPinView); } } } } - } - } - ConfirmationPopup { - id: informationPairingPopup - style: ConfirmationPopup.PopupStyle.OkButton - //: INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - text: qsTr("Start the pairing mode on your smartphone if you haven't done it already.") - //: INFO ANDROID IOS - title: qsTr("Pairing mode") - - onConfirmed: { - d.oldLockedAndHiddenStatus = getLockedAndHidden(); - setLockedAndHidden(); - push(enterPinView); + GText { + //: INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. + text: qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).") + textStyle: Style.text.normal_warning + visible: !ApplicationModel.wifiEnabled + width: parent.width + } + GButton { + anchors.horizontalCenter: parent.horizontalCenter + + //: LABEL ANDROID IOS + text: qsTr("Enable WiFi") + visible: !ApplicationModel.wifiEnabled + + onClicked: ApplicationModel.enableWifi() + } + LocalNetworkInfo { + topPadding: Constants.component_spacing + visible: RemoteServiceModel.requiresLocalNetworkPermission && !RemoteServiceModel.remoteReaderVisible + width: parent.width + } + PairingProcessInfo { + visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled + width: parent.width + } + RemoteServiceWifiInfo { + visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled + width: parent.width + } } } PasswordInfoData { diff --git a/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml new file mode 100644 index 0000000..ab03cc2 --- /dev/null +++ b/resources/qml/Governikus/RemoteServiceView/+mobile/RemoteServiceWifiInfo.qml @@ -0,0 +1,21 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +RowLayout { + spacing: Constants.text_spacing + + TintableIcon { + source: "qrc:/images/info.svg" + sourceSize.width: Style.dimens.small_icon_size + tintColor: Style.text.normal_secondary.textColor + } + GText { + Layout.fillWidth: true + + //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + text: qsTr("Both devices have to be connected to the same WiFi.") + textStyle: Style.text.normal_secondary + } +} diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml index 60dedbc..d3abf49 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceController.qml @@ -3,17 +3,33 @@ */ import QtQuick 2.15 import QtQuick.Controls 2.15 +import Governikus.AuthView 1.0 import Governikus.EnterPasswordView 1.0 import Governikus.PasswordInfoView 1.0 +import Governikus.Style 1.0 import Governikus.TitleBar 1.0 import Governikus.View 1.0 +import Governikus.Workflow 1.0 +import Governikus.Type.ChatModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PasswordType 1.0 import Governikus.Type.ReaderPlugIn 1.0 import Governikus.Type.RemoteServiceModel 1.0 +import Governikus.Type.SettingsModel 1.0 Controller { id: controller + + readonly property bool enterPasswordShown: stackView.currentItem instanceof EnterPasswordView + readonly property bool workflowShown: stackView.currentItem instanceof GeneralWorkflow + + function requestCard() { + if (RemoteServiceModel.hasCard && workflowShown) { + pop(); + } else if (!RemoteServiceModel.hasCard && !workflowShown) { + push(generalWorkflow); + } + } function requestInput(pState) { if (RemoteServiceModel.isBasicReader && RemoteServiceModel.pinPadModeOn()) { push(enterPinView); @@ -23,6 +39,14 @@ } Connections { + function onFireConnectedChanged() { + if (RemoteServiceModel.connectedToPairedDevice && !workflowShown) { + RemoteServiceModel.setInitialPluginType(); + requestCard(); + } else if (!RemoteServiceModel.connectedToPairedDevice && workflowShown) { + pop(); + } + } function onFireCurrentStateChanged() { switch (RemoteServiceModel.currentState) { case "Initial": @@ -32,7 +56,16 @@ RemoteServiceModel.continueWorkflow(); break; case "StateEnterPacePasswordIfd": - requestInput(); + if (SettingsModel.showAccessRights) { + push(editRights); + } else { + requestInput(); + } + break; + case "StateEstablishPaceChannelIfd": + case "StateChangePinIfd": + requestCard(); + RemoteServiceModel.continueWorkflow(); break; case "StateEnterNewPacePinIfd": requestInput(); @@ -45,8 +78,59 @@ RemoteServiceModel.continueWorkflow(); } } + function onFireHasCardChanged() { + if (!RemoteServiceModel.connectedToPairedDevice) { + return; + } + if (enterPasswordShown) { + return; + } + requestCard(); + } target: RemoteServiceModel + } + Component { + id: editRights + EditRights { + //: LABEL ANDROID IOS + actionText: qsTr("You are about to identify yourself towards the following provider using the device \"%1\":").arg(RemoteServiceModel.connectedClientName) + //: LABEL ANDROID IOS + title: qsTr("Card reader") + workflowModel: RemoteServiceModel + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + pop(); + RemoteServiceModel.cancelPasswordRequest(); + } + } + + onRightsAccepted: { + ChatModel.transferAccessRights(); + pop(); + requestInput(); + } + } + } + Component { + id: generalWorkflow + GeneralWorkflow { + titleBarColor: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART ? Style.color.accent_smart : Style.color.accent + workflowModel: RemoteServiceModel + //: LABEL ANDROID IOS + workflowTitle: qsTr("Remote service") + + navigationAction: NavigationAction { + action: NavigationAction.Action.Cancel + + onClicked: { + RemoteServiceModel.setRunning(false); + } + } + } } PasswordInfoData { id: infoData @@ -70,6 +154,8 @@ id: passwordView enableTransportPinLink: RemoteServiceModel.enableTransportPinLink moreInformationText: infoData.linkText + //: LABEL ANDROID IOS + title: qsTr("Card reader") navigationAction: NavigationAction { action: NavigationAction.Action.Cancel @@ -85,6 +171,7 @@ } onPasswordEntered: { pop(); + RemoteServiceModel.startScanExplicitly(); RemoteServiceModel.continueWorkflow(); } onRequestPasswordInfo: push(passwordInfoView) diff --git a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml index a419e9d..e801577 100644 --- a/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml +++ b/resources/qml/Governikus/RemoteServiceView/RemoteServiceSettings.qml @@ -11,7 +11,7 @@ SectionPage { id: rootPage //: LABEL ANDROID IOS - title: qsTr("Configure remote service") + title: qsTr("Manage pairings") content: RemoteServiceViewRemote { width: rootPage.width diff --git a/resources/qml/Governikus/RemoteServiceView/qmldir b/resources/qml/Governikus/RemoteServiceView/qmldir index a4aefd1..a17751a 100644 --- a/resources/qml/Governikus/RemoteServiceView/qmldir +++ b/resources/qml/Governikus/RemoteServiceView/qmldir @@ -1,8 +1,11 @@ module RemoteServiceView internal DevicesListDelegate DevicesListDelegate.qml +internal PairingCodeInfoView PairingCodeInfoView.qml +internal PairingProcessInfo PairingProcessInfo.qml internal RemoteServiceController RemoteServiceController.qml internal RemoteServiceViewRemote RemoteServiceViewRemote.qml +internal RemoteServiceWifiInfo RemoteServiceWifiInfo.qml LinkQuality 1.0 LinkQuality.qml LocalNetworkInfo 1.0 LocalNetworkInfo.qml diff --git a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml index b724585..7447e9d 100644 --- a/resources/qml/Governikus/ResultView/+desktop/ResultView.qml +++ b/resources/qml/Governikus/ResultView/+desktop/ResultView.qml @@ -25,10 +25,10 @@ property alias header: resultHeader.text property alias hintButtonText: hintItem.buttonText property alias hintText: hintItem.text + property alias mailButtonVisible: mailButton.visible property alias popupText: detailedResultPopup.text property alias popupTitle: detailedResultPopup.title property int resultType: ResultView.Type.IsSuccess - property alias supportButtonsVisible: supportButtonsLayout.visible property alias text: resultText.text signal emailButtonPressed @@ -88,17 +88,18 @@ } } RowLayout { - id: supportButtonsLayout Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true spacing: Constants.component_spacing - visible: false + visible: popupTitle !== "" || popupText !== "" GButton { + id: mailButton icon.source: "qrc:///images/material_mail.svg" //: LABEL DESKTOP text: qsTr("Send email") tintIcon: true + visible: false onClicked: baseItem.emailButtonPressed() } @@ -127,7 +128,7 @@ } } GButton { - icon.source: "qrc:/images/info.svg" + icon.source: "qrc:/images/desktop/info_white.svg" //: LABEL DESKTOP text: qsTr("See details") tintIcon: true diff --git a/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml b/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml index 0da8356..779e0a1 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/ConnectSacView.qml @@ -110,8 +110,7 @@ pairingFailedView.errorMessage = pErrorMessage; d.view = ConnectSacView.SubView.PairingFailed; } - function onFirePairingSuccess(pDeviceName) { - ApplicationModel.showFeedback(qsTr("The device \"%1\" has been paired.").arg(pDeviceName)); + function onFirePairingSuccess() { root.closeView(); } diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml index 63647b2..3b092bb 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderDelegate.qml @@ -50,12 +50,7 @@ } GText { id: subtext - text: { - if (!isPaired) { - return qsTr("Click to pair"); - } - return remoteDeviceStatus; - } + text: remoteDeviceStatus textStyle: Style.text.normal width: parent.width } @@ -75,7 +70,7 @@ source: "qrc:///images/material_delete.svg" sourceSize.height: iconHeight tintColor: Style.color.accent - visible: isPaired + visible: isPaired && !isPairing MouseArea { id: trashMouse @@ -99,7 +94,7 @@ MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - visible: !isPaired + visible: !trashMouse.visible onClicked: pairDevice(deviceId) } diff --git a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml index 57a6726..397f243 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/RemoteReaderView.qml @@ -6,6 +6,7 @@ import Governikus.Global 1.0 import Governikus.Style 1.0 import Governikus.TitleBar 1.0 +import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.RemoteServiceModel 1.0 import Governikus.Type.ReaderScanEnabler 1.0 @@ -17,7 +18,6 @@ readonly property string helpTopic: "settingsRemoteReader" - signal moreInformation signal pairDevice(string pDeviceId) signal unpairDevice(string pDeviceId) @@ -32,25 +32,50 @@ anchors.fill: parent spacing: Constants.component_spacing - GText { - activeFocusOnTab: true - text: qsTr("Paired remote devices") - textStyle: Style.text.header_accent - visible: knownDevices.count > 0 + Column { + spacing: Constants.component_spacing + visible: availablePairedDevices.count > 0 width: parent.width - FocusFrame { + GText { + activeFocusOnTab: true + text: qsTr("Paired devices") + textStyle: Style.text.header_accent + width: parent.width + + FocusFrame { + } + } + Repeater { + id: availablePairedDevices + model: RemoteServiceModel.availablePairedDevices + + delegate: RemoteReaderDelegate { + width: parent.width + + onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) + } } } Column { + spacing: Constants.component_spacing + visible: unavailablePairedDevices.count > 0 width: parent.width + GText { + activeFocusOnTab: true + text: qsTr("Last connected") + textStyle: Style.text.header_accent + width: parent.width + + FocusFrame { + } + } Repeater { - id: knownDevices - model: RemoteServiceModel.knownDevices + id: unavailablePairedDevices + model: RemoteServiceModel.unavailablePairedDevices delegate: RemoteReaderDelegate { - height: implicitHeight + Constants.pane_padding width: parent.width onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId) @@ -58,12 +83,12 @@ } } GSeparator { - visible: knownDevices.count > 0 + visible: availablePairedDevices.count > 0 || unavailablePairedDevices.count > 0 width: parent.width } GText { activeFocusOnTab: true - text: qsTr("Available remote devices") + text: qsTr("Add pairing") textStyle: Style.text.header_accent width: parent.width @@ -73,7 +98,7 @@ GListView { id: availableDevices height: contentHeight - model: RemoteServiceModel.availableRemoteDevices + model: RemoteServiceModel.availableDevicesInPairingMode width: parent.width delegate: RemoteReaderDelegate { @@ -83,22 +108,47 @@ onPairDevice: pDeviceId => root.pairDevice(pDeviceId) } } - GText { - activeFocusOnTab: true - text: RemoteServiceModel.availableRemoteDevices.emptyListDescriptionString - textStyle: Style.text.normal + Column { + spacing: Constants.text_spacing visible: availableDevices.count === 0 width: parent.width - FocusFrame { + Repeater { + model: [ + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + qsTr("Open the %1 on your Smartphone as card reader.").arg(Qt.application.name), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + qsTr("On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.").arg("").arg(""), + //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + qsTr("Choose the device in the list to pair it.")] + + RowLayout { + spacing: Constants.component_spacing + width: parent.width + + GText { + Accessible.ignored: true + Layout.alignment: Qt.AlignTop + text: (index + 1) + "." + } + GText { + Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData) + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + activeFocusOnTab: true + text: modelData + + FocusFrame { + } + } + } } } - GSeparator { - width: parent.width - } RowLayout { - id: hint spacing: Constants.text_spacing + visible: availableDevices.count === 0 width: parent.width TintableIcon { @@ -107,11 +157,10 @@ tintColor: Style.color.accent } GText { - id: hintText Layout.alignment: Qt.AlignVCenter Layout.fillWidth: true activeFocusOnTab: true - text: qsTr("Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here.") + text: qsTr("Both devices have to be connected to the same WiFi.") textStyle: Style.text.hint verticalAlignment: Text.AlignBottom wrapMode: Text.WordWrap @@ -120,11 +169,5 @@ } } } - GButton { - //: LABEL DESKTOP - text: qsTr("More information") - - onClicked: moreInformation() - } } } diff --git a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml index 75517f7..229ef74 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SecurityAndPrivacySettings.qml @@ -83,6 +83,7 @@ } GSeparator { Layout.fillWidth: true + visible: SettingsModel.autoUpdateAvailable } GText { activeFocusOnTab: true @@ -90,16 +91,18 @@ //: LABEL DESKTOP text: qsTr("Software updates") textStyle: Style.text.header_accent + visible: SettingsModel.autoUpdateAvailable FocusFrame { } } GCheckBox { checked: SettingsModel.autoUpdateCheck - enabled: !SettingsModel.autoUpdateCheckSetByAdmin && SettingsModel.autoUpdateAvailable + enabled: !SettingsModel.autoUpdateCheckSetByAdmin //: LABEL DESKTOP text: qsTr("Check at program start") + visible: SettingsModel.autoUpdateAvailable onCheckedChanged: SettingsModel.autoUpdateCheck = checked } @@ -109,9 +112,9 @@ Layout.fillWidth: true spacing: Constants.component_spacing + visible: SettingsModel.autoUpdateAvailable GButton { - enabled: SettingsModel.autoUpdateAvailable text: (parent.updateAvailable ? //: LABEL DESKTOP qsTr("Show update") : diff --git a/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml b/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml index bd7238a..0a8b607 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/SettingsView.qml @@ -97,12 +97,6 @@ height: Math.max(implicitHeight, tabbedPane.availableHeight) width: parent.width - onMoreInformation: { - d.precedingView = d.view; - d.view = TabbedReaderView.SubView.ConnectSacView; - connectSacView.showPairingInformation(); - updateTitleBarActions(); - } onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = SettingsView.SubView.ConnectSacView; diff --git a/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml b/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml index 3f7c6d4..e91d03c 100644 --- a/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml +++ b/resources/qml/Governikus/SettingsView/+desktop/TabbedReaderView.qml @@ -66,12 +66,6 @@ height: Math.max(implicitHeight, tabbedPane.availableHeight) width: parent.width - onMoreInformation: { - d.precedingView = d.view; - d.view = TabbedReaderView.SubView.ConnectSacView; - connectSacView.showPairingInformation(); - updateTitleBarActions(); - } onPairDevice: pDeviceId => { if (RemoteServiceModel.rememberServer(pDeviceId)) { d.view = TabbedReaderView.SubView.ConnectSacView; diff --git a/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml b/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml index 33a3754..e72033d 100644 --- a/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml +++ b/resources/qml/Governikus/SettingsView/+mobile/SettingsView.qml @@ -136,12 +136,24 @@ onCheckedChanged: SettingsModel.pinPadMode = checked } + LabeledSwitch { + checked: SettingsModel.showAccessRights + //: LABEL ANDROID IOS + description: qsTr("Show requested rights on this device as well") + enabled: SettingsModel.pinPadMode + + //: LABEL ANDROID IOS + title: qsTr("Show access rights") + width: parent.width + + onCheckedChanged: SettingsModel.showAccessRights = checked + } MenuItem { //: LABEL ANDROID IOS - description: qsTr("Configure remote service for another device") - - //: LABEL ANDROID IOS - title: qsTr("Remote card reader") + description: qsTr("Manage paired devices and add new devices") + + //: LABEL ANDROID IOS + title: qsTr("Manage pairings") width: parent.width onClicked: push(remoteServiceSettings) @@ -396,9 +408,4 @@ } } } - navigationAction: NavigationAction { - action: topLevelPage ? NavigationAction.Action.None : NavigationAction.Action.Back - - onClicked: pop() - } } diff --git a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml index 82713d6..4948272 100644 --- a/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml +++ b/resources/qml/Governikus/SmartView/+mobile/PersonalizationController.qml @@ -12,6 +12,7 @@ import Governikus.WhiteListClient 1.0 import Governikus.Workflow 1.0 import Governikus.Type.ConnectivityManager 1.0 +import Governikus.Type.ChatModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PasswordType 1.0 import Governikus.Type.PersonalizationModel 1.0 @@ -269,6 +270,11 @@ title: qsTr("Set up Smart-eID") titleBarColor: Style.color.accent_smart workflowModel: PersonalizationModel + + onRightsAccepted: { + ChatModel.transferAccessRights(); + PersonalizationModel.continueWorkflow(); + } } } Component { diff --git a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml index 4435138..3b7d6b8 100644 --- a/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml +++ b/resources/qml/Governikus/Style/+mobile/PlatformDimensions.qml @@ -4,11 +4,12 @@ import QtQml 2.15 import Governikus.Global 1.0 import Governikus.Type.SettingsModel 1.0 +import QtQuick.Window 2.15 BrandDimensions { readonly property int button_radius: 6 readonly property int corner_radius: 10 - readonly property int header_icon_size: Constants.is_tablet ? 240 : huge_icon_size + readonly property int header_icon_size: Constants.is_tablet ? Math.min(Screen.height / 5, 240) : huge_icon_size readonly property int high_contrast_item_border: 0 readonly property int huge_icon_size: 160 readonly property int icon_size: 48 @@ -33,4 +34,5 @@ readonly property int tutorial_component_spacing: 40 readonly property int tutorial_header_font_size: 26 readonly property int tutorial_title_font_size: 60 + readonly property int workflow_progress_indicator_size: 1.5 * header_icon_size } diff --git a/resources/qml/Governikus/Style/TextStyles.qml b/resources/qml/Governikus/Style/TextStyles.qml index 8c1cc96..e697fce 100644 --- a/resources/qml/Governikus/Style/TextStyles.qml +++ b/resources/qml/Governikus/Style/TextStyles.qml @@ -100,6 +100,10 @@ readonly property var normal_accent: TextStyle { textColor: Style.color.accent_text } + readonly property var normal_accent_highlight: TextStyle { + bold: true + textColor: Style.color.accent_text + } readonly property var normal_highlight: TextStyle { bold: true } diff --git a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml index 414e0c7..bda4494 100644 --- a/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml +++ b/resources/qml/Governikus/TechnologyInfo/+mobile/TechnologyInfo.qml @@ -24,6 +24,7 @@ GFlickableColumnLayout { anchors.fill: parent spacing: 0 + topMargin: 0 GText { id: title diff --git a/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml b/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml index 61e22e6..bd5e403 100644 --- a/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml +++ b/resources/qml/Governikus/TitleBar/+desktop/TitleBar.qml @@ -163,7 +163,7 @@ id: settingsButton Accessible.description: qsTr("Open settings view of %1").arg(Qt.application.name) height: rightTitleBarActions.height - source: "qrc:///images/material_settings.svg" + source: "qrc:///images/desktop/material_settings_white.svg" text: qsTr("Settings") visible: rightMostAction.showSettings @@ -173,7 +173,7 @@ id: helpButton Accessible.description: qsTr("Open online help of %1 in browser").arg(Qt.application.name) height: rightTitleBarActions.height - source: "qrc:///images/desktop/material_menu_book.svg" + source: "qrc:///images/desktop/material_menu_book_white.svg" text: qsTr("Open online help in browser") visible: rightMostAction.showHelp diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml index 3b65a14..3012cf4 100644 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml +++ b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacDesktop.qml @@ -201,7 +201,7 @@ horizontalAlignment: Text.AlignHCenter //: LABEL ANDROID IOS - text: qsTr("Now choose \"Remote\" in the AusweisApp2 on your smartphone...") + text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...") textStyle: Style.text.tutorial_header width: parent.width * 0.9 @@ -240,7 +240,7 @@ animationsDisabled: true //: LABEL ANDROID IOS - text: qsTr("Start pairing") + text: qsTr("Pair device") Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() diff --git a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml index 34e5f04..2b7c1a5 100644 --- a/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml +++ b/resources/qml/Governikus/TutorialView/+mobile/TutorialReaderMethodSacMobile.qml @@ -194,7 +194,7 @@ horizontalAlignment: Text.AlignHCenter //: LABEL ANDROID IOS - text: qsTr("Now choose \"Remote\" in the AusweisApp2 on your smartphone...") + text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...") textStyle: Style.text.tutorial_header width: parent.width * 0.9 @@ -233,7 +233,7 @@ animationsDisabled: true //: LABEL ANDROID IOS - text: qsTr("Start pairing") + text: qsTr("Pair device") Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction() Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction() @@ -343,7 +343,7 @@ horizontalAlignment: Text.AlignHCenter text: (Constants.is_layout_ios ? //: LABEL IOS - qsTr("Now open the AusweisApp2 on your device without NFC and select Configure remote service.") : + qsTr("Now open the AusweisApp2 on your device without NFC and select Manage pairings.") : //: LABEL ANDROID qsTr("Now open the AusweisApp2 on your device without NFC and select Smartphone as card reader.")) textStyle: Style.text.tutorial_header diff --git a/resources/qml/Governikus/View/+mobile/SectionPage.qml b/resources/qml/Governikus/View/+mobile/SectionPage.qml index ff8b435..3d558d3 100644 --- a/resources/qml/Governikus/View/+mobile/SectionPage.qml +++ b/resources/qml/Governikus/View/+mobile/SectionPage.qml @@ -25,7 +25,6 @@ property color titleBarColor: Style.color.accent property real titleBarOpacity: 1 property bool titleBarVisible: true - readonly property bool topLevelPage: StackView.index === 0 signal reset diff --git a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml index cb1d6ee..583982c 100644 --- a/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+desktop/GeneralWorkflow.qml @@ -19,6 +19,7 @@ property bool isPinChange: false property int waitingFor: 0 + signal deviceUnpaired(var pDeviceName) signal settingsRequested onWaitingForChanged: if (visible) @@ -33,8 +34,7 @@ } Connections { function onFireCertificateRemoved(pDeviceName) { - //: INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - ApplicationModel.showFeedback(qsTr("The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(pDeviceName)); + deviceUnpaired(pDeviceName); } target: RemoteServiceModel diff --git a/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml deleted file mode 100644 index b035a4e..0000000 --- a/resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import Governikus.Global 1.0 - -Item { - property string image - property alias running: busyIndicator.running - - GBusyIndicator { - id: busyIndicator - anchors.centerIn: parent - factor: 1.2 - height: img.height - running: false - width: height - } - Image { - id: img - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - smooth: true - source: image - width: parent.width - } -} diff --git a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml index f08536b..884b0c2 100644 --- a/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/GeneralWorkflow.qml @@ -6,6 +6,7 @@ import Governikus.TechnologyInfo 1.0 import Governikus.TitleBar 1.0 import Governikus.Workflow 1.0 +import Governikus.ResultView 1.0 import Governikus.View 1.0 import Governikus.Type.ReaderPlugIn 1.0 @@ -23,54 +24,60 @@ onClicked: workflowModel.cancelWorkflow() } - NfcWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC - - onStartScanIfNecessary: workflowModel.startScanIfNecessary() - + Item { anchors { - bottom: technologySwitch.top + bottom: technologySwitch.visible ? technologySwitch.top : parent.bottom left: parent.left right: parent.right top: parent.top } - } - SmartWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART - workflowModel: baseItem.workflowModel + NfcWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + onStartScanIfNecessary: workflowModel.startScanExplicitly() } - } - RemoteWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC + SmartWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART + workflowModel: baseItem.workflowModel + } + RemoteWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + onDeviceUnpaired: function (pDeviceName) { + push(deviceUnpairedView, { + "deviceName": pDeviceName + }); + } + + Component { + id: deviceUnpairedView + ResultView { + property string deviceName + + resultType: ResultView.Type.IsError + //: INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + text: qsTr("The device \"%1\" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(deviceName) + title: workflowTitle + + onCancelClicked: pop() + onContinueClicked: pop() + } + } } - } - SimulatorWorkflow { - visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR - workflowModel: baseItem.workflowModel - - anchors { - bottom: technologySwitch.top - left: parent.left - right: parent.right - top: parent.top + SimulatorWorkflow { + anchors.fill: parent + visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR + workflowModel: baseItem.workflowModel } } TechnologySwitch { id: technologySwitch selectedTechnology: workflowModel.readerPlugInType supportedTechnologies: workflowModel.supportedPlugInTypes + visible: workflowModel.supportedPlugInTypes.length > 1 onRequestPluginType: pReaderPlugInType => workflowModel.readerPlugInType = pReaderPlugInType diff --git a/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml index 85b4bb1..602e6d0 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcProgressIndicator.qml @@ -13,6 +13,8 @@ property real animateOutDuration: 0.2 * cardPositionModel.cyclingClock property var cardPosition: null property bool startPositionLeft: true + + height: Style.dimens.workflow_progress_indicator_size states: [ State { @@ -156,9 +158,9 @@ anchors.centerIn: parent clip: true desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 opacity: tintEnabled ? 0.7 : 1.0 source: "qrc:///images/mobile/phone_nfc.svg" + sourceSize.height: Style.dimens.header_icon_size z: 0 Image { diff --git a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml index bd34b79..bf22c67 100644 --- a/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/NfcWorkflow.qml @@ -8,10 +8,12 @@ import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.ReaderPlugIn 1.0 import Governikus.Type.NumberModel 1.0 +import Governikus.Type.RemoteServiceModel 1.0 Item { id: baseItem + readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE readonly property int nfcState: visible ? ApplicationModel.nfcState : ApplicationModel.NFC_UNAVAILABLE signal startScanIfNecessary @@ -22,7 +24,6 @@ anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - height: baseItem.height / 2 state: nfcState === ApplicationModel.NFC_READY ? "on" : "off" } TechnologyInfo { @@ -52,9 +53,9 @@ //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. qsTr("Please enable NFC in your system settings."); case ApplicationModel.NFC_INACTIVE: - //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + //: INFO ANDROID IOS NFC is available and enabled but needs to be started. return qsTr("NFC scan is not running.") + "
" + - //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + //: INFO ANDROID IOS NFC is available and enabled but needs to be started. qsTr("Please start the NFC scan."); default: return ""; @@ -76,6 +77,10 @@ } } titleText: { + if (isRemoteWorkflow && RemoteServiceModel.connectedClientName !== "") { + //: INFO ANDROID IOS %1 will be replaced with the name of the device. + return qsTr("The device \"%1\" wants to use this smartphone as card reader and connect to your id card.").arg(RemoteServiceModel.connectedClientName); + } switch (nfcState) { case ApplicationModel.NFC_UNAVAILABLE: //: INFO ANDROID IOS diff --git a/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml deleted file mode 100644 index 97314e0..0000000 --- a/resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany - */ -import QtQuick 2.15 -import Governikus.Global 1.0 - -Item { - id: baseItem - - property alias imageIconSource: busyIcon.image - property alias imagePhoneSource: phone.source - - TintableIcon { - id: phone - anchors.centerIn: parent - desaturate: true - height: parent.height * 0.5 - opacity: tintEnabled ? 0.7 : 1.0 - visible: baseItem.state === "off" - width: height - } - Item { - id: currentAction - anchors.bottom: pCircle.top - anchors.left: parent.left - anchors.margins: Constants.component_spacing - anchors.right: parent.right - anchors.top: parent.top - - BusyImageIndicator { - id: busyIcon - anchors.centerIn: parent - height: Math.min(parent.height - 40, 2 * pCircle.height) - running: visible - visible: baseItem.state === "one" - width: height - } - CardReader { - anchors.centerIn: parent - cardAnimation: baseItem.state === "two" - height: parent.height - pinFieldAnimation: false - visible: baseItem.state === "two" - } - } - ProgressCircle { - id: pCircle - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - state: baseItem.state - visible: baseItem.state === "one" || baseItem.state === "two" - } -} diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml new file mode 100644 index 0000000..85c3ca2 --- /dev/null +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteProgressIndicator.qml @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany + */ +import QtQuick 2.15 +import Governikus.Global 1.0 +import Governikus.Style 1.0 + +Item { + id: baseItem + + property bool foundSelectedReader: false + + height: Style.dimens.workflow_progress_indicator_size + + TintableIcon { + id: phone + anchors.centerIn: parent + desaturate: true + opacity: tintEnabled ? 0.7 : 1.0 + source: "qrc:///images/mobile/phone_remote.svg" + sourceSize.height: Style.dimens.header_icon_size + visible: !baseItem.foundSelectedReader + } + Item { + id: currentAction + anchors.bottom: pCircle.top + anchors.left: parent.left + anchors.margins: Constants.component_spacing + anchors.right: parent.right + anchors.top: parent.top + + CardReader { + anchors.centerIn: parent + height: parent.height + pinFieldAnimation: false + visible: baseItem.foundSelectedReader + } + } + ProgressCircle { + id: pCircle + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + state: baseItem.foundSelectedReader ? "two" : "off" + visible: baseItem.foundSelectedReader + } +} diff --git a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml index 2b152f3..0ecf8be 100644 --- a/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/RemoteWorkflow.qml @@ -18,6 +18,8 @@ property bool settingsPushed: remoteServiceSettings.visible property bool wifiEnabled: ApplicationModel.wifiEnabled + signal deviceUnpaired(var pDeviceName) + onFoundSelectedReaderChanged: { if (baseItem.settingsPushed && foundSelectedReader) { remoteServiceSettings.pop(); @@ -26,22 +28,18 @@ Connections { function onFireCertificateRemoved(pDeviceName) { - //: INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - ApplicationModel.showFeedback(qsTr("The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.").arg(pDeviceName)); + deviceUnpaired(pDeviceName); } target: RemoteServiceModel } - ProgressIndicator { + RemoteProgressIndicator { id: progressIndicator Accessible.ignored: true anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - height: parent.height / 2 - imageIconSource: "qrc:///images/mobile/icon_remote.svg" - imagePhoneSource: "qrc:///images/mobile/phone_remote.svg" - state: foundSelectedReader ? "two" : "off" + foundSelectedReader: baseItem.foundSelectedReader } TechnologyInfo { id: techInfo @@ -51,7 +49,7 @@ return qsTr("Enable WiFi"); } else if (!foundSelectedReader) { //: LABEL ANDROID IOS - return qsTr("Pair device"); + return qsTr("Manage pairings"); } else { return ""; } @@ -62,7 +60,7 @@ return qsTr("To use the remote service WiFi has to be activated. Please activate WiFi in your device settings."); } else if (!foundSelectedReader) { //: INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - return qsTr("No paired smartphone as card reader (SaC) with activated \"remote service\" available."); + return qsTr("Allow a connection on a paired smartphone or pair a new smartphone."); } else { return ""; } @@ -87,7 +85,7 @@ return qsTr("Wifi disabled"); } else if (!foundSelectedReader) { //: LABEL ANDROID IOS - return qsTr("Waiting for connection"); + return qsTr("No smartphone as card reader connected"); } else { //: LABEL ANDROID IOS return qsTr("Determine card"); diff --git a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml index 47c6b03..16dac48 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SimulatorWorkflow.qml @@ -4,6 +4,7 @@ import QtQuick 2.15 import Governikus.Global 1.0 import Governikus.TechnologyInfo 1.0 +import Governikus.Style 1.0 Item { id: baseItem @@ -12,7 +13,7 @@ Item { id: progressIndicator - height: parent.height / 2 + height: Style.dimens.workflow_progress_indicator_size anchors { left: parent.left @@ -23,8 +24,8 @@ id: icon anchors.centerIn: parent desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 source: "qrc:///images/mobile/phone_simulator.svg" + sourceSize.height: Style.dimens.header_icon_size tintEnabled: false } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml index 9a040a6..d4e3855 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartProgressIndicator.qml @@ -3,18 +3,21 @@ */ import QtQuick 2.15 import Governikus.Global 1.0 +import Governikus.Style 1.0 Item { id: baseItem property alias disabled: icon.tintEnabled + height: Style.dimens.workflow_progress_indicator_size + TintableIcon { id: icon anchors.centerIn: parent desaturate: true - height: Math.ceil(parent.height * 0.25) * 2 opacity: tintEnabled ? 0.7 : 1.0 source: "qrc:///images/mobile/phone_smart.svg" + sourceSize.height: Style.dimens.header_icon_size } } diff --git a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml index ce02c04..1c2a7b5 100644 --- a/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml +++ b/resources/qml/Governikus/Workflow/+mobile/SmartWorkflow.qml @@ -4,6 +4,7 @@ import QtQuick 2.15 import Governikus.Global 1.0 import Governikus.TechnologyInfo 1.0 +import Governikus.Type.ApplicationModel 1.0 import Governikus.Type.SmartModel 1.0 import Governikus.Type.NumberModel 1.0 import Governikus.Type.PersonalizationModel 1.0 @@ -12,6 +13,7 @@ id: baseItem readonly property bool canUseSmart: smartState === SmartModel.SMART_READY && isSmartCardAllowed && SmartModel.isScanRunning + readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE readonly property bool isSmartCardAllowed: workflowModel.isSmartCardAllowed readonly property int smartState: SmartModel.smartState property var workflowModel @@ -20,7 +22,6 @@ id: progressIndicator Accessible.ignored: true disabled: !canUseSmart - height: parent.height / 2 anchors { left: parent.left @@ -55,6 +56,10 @@ } return ""; default: + if (isRemoteWorkflow) { + //: LABEL ANDROID IOS + return qsTr("You have not yet set up a Smart-eID or it is no longer usable.\n\nTo proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen."); + } //: LABEL ANDROID IOS return qsTr("You have not yet set up a Smart-eID or it is no longer usable.\n\nTo proceed use your ID card by selecting the NFC interface or choose \"WiFi\" to connect with another device as cardreader. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen."); } diff --git a/resources/qml/Governikus/Workflow/qmldir b/resources/qml/Governikus/Workflow/qmldir index c79470e..dbdcf50 100644 --- a/resources/qml/Governikus/Workflow/qmldir +++ b/resources/qml/Governikus/Workflow/qmldir @@ -1,10 +1,9 @@ module Workflow -internal BusyImageIndicator BusyImageIndicator.qml internal CardReader CardReader.qml internal NfcProgressIndicator NfcProgressIndicator.qml internal ProgressCircle ProgressCircle.qml -internal ProgressIndicator ProgressIndicator.qml +internal RemoteProgressIndicator RemoteProgressIndicator.qml internal RemoteWorkflow RemoteWorkflow.qml internal SmartProgressIndicator SmartProgressIndicator.qml internal TextCircle TextCircle.qml diff --git a/resources/translations/ausweisapp2_de.ts b/resources/translations/ausweisapp2_de.ts index da1d532..e40e183 100644 --- a/resources/translations/ausweisapp2_de.ts +++ b/resources/translations/ausweisapp2_de.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - efee4b38a0c7 + b9ade3b30f3d @@ -178,6 +178,11 @@ Do you know your six-digit ID card PIN? Kennen Sie Ihre sechsstellige Karten-PIN? + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + BaseConfirmationPopup @@ -496,6 +501,11 @@ INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. Sie haben dreimal eine falsche, sechsstellige Karten-PIN eingegeben, Ihre Karten-PIN ist nun gesperrt. Um die Sperre aufzuheben, muss zunächst die zehnstellige PUK eingegeben werden. + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + ChangePinViewContent @@ -985,10 +995,6 @@ Das Gerät wird gekoppelt ... - The device "%1" has been paired. - Das Gerät "%1" wurde gekoppelt. - - Pairing to "%1" failed: ERROR DESKTOP An error occurred while pairing the device. Die Kopplung mit "%1" ist fehlgeschlagen: @@ -1469,11 +1475,6 @@ Bitte wiederholen Sie die Eingabe Ihrer neuen sechsstelligen Karten-PIN. - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Starten Sie die Kopplung auf Ihrem Smartphone und geben Sie den dort angezeigten Kopplungscode ein um Ihr Smartphone als Kartenleser (SaK) zu verwenden. - - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. Unbekannter Passwort-Typ: @@ -1612,6 +1613,11 @@ LABEL ANDROID IOS Karten-PIN senden + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Geben Sie den Kopplungscode ein, der auf Ihrem Smartphone angezeigt wird. + GProgressBar @@ -1686,11 +1692,6 @@ GeneralWorkflow - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - Das Gerät %1 wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. - - Attempts LABEL DESKTOP Versuche @@ -1753,6 +1754,11 @@ INFO DESKTOP Zu den Einstellungen + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Das Gerät "%1" wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. + Hint @@ -1765,20 +1771,8 @@ HistoryListItem Click to view details of history entry. + LABEL ANDROID IOS Zeige Details des Verlaufseintrags. - - - today - LABEL ANDROID IOS - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy Tap for more details @@ -1860,18 +1854,6 @@ Im Verlauf suchen - today - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy - - Clear history LABEL DESKTOP Lösche Verlauf @@ -1959,6 +1941,9 @@ dd.MM.yyyy + LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString +---------- +LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy @@ -2053,15 +2038,15 @@ LocalNetworkInfo - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Um Ihr Smartphone als Kartenleser (SaK) nutzen zu können, stellen Sie bitte sicher, dass der Zugriff auf das lokale Netzwerk erlaubt ist. - - Go to application settings INFO IOS Link to application settings Zu den Anwendungseinstellungen + + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + In den Einstellungen muss der Zugriff auf das lokale Netzwerk erlaubt sein. + LogTitleBarControls @@ -2577,16 +2562,16 @@ Anbieter - Remote - Fernzugriff - - Settings Einstellungen Help Hilfe + + + Card reader + Kartenleser @@ -2623,12 +2608,12 @@ NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Der NFC-Scan ist nicht aktiv. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Bitte starten Sie den NFC-Scan. @@ -2666,6 +2651,11 @@ INFO ANDROID The ID card may be inserted, the authentication process may be started. Bitte platzieren Sie Ihren Ausweis direkt an der Geräterückseite.<br/><br/>Die genaue Position des Ausweises ist modellabhängig. Die Animationen zeigen Ihnen mögliche Positionen. Halten Sie jede Position einige Sekunden, bevor Sie eine andere ausprobieren und bewegen Sie den Ausweis nicht mehr, sobald der Kontakt hergestellt wurde. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Das Gerät "%1" möchte dieses Smartphone als Kartenleser nutzen und sich mit Ihrem Ausweis verbinden. + NumberField @@ -2728,6 +2718,52 @@ + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Informationen zur Kopplung + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Öffnen Sie auf Ihrem %2anderen Gerät%3 die %1. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + Gehen Sie dort in die %1Einstellungen%2 und dann zu %1Smartphone als Kartenleser%2 bzw. %1Kopplungen verwalten%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Wählen Sie in der angezeigten Liste dieses Smartphone aus, um es zu koppeln. + + + + PairingProcessInfo + + Open %1 on your smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Klicken Sie zum Koppeln auf das hier angezeigte Gerät. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat. + + + PasswordInfoContent More information @@ -3316,19 +3352,6 @@ ProviderDetailHistoryItem - today - LABEL ANDROID IOS - heute - - - yesterday - gestern - - - dd.MM.yyyy - dd.MM.yyyy - - Service: LABEL DESKTOP Dienst: @@ -3591,10 +3614,6 @@ Drücken Sie die Leertaste um das Smartphone "%1" zu koppeln. - Click to pair - Klicken zum Koppeln - - Remove remote device Entferne das Gerät @@ -3602,38 +3621,70 @@ RemoteReaderView - Paired remote devices - Gekoppelte Netzwerkgeräte - - - Available remote devices - Verfügbare Netzwerkgeräte - - - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Nur Geräte die bereits gekoppelt wurden, oder sich mit aktiviertem Fernzugriff im selben WLAN-Netz befinden, werden hier angezeigt. - - - More information - LABEL DESKTOP - Mehr Informationen + Paired devices + Gekoppelte Geräte + + + Add pairing + Kopplung hinzufügen + + + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser. + + + Both devices have to be connected to the same WiFi. + Beide Geräte müssen mit demselben WLAN verbunden sein. + + + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Klicken Sie zum Koppeln auf das hier angezeigte Gerät. + + + Last connected + Zuletzt verbunden + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat. + + + + RemoteServiceController + + You are about to identify yourself towards the following provider using the device "%1": + LABEL ANDROID IOS + Sie möchten sich mit dem Gerät %1 bei folgendem Anbieter ausweisen: + + + Card reader + LABEL ANDROID IOS + Kartenleser + + + Remote service + LABEL ANDROID IOS + Fernzugriff RemoteServiceSettings - Configure remote service - LABEL ANDROID IOS - Fernzugriff konfigurieren + Manage pairings + LABEL ANDROID IOS + Kopplungen verwalten RemoteServiceView - - Remote service - LABEL ANDROID IOS - Fernzugriff - Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3665,87 +3716,97 @@ Warte auf Verbindung - Remote service ready - LABEL ANDROID IOS - Fernzugriff startbereit - - Waiting for connection from a paired device... INFO ANDROID IOS Warte auf eine Verbindung eines gekoppelten Gerätes... - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). + Pairing code: <b>%1</b> + LABEL ANDROID IOS + Kopplungscode: <b>%1</b> + + + Enable WiFi + LABEL ANDROID IOS + WLAN aktivieren + + + Enable NFC + LABEL ANDROID IOS + NFC aktivieren + + + Pair device + LABEL ANDROID IOS + Gerät koppeln + + + Allow connection + LABEL ANDROID IOS + Verbindung erlauben + + + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. +To do this you first have to pair that device with this smartphone. INFO ANDROID IOS - Starten Sie den Fernzugriff, um dieses Smartphone sichtbar und damit als Kartenleser (SaK) nutzbar zu machen. + Sie können dieses Smartphone als Kartenleser für die %1 auf einem anderen Gerät, z.B. Ihrem Laptop, nutzen. -Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um dieses Smartphone als Kartenleser einzurichten. - - - Pairing code: <b>%1</b> - LABEL ANDROID IOS - Kopplungscode: <b>%1</b> - - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Ihre beiden Geräte müssen mit dem selben WLAN-Netz verbunden sein. - - - Enable WiFi - LABEL ANDROID IOS - WLAN aktivieren - - - Enable NFC - LABEL ANDROID IOS - NFC aktivieren - - - Stop remote service - LABEL ANDROID IOS - Fernzugriff stoppen - - - Start remote service - LABEL ANDROID IOS - Fernzugriff starten - - - Stop pairing - LABEL ANDROID IOS - Kopplung stoppen - - - Start pairing - LABEL ANDROID IOS - Kopplung starten - - - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). +Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppeln. + + + Card reader + LABEL ANDROID IOS + Kartenleser + + + Paired Devices INFO ANDROID IOS - Geben Sie den Code %1 in der %2 auf Ihrem anderen Gerät ein, um Ihr Smartphone als Kartenleser (SaK) zu verwenden. + Gekoppelte Geräte + + + Pair new device + LABEL ANDROID IOS + Neues Gerät koppeln + + + Waiting for pairing + LABEL ANDROID IOS + Warte auf Kopplung + + + Start pairing of a new device + LABEL ANDROID IOS + Kopplung mit einem neuen Gerät starten. + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Wo gebe ich den Kopplungscode ein? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Geben Sie den Kopplungscode %1 in der %2 auf Ihrem anderen Gerät ein. + + + Cancel pairing + LABEL ANDROID IOS + Kopplung abbrechen + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Erlauben Sie eine Verbindung mit gekoppelten Geräten, um dieses Smartphone als Kartenleser zu nutzen oder koppeln Sie weitere Geräte. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Gekoppelte Geräte können dieses Smartphone jetzt als Kartenleser nutzen. RemoteServiceViewRemote - - Paired devices - LABEL ANDROID IOS - Gekoppelte Geräte - - - No device is paired. - LABEL ANDROID IOS - Kein Gerät gekoppelt. - - - Click to remove device - LABEL ANDROID IOS - Klicken, um das Gerät zu entfernen - Remove pairing INFO ANDROID IOS @@ -3762,16 +3823,6 @@ Entfernen - Available devices - LABEL ANDROID IOS - Verfügbare Geräte - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Kein ungekoppeltes Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion "Fernzugriff" in der AusweisApp2 auf Ihrem Smartphone aktiviert ist und beide Geräte mit demselben WLAN verbunden sind. - - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. Bitte verbinden Sie sich mit Ihrem WLAN, um ein anderes Smartphone als Kartenleser (SaK) benutzen zu können. @@ -3782,42 +3833,55 @@ WLAN aktivieren + Pairing code + LABEL ANDROID IOS + Kopplungscode + + + Add pairing + LABEL ANDROID IOS + Kopplung hinzufügen + + + Click to remove device + LABEL ANDROID IOS + Klicken, um das Gerät zu entfernen + + + Last connected + LABEL ANDROID IOS + Zuletzt verbunden + + + Available + LABEL ANDROID IOS + Verfügbar + + + Paired devices + LABEL ANDROID IOS + Gekoppelte Geräte + + Click to pair LABEL ANDROID IOS Klicken zum Koppeln - - Pairing mode - INFO ANDROID IOS - Kopplungsmodus - - - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Starten Sie den Kopplungsmodus auf Ihrem Smartphone, falls noch nicht geschehen. - - - Pairing code - LABEL ANDROID IOS - Kopplungscode + + + RemoteServiceWifiInfo + + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Beide Geräte müssen mit demselben WLAN verbunden sein. RemoteWorkflow - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Das Gerät %1 wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden. - - Enable WiFi LABEL ANDROID IOS WLAN aktivieren - - - Pair device - LABEL ANDROID IOS - Gerät koppeln To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. @@ -3825,19 +3889,9 @@ Um den Fernzugriff zu nutzen, muss WLAN aktiviert werden. Bitte aktivieren Sie WLAN in Ihren Einstellungen. - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Kein gekoppeltes Smartphone als Kartenleser mit aktiviertem "Fernzugriff" verfügbar. - - Wifi disabled LABEL ANDROID IOS WLAN ist deaktiviert - - - Waiting for connection - LABEL ANDROID IOS - Warte auf Verbindung Determine card @@ -3854,6 +3908,21 @@ INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. Verbunden mit %1. Bitte platzieren Sie das Smartphone mit der NFC-Schnittstelle auf Ihrem Ausweis. + + Manage pairings + LABEL ANDROID IOS + Kopplungen verwalten + + + No smartphone as card reader connected + LABEL ANDROID IOS + Kein Smartphone als Kartenleser verbunden + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Erlauben Sie die Verbindung auf einem bereits gekoppelten Smartphone oder koppeln Sie ein neues Smartphone. + ResultErrorView @@ -4249,16 +4318,6 @@ PIN-Eingabe auf diesem Gerät - Remote card reader - LABEL ANDROID IOS - Smartphone als Kartenleser - - - Configure remote service for another device - LABEL ANDROID IOS - Ein anderes Gerät für den Fernzugriff konfigurieren - - Save history LABEL ANDROID IOS Verlauf speichern @@ -4374,6 +4433,26 @@ 15 days old Logfile LABEL ALL_PLATFORMS 15 Tage alte Protokolldatei + + + Show requested rights on this device as well + LABEL ANDROID IOS + Angefragte Berechtigung auch auf diesem Gerät anzeigen + + + Show access rights + LABEL ANDROID IOS + Berechtigungsanzeige + + + Manage paired devices and add new devices + LABEL ANDROID IOS + Gekoppelte Geräte verwalten und neue Geräte hinzufügen + + + Manage pairings + LABEL ANDROID IOS + Kopplungen verwalten @@ -4758,6 +4837,15 @@ Continue Weiter + + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. + LABEL ANDROID IOS + Sie haben noch keine Smart-eID eingerichtet oder diese ist nicht mehr nutzbar. + +Um fortzufahren, verwenden Sie Ihren Ausweis, indem Sie die NFC-Schnittstelle auswählen. Möchten Sie stattdessen eine Smart-eID einrichten, brechen Sie den aktuellen Vorgang bitte ab und starten Sie die Smart-eID-Einrichtung vom Startbildschirm. + StoreFeedbackPopup @@ -5325,9 +5413,9 @@ Beide Geräte müssen im selben WLAN sein - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht "Fernzugriff"... + Now choose "Card reader" in the AusweisApp2 on your smartphone... + LABEL ANDROID IOS + Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht "Kartenleser"... Now @@ -5335,9 +5423,9 @@ Jetzt - Start pairing - LABEL ANDROID IOS - Kopplung starten + Pair device + LABEL ANDROID IOS + Gerät koppeln Pairing code @@ -5483,9 +5571,9 @@ Beide Geräte müssen im selben WLAN sein - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich "Fernzugriff"... + Now choose "Card reader" in the AusweisApp2 on your smartphone... + LABEL ANDROID IOS + Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich "Kartenleser"... Now @@ -5493,9 +5581,9 @@ Jetzt - Start pairing - LABEL ANDROID IOS - Kopplung starten + Pair device + LABEL ANDROID IOS + Gerät koppeln Pairing code @@ -5513,9 +5601,9 @@ Bei der ersten Verwendung des Smartphones als Kartenleser (SaK) bittet iOS Sie um Ihre Erlaubnis um auf das lokale Netzwerk zugreifen zu dürfen. Diese Berechtigung ist erforderlich, um Ihr SaK zu finden und eine Verbindung zu ihm herzustellen. Nach der ersten Anfrage können Sie jederzeit auf die Berechtigung in den iOS-Einstellungen für diese App zugreifen. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. + Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. LABEL IOS - Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen Sie <b>Fernzugriff konfigurieren</b> aus. + Öffnen Sie nun die AusweisApp2 auf dem Gerät <b>ohne</b> NFC und wählen Sie <b>Kopplungen verwalten</b> aus. Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. @@ -5923,6 +6011,24 @@ Checksum link: LABEL DESKTOP Link to download checksum to verify the downloaded update file. Link zur Prüfsumme: + + + + Utils + + today + LABEL ALL_PLATFORMS + heute + + + yesterday + LABEL ALL_PLATFORMS + gestern + + + dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -6318,7 +6424,7 @@ d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d. MMMM yyyy, HH:mm:ss 'Uhr' @@ -6528,7 +6634,7 @@ dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy, hh:mm:ss @@ -6793,9 +6899,9 @@ Die Authentisierung ist fehlgeschlagen. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ihr Kartenleser unterstützt keine Extended Length Kommunikation und kann nicht zum Auslesen des Ausweises genutzt werden. Auf diese Einschränkung hat die %1 leider keinen Einfluss. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Die Länge der an den Ausweis gesendeten Daten wurde nicht akzeptiert. Entweder sind die Daten fehlerhaft oder Ihr Kartenleser unterstützt keine Extended Length Kommunikation und kann nicht zum Auslesen des Ausweises genutzt werden. Auf diese Einschränkung hat die %1 leider keinen Einfluss. No certificate description available. @@ -7095,6 +7201,7 @@ governikus::HistoryModelSearchFilter dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy @@ -7147,6 +7254,7 @@ dd.MM.yyyy hh:mm:ss + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm:ss @@ -7206,6 +7314,7 @@ governikus::NotificationModel hh:mm:ss + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm:ss @@ -7299,7 +7408,7 @@ dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy HH:mm @@ -7324,12 +7433,12 @@ dd.MM.yyyy - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm @@ -7475,6 +7584,7 @@ hh:mm:ss AP + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString HH:mm:ss @@ -7531,11 +7641,6 @@ Gekoppelt, aber nicht unterstützt - Paired, but unavailable - LABEL ALL_PLATFORMS - Gekoppelt, aber nicht verfügbar - - Unsupported LABEL ALL_PLATFORMS Nicht unterstützt @@ -7547,6 +7652,7 @@ dd.MM.yyyy hh:mm AP + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy HH:mm @@ -7558,6 +7664,16 @@ No smartphone as card reader (Sac) available. Please make sure to activate the "remote service" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use. INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. Kein Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion "Fernzugriff" in der AusweisApp2 auf Ihrem Smartphone aktiviert ist und beide Geräte mit demselben WLAN verbunden sind. Informationen zur Verwendung finden Sie in der %1. + + + Unavailable + LABEL ALL_PLATFORMS + Nicht verfügbar + + + Click to pair + LABEL ALL_PLATFORMS + Klicken zum Koppeln @@ -7590,6 +7706,11 @@ Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu können. + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Die Kopplung mit %1 war erfolgreich. + governikus::RemoteServiceSettings @@ -7613,14 +7734,17 @@ dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString dd.MM.yyyy xx.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day xx.MM.yyyy xx.xx.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month xx.xx.yyyy @@ -7761,6 +7885,14 @@ Access denied. INFO IOS The current session was interrupted because of a wrong password. Zugriff verweigert. + + + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Der sichere Kanal wird geöffnet diff --git a/resources/translations/ausweisapp2_ru.ts b/resources/translations/ausweisapp2_ru.ts index 79350d5..43dbdad 100644 --- a/resources/translations/ausweisapp2_ru.ts +++ b/resources/translations/ausweisapp2_ru.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - efee4b38a0c7 + b9ade3b30f3d @@ -178,6 +178,11 @@ Do you know your six-digit ID card PIN? Вы знаете 6-значный PIN-код идентификационной карты? + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + BaseConfirmationPopup @@ -496,6 +501,11 @@ INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. Вы трижды ввели неправильный 6-значный PIN-код идентификационной карты, PIN-код идентификационной карты заблокирован. Для разблокировки введите 10-значный PUK-код. + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + ChangePinViewContent @@ -505,11 +515,21 @@ Какой у вас PIN-код? + Six-digit PIN + LABEL ALL_PLATFORMS + 6-значный PIN-код + + Set by yourself LABEL ALL_PLATFORMS Создается пользователем самостоятельно + Five-digit Transport PIN + LABEL ALL_PLATFORMS + 5-значный временный PIN-код + + Received by mail in PIN letter LABEL ALL_PLATFORMS Получен по почте в письме с PIN-кодом @@ -523,16 +543,6 @@ Lost, forgotten, or never received it LABEL ALL_PLATFORMS Утерян, забыт или не получен вовсе - - - Six-digit PIN - LABEL ALL_PLATFORMS - 6-значный PIN-код - - - Five-digit Transport PIN - LABEL ALL_PLATFORMS - 5-значный временный PIN-код @@ -665,7 +675,7 @@ Your mobile device has no NFC interface. This is required to read the ID card. However, you can use a separate smartphone as card reader to utilize the eID function.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы также можете использовать другой смартфон в качестве устройства чтения карт для онлайн-идентификации.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. + В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы можете воспользоваться функцией eID на другом смартфоне, используемом в качестве устройства чтения карт.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. Open website @@ -695,7 +705,7 @@ The NFC interface of your mobile device does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. %1 не имеет какого-либо влияния на это ограничение.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. + Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение.<br><br>Список совместимых с %1 смартфонов см. на нашем сайте. ID card access failed @@ -725,7 +735,7 @@ The ID card PIN has been entered incorrectly twice in a row. This is why you must first enter the six-digit Card Access Number (CAN) for the next identification process. You can find it at the bottom right of the front of your ID card.<br><br>You may now try the function: "See my personal data". There you can also use the CAN to unblock the ID card PIN. LABEL ANDROID IOS - PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он расположен внизу справа на передней стороне идентификационной карты.<br><br>Теперь проверьте работу функции. «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты. + PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он указан внизу справа на передней стороне вашей идентификационной карты.<br><br>Проверьте функцию: «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты. Continue @@ -740,7 +750,7 @@ The ID card PIN has been entered incorrectly thrice. Therefore, you must first enter the ten-digit PUK during the next authentication process. You can find it in the PIN letter you received after applying for your ID card.<br><br>You may now try the function: "See my personal data". Have your PUK ready to unlock the ID card PIN. LABEL ANDROID IOS - PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.<br><br>Теперь проверьте работу функции. «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты. + PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.<br><br>Проверьте функцию: «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты. @@ -985,10 +995,6 @@ Сопряжение устройства… - The device "%1" has been paired. - Устройство «%1» сопряжено. - - Pairing to "%1" failed: ERROR DESKTOP An error occurred while pairing the device. Сбой сопряжения «%1»: @@ -1469,11 +1475,6 @@ Подтвердите новый 6-значный PIN-код идентификационной карты. - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Запустите сопряжение на смартфоне и введите указанный в смартфоне код сопряжения для использования смартфона в качестве устройства чтения карт (SaC). - - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. Неизвестный тип пароля: @@ -1612,6 +1613,11 @@ LABEL ANDROID IOS Отправить PIN-код идентификационной карты + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Введите указанный в смартфоне код сопряжения. + GProgressBar @@ -1686,11 +1692,6 @@ GeneralWorkflow - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - Сопряжение устройства %1 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. - - Attempts LABEL DESKTOP Попытки @@ -1753,6 +1754,11 @@ INFO DESKTOP Перейти к настройкам устройства чтения карт + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. + Hint @@ -1765,20 +1771,8 @@ HistoryListItem Click to view details of history entry. + LABEL ANDROID IOS Щелкните, чтобы просмотреть подробную информацию о записи журнала. - - - today - LABEL ANDROID IOS - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - дд.ММ.гггг Tap for more details @@ -1860,18 +1854,6 @@ Поиск в журнале - today - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - дд.ММ.гггг - - Clear history LABEL DESKTOP Очистить журнал @@ -1959,7 +1941,10 @@ dd.MM.yyyy - дд.ММ.гггг + LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString +---------- +LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy Write access (update) @@ -2053,15 +2038,15 @@ LocalNetworkInfo - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Чтобы использовать смартфон в качестве устройства чтения карт (SaC), убедитесь в наличии доступа к локальной сети. - - Go to application settings INFO IOS Link to application settings Перейти к настройкам приложения + + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + Убедитесь в наличии доступа к локальной сети. + LogTitleBarControls @@ -2164,20 +2149,20 @@ Фильтр + Level + LABEL ANDROID IOS + Уровень + + + Category + LABEL ANDROID IOS + Категория + + Currently there are no log entries matching your filter. INFO ANDROID IOS No log entries, placeholder text. В настоящее время отсутствуют записи журнала, соответствующие вашему фильтру. - - Level - LABEL ANDROID IOS - Уровень - - - Category - LABEL ANDROID IOS - Категория - MainView @@ -2577,16 +2562,16 @@ Провайдер - Remote - Удаленный доступ - - Settings Настройки Help Справка + + + Card reader + Устройство чтения карт @@ -2623,12 +2608,12 @@ NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. NFC-сканирование не выполняется. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Запустите NFC-сканирование. @@ -2666,6 +2651,11 @@ INFO ANDROID The ID card may be inserted, the authentication process may be started. Расположите идентификационную карту непосредственно на задней стороне устройства.<br/><br/>Точное положение идентификационной карты зависит от устройства. Возможное положение показано в анимации. Удерживайте идентификационную карту в одном положении несколько секунд, прежде чем поменять положение, и не смещайте ее после установки соединения. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Устройство «%1» планирует использовать данный смартфон в качестве устройства чтения карт и установить соединение с вашей идентификационной картой. + NumberField @@ -2728,6 +2718,52 @@ + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Информация о сопряжении + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Откройте %1 в другом %2вашем устройстве%3. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + В данном устройстве перейдите в меню %1Настройки%2, а затем %1Смартфон в качестве устройства чтения карт%2 и в соответствующее меню %1Управлять сопряжениями%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Чтобы выполнить сопряжение, выберите данный смартфон в списке. + + + + PairingProcessInfo + + Open %1 on your smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Откройте %1 в вашем смартфоне в качестве устройства чтения карт. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + В данном устройстве выберите %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и соответствующее меню %1Выполнить сопряжение нового устройства%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Чтобы выполнить сопряжение, выберите смартфон в приведенном списке. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2. + + + PasswordInfoContent More information @@ -2748,14 +2784,34 @@ Информация о PIN-коде + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID. + + Where can I find the card PIN? LABEL ALL_PLATFORMS Где найти PIN-код карты? + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' + Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID. + + How do I choose a secure PIN? LABEL ALL_PLATFORMS Как выбрать безопасный PIN-код? + + + For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 + Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, «123456», дату своего рождения или любые другие цифры с идентификационной карты). + + + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 + Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код. Keep your PIN secret and change it if another person becomes aware of it. @@ -2773,6 +2829,16 @@ Информация о временном PIN-коде + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 + 5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту. + + + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 + Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода. + + Once you have set a card PIN, the Transport PIN loses its validity. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 После создания PIN-кода карты временный PIN-код перестает действовать. @@ -2803,6 +2869,11 @@ Информация о PUK-коде + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' + PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту. + + Why is the PUK required? LABEL ALL_PLATFORMS Для чего необходим PUK-код? @@ -2858,6 +2929,11 @@ Где найти CAN-код? + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' + CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты. + + The Card Access Number (CAN) allows to access the imprinted data of the ID card. The CAN is a six-digit number that can be found on the front of the ID card. It is located at the bottom right next to the validity date (marked in red). INFO ALL_PLATFORMS Description text of CAN-allowed authentication Код доступа (CAN) предоставляет доступ к сохраненным на идентификационной карте данным. CAN — это 6-значный номер, указанный на идентификационной карте спереди. Он расположен внизу справа рядом со сроком действия (выделен красным цветом). @@ -2890,6 +2966,11 @@ Знаете ли вы свой PIN-код? + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? + INFO ALL_PLATFORMS + Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код? + + You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it? INFO ALL_PLATFORMS Вы установили PIN-код карты при получении идентификационной карты или позже самостоятельно, но не можете его вспомнить? @@ -2905,11 +2986,46 @@ Типы PIN-кодов + Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить на 6-значным PIN-кодом (его вы выберете сами). + + + Five-digit Transport PIN + LABEL ALL_PLATFORMS + 5-значный временный PIN-код + + + The five-digit Transport PIN was sent to you by post after you applied for your ID card. + INFO ALL_PLATFORMS Description text explaining the PINs 2/6 + 5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту. + + + The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 3/6 + Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами. + + + Six-digit PIN + LABEL ALL_PLATFORMS + 6-значный PIN-код + + + This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 4/6 + Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код. + + This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. INFO ALL_PLATFORMS Description text explaining the PINs 5/6 Этот PIN-код позволяет в режиме онлайн подтвердить то, что идентификационная карта принадлежит именно вам. Никто не сможет использовать вашу идентификационную карту в режиме онлайн без этого PIN-кода. + You can change your six-digit PIN at any time in AusweisApp2. + INFO ALL_PLATFORMS Description text explaining the PINs 6/6 + Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2. + + You can use the PIN Reset Service to request a new card PIN free of charge. LABEL ALL_PLATFORMS Вы можете воспользоваться службой сброса PIN-кода, чтобы бесплатно запросить новый PIN-код карты. @@ -2924,86 +3040,6 @@ LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. Если вы забыли PIN-код карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода. - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID. - - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID. - - - For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 - Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, 123456, дату своего рождения или любые другие цифры с идентификационной карты). - - - You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 - Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код. - - - The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - 5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту. - - - If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода. - - - The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту. - - - The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты. - - - Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 - К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить 6-значным PIN-кодом (его вы выберете сами). - - - Five-digit Transport PIN - LABEL ALL_PLATFORMS - 5-значный временный PIN-код - - - The five-digit Transport PIN was sent to you by post after you applied for your ID card. - INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - 5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту. - - - The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами. - - - Six-digit PIN - LABEL ALL_PLATFORMS - 6-значный PIN-код - - - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код. - - - You can change your six-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2. - - - You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? - INFO ALL_PLATFORMS - Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код? - PersonalizationController @@ -3316,19 +3352,6 @@ ProviderDetailHistoryItem - today - LABEL ANDROID IOS - сегодня - - - yesterday - вчера - - - dd.MM.yyyy - дд.ММ.гггг - - Service: LABEL DESKTOP Служба: @@ -3387,7 +3410,7 @@ See details under "more..." LABEL DESKTOP - Подробнее см. в пункте «Дополнительные сведения» + Подробнее см. в пункте «Дополнительные сведения». @@ -3591,10 +3614,6 @@ Нажмите пробел для сопряжения смартфона «%1». - Click to pair - Нажмите для сопряжения - - Remove remote device Удалить дистанционное устройство @@ -3602,38 +3621,70 @@ RemoteReaderView - Paired remote devices - Сопряженные дистанционные устройства - - - Available remote devices - Доступные дистанционные устройства - - - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Здесь отображаются только уже сопряженные или подключенные к той же сети Wi-Fi устройства с активированной удаленной службой. - - - More information - LABEL DESKTOP - Дополнительные сведения + Paired devices + Сопряженные устройства + + + Add pairing + Добавить сопряжение + + + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Откройте %1 в вашем смартфоне в качестве устройства чтения карт. + + + Both devices have to be connected to the same WiFi. + Оба устройства должны быть подключены к одной сети Wi-Fi. + + + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + В данном устройстве перейдите в меню %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и в соответствующее меню %1Выполнить сопряжение нового устройства%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Чтобы выполнить сопряжение, выберите устройство в списке. + + + Last connected + Последние подключенные + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2. + + + + RemoteServiceController + + You are about to identify yourself towards the following provider using the device "%1": + LABEL ANDROID IOS + Вы собираетесь пройти самоидентификацию для следующего провайдера, используя устройство «%1»: + + + Card reader + LABEL ANDROID IOS + Устройство чтения карт + + + Remote service + LABEL ANDROID IOS + Удаленная служба RemoteServiceSettings - Configure remote service - LABEL ANDROID IOS - Сконфигурировать удаленную службу + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями RemoteServiceView - - Remote service - LABEL ANDROID IOS - Удаленная служба - Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3665,87 +3716,97 @@ Ожидание соединения - Remote service ready - LABEL ANDROID IOS - Удаленная служба готова к работе - - Waiting for connection from a paired device... INFO ANDROID IOS Ожидание соединения сопряженного устройства… - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). + Pairing code: <b>%1</b> + LABEL ANDROID IOS + Код сопряжения: <b>%1</b> + + + Enable WiFi + LABEL ANDROID IOS + Активировать Wi-Fi + + + Enable NFC + LABEL ANDROID IOS + Активировать NFC + + + Pair device + LABEL ANDROID IOS + Выполнить сопряжение устройства + + + Allow connection + LABEL ANDROID IOS + Разрешить подключение + + + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. +To do this you first have to pair that device with this smartphone. INFO ANDROID IOS - Запустите удаленный доступ, чтобы смартфон стал видимым и его можно было использовать как устройство чтения карт (SaC). + Можно использовать данный смартфон в качестве устройства чтения карт для %1 в других устройствах, например в ноутбуке. -Если сопряженных устройств еще нет, запустите сопряжение, чтобы настроить смартфон как устройство чтения карт. - - - Pairing code: <b>%1</b> - LABEL ANDROID IOS - Код сопряжения: <b>%1</b> - - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Оба устройства должны быть подключены к одной сети Wi-Fi. - - - Enable WiFi - LABEL ANDROID IOS - Активировать Wi-Fi - - - Enable NFC - LABEL ANDROID IOS - Активировать NFC - - - Stop remote service - LABEL ANDROID IOS - Остановить удаленную службу - - - Start remote service - LABEL ANDROID IOS - Запустить удаленную службу - - - Stop pairing - LABEL ANDROID IOS - Остановить сопряжение - - - Start pairing - LABEL ANDROID IOS - Запустить сопряжение - - - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). +Для этого сначала следует выполнить сопряжение данного устройства с этим смартфоном. + + + Card reader + LABEL ANDROID IOS + Устройство чтения карт + + + Paired Devices INFO ANDROID IOS - Введите код %1 в %2 на другом вашем устройстве, чтобы использовать смартфон в качестве устройства чтения карт (SaC). + Сопряженные устройства + + + Pair new device + LABEL ANDROID IOS + Выполнить сопряжение нового устройства + + + Waiting for pairing + LABEL ANDROID IOS + Ожидание сопряжения + + + Start pairing of a new device + LABEL ANDROID IOS + Начать сопряжение нового устройства + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Где следует вводить код сопряжения? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Введите код сопряжения %1 в поле %2 в другом вашем устройстве. + + + Cancel pairing + LABEL ANDROID IOS + Отменить сопряжение + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Разрешите подключение к сопряженным устройствам, чтобы использовать этот смартфон в качестве устройства чтения карт, а также для сопряжения с другим устройством. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Теперь сопряженные устройства могут использовать этот смартфон в качестве устройства чтения карт. RemoteServiceViewRemote - - Paired devices - LABEL ANDROID IOS - Сопряженные устройства - - - No device is paired. - LABEL ANDROID IOS - Нет сопряженных устройств. - - - Click to remove device - LABEL ANDROID IOS - Нажмите для удаления устройства - Remove pairing INFO ANDROID IOS @@ -3762,16 +3823,6 @@ Удалить - Available devices - LABEL ANDROID IOS - Доступные устройства - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Нет доступных сопряженных смартфонов, используемых как устройство чтения карт (SaC). Убедитесь в том, что смартфон активирован в AusweisApp2 на другом устройстве в качестве устройства чтения карт (SaC) и оба устройства подключены к одной сети Wi-Fi. - - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. Подключитесь к сети Wi-Fi, чтобы использовать другой смартфон в качестве устройства чтения карт (SaC). @@ -3782,42 +3833,55 @@ Активировать Wi-Fi + Pairing code + LABEL ANDROID IOS + Код сопряжения + + + Add pairing + LABEL ANDROID IOS + Добавить сопряжение + + + Click to remove device + LABEL ANDROID IOS + Нажмите для удаления устройства + + + Last connected + LABEL ANDROID IOS + Последние подключенные + + + Available + LABEL ANDROID IOS + Доступно + + + Paired devices + LABEL ANDROID IOS + Сопряженные устройства + + Click to pair LABEL ANDROID IOS Нажмите для сопряжения - - Pairing mode - INFO ANDROID IOS - Режим сопряжения - - - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Запустите режим сопряжения на смартфоне, если вы еще не сделали это. - - - Pairing code - LABEL ANDROID IOS - Код сопряжения + + + RemoteServiceWifiInfo + + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Оба устройства должны быть подключены к одной сети Wi-Fi. RemoteWorkflow - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Сопряжение устройства %1 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт. - - Enable WiFi LABEL ANDROID IOS Активировать Wi-Fi - - - Pair device - LABEL ANDROID IOS - Выполнить сопряжение устройства To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. @@ -3825,19 +3889,9 @@ Для использования удаленной службы необходимо активировать Wi-Fi. Активируйте Wi-Fi в настройках устройства. - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC), с активированной удаленной службой. - - Wifi disabled LABEL ANDROID IOS Wi-Fi деактивирован - - - Waiting for connection - LABEL ANDROID IOS - Ожидание соединения Determine card @@ -3854,6 +3908,21 @@ INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. Подключено к %1. Разместите интерфейс NFC смартфона на идентификационной карте. + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями + + + No smartphone as card reader connected + LABEL ANDROID IOS + Смартфон в качестве устройства чтения карт не подключен + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Разрешите подключение к сопряженному смартфону или выполните сопряжение нового смартфона. + ResultErrorView @@ -4249,16 +4318,6 @@ Ввести PIN-код на этом устройстве - Remote card reader - LABEL ANDROID IOS - Удаленное устройство чтения карт - - - Configure remote service for another device - LABEL ANDROID IOS - Сконфигурировать удаленную службу для другого устройства - - Save history LABEL ANDROID IOS Сохранить журнал @@ -4374,6 +4433,26 @@ 15 days old Logfile LABEL ALL_PLATFORMS Файл журнала, созданный 15 дней назад + + + Show requested rights on this device as well + LABEL ANDROID IOS + Показывать запрошенные права также и в этом устройстве + + + Show access rights + LABEL ANDROID IOS + Показывать права доступа + + + Manage paired devices and add new devices + LABEL ANDROID IOS + Управление сопряженными устройствами и добавление новых устройств + + + Manage pairings + LABEL ANDROID IOS + Управление сопряжениями @@ -4758,6 +4837,15 @@ Continue Продолжить + + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. + LABEL ANDROID IOS + Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования. + +Для продолжения используйте вашу идентификационную карту, выбрав интерфейс NFC. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране. + StoreFeedbackPopup @@ -5015,7 +5103,7 @@ App on Android smartphone <b>with</b> NFC chip as card reader - Приложение на смартфоне с ОС Android <b>с</b> чипсетом NFC в качестве устройства чтения карт + Приложение на смартфоне <b>с</b> ОС Android с чипсетом NFC в качестве устройства чтения карт Smartphone as card reader tutorial @@ -5158,7 +5246,7 @@ You can read our <b>FAQs</b> or <b>write</b> to us... LABEL ANDROID IOS - Прочитайте раздел <b>Часто задаваемые вопросы</b> или <b>напишите</b> нам… + Прочитайте раздел «Часто задаваемые вопросы» или <b>напишите</b> нам… or @@ -5204,7 +5292,7 @@ App on Android smartphone <b>with</b> NFC chip as card reader LABEL ANDROID - Приложение на смартфоне с ОС Android <b>с</b> чипсетом NFC в качестве устройства чтения карт + Приложение на смартфоне <b>с</b> ОС Android с чипсетом NFC в качестве устройства чтения карт Click link on the website of the provider. @@ -5325,9 +5413,9 @@ Оба устройства должны быть подключены к одной сети Wi-Fi. - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне… + Now choose "Card reader" in the AusweisApp2 on your smartphone... + LABEL ANDROID IOS + Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне… Now @@ -5335,9 +5423,9 @@ сейчас - Start pairing - LABEL ANDROID IOS - Запустить сопряжение + Pair device + LABEL ANDROID IOS + Выполнить сопряжение устройства Pairing code @@ -5362,7 +5450,7 @@ Select the <b>Smartphone as card reader</b> tab. LABEL ANDROID IOS - Выберите вкладку <b>Смартфон в качестве устройства чтения карт</b>. + Выберите вкладку «Смартфон в качестве устройства чтения карт». Select smartphone from list @@ -5483,9 +5571,9 @@ Оба устройства должны быть подключены к одной сети Wi-Fi. - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне… + Now choose "Card reader" in the AusweisApp2 on your smartphone... + LABEL ANDROID IOS + Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне… Now @@ -5493,9 +5581,9 @@ сейчас - Start pairing - LABEL ANDROID IOS - Запустить сопряжение + Pair device + LABEL ANDROID IOS + Выполнить сопряжение устройства Pairing code @@ -5513,19 +5601,19 @@ При первом использовании смартфона в качестве устройства чтения карт (SaC) iOS запрашивает разрешение на доступ к локальной сети. Разрешение необходимо, чтобы обнаружить ваш SaC и подключиться к нему. После первого запроса вы всегда можете отменить разрешение в настройках iOS для этого приложения. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. + Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. LABEL IOS - Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите <b>Сконфигурировать удаленную службу</b>. + Теперь откройте приложение AusweisApp2 в своем устройстве <b>без</b> NFC и выберите меню «Управление сопряжениями». Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. LABEL ANDROID - Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите <b>Смартфон в качестве устройства чтения карт</b>. + Откройте AusweisApp2 на вашем устройстве <b>без</b> NFC и выберите «Смартфон в качестве устройства чтения карт». Now select <b>Settings</b>. LABEL ANDROID IOS - Далее выберите <b>Настройки</b>. + Далее выберите «Настройки». Choose smartphone from list @@ -5681,7 +5769,7 @@ On every authentication you get displayed <b>who</b> wants to access <b>which</b> data LABEL ANDROID IOS - При каждой аутентификации отображается, <b>кто</b> и к <b>каким</b> данным запрашивает доступ, + При каждой аутентификации отображается, <b>кто</b> и к <b>каким</b> данным запрашивает доступ. and you consent to the request with your six-digit PIN. @@ -5923,6 +6011,24 @@ Checksum link: LABEL DESKTOP Link to download checksum to verify the downloaded update file. Ссылка для контрольной суммы: + + + + Utils + + today + LABEL ALL_PLATFORMS + сегодня + + + yesterday + LABEL ALL_PLATFORMS + вчера + + + dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -6318,7 +6424,7 @@ d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d MMMM yyyy г., hh:mm:ss @@ -6528,8 +6634,8 @@ dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp - дд.ММ.гггг, чч:мм:сс + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + dd.MM.yyyy, hh:mm:ss Last connection: %1 @@ -6793,9 +6899,9 @@ Сбой аутентификации. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Размер данных, отправленных на идентификационную карту, не был принят. Либо данные неверны, либо ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение. No certificate description available. @@ -7095,7 +7201,8 @@ governikus::HistoryModelSearchFilter dd.MM.yyyy - дд.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -7147,6 +7254,7 @@ dd.MM.yyyy hh:mm:ss + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy, hh:mm:ss @@ -7206,7 +7314,8 @@ governikus::NotificationModel hh:mm:ss - чч:мм:сс + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString + hh:mm:ss @@ -7277,7 +7386,7 @@ AusweisApp2 is a product of Governikus GmbH & Co. KG - on behalf of the Federal Office for Information Security. LABEL ALL_PLATFORMS - AusweisApp2 является продуктом компании Governikus GmbH & Co. KG — по заказу Федерального управления по информационной безопасности. + AusweisApp2 является продуктом компании Governikus GmbH Co. KG — по заказу Федерального управления по информационной безопасности. For further information, please see %1 @@ -7299,7 +7408,7 @@ dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7324,12 +7433,12 @@ dd.MM.yyyy - LABEL ALL_PLATFORMS - дд.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm @@ -7475,6 +7584,7 @@ hh:mm:ss AP + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm:ss @@ -7531,11 +7641,6 @@ Сопряжено, но не поддерживается - Paired, but unavailable - LABEL ALL_PLATFORMS - Сопряжено, но недоступно - - Unsupported LABEL ALL_PLATFORMS Не поддерживается @@ -7547,6 +7652,7 @@ dd.MM.yyyy hh:mm AP + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7558,6 +7664,16 @@ No smartphone as card reader (Sac) available. Please make sure to activate the "remote service" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use. INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC). Убедитесь в том, что удаленная служба активирована на вашем смартфоне и оба устройства подключены к одной сети Wi-Fi. Подробную информацию об использовании см. здесь: %1. + + + Unavailable + LABEL ALL_PLATFORMS + Недоступно + + + Click to pair + LABEL ALL_PLATFORMS + Нажмите для сопряжения @@ -7590,6 +7706,11 @@ Активируйте NFC, чтобы использовать смартфон в качестве устройства чтения карт (SaC). + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Сопряжение с %1 выполнено успешно. + governikus::RemoteServiceSettings @@ -7613,15 +7734,18 @@ dd.MM.yyyy - дд.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy xx.MM.yyyy - хх.ММ.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day + xx.MM.yyyy xx.xx.yyyy - хх.хх.гггг + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month + xx.xx.yyyy Family name @@ -7761,6 +7885,14 @@ Access denied. INFO IOS The current session was interrupted because of a wrong password. Доступ отклонен. + + + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Защищенный канал открыт @@ -8096,7 +8228,7 @@ The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. - Программа по-прежнему доступна через значок на панели задач. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс. + Программа по-прежнему доступна через значок в строке меню. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс. diff --git a/resources/translations/ausweisapp2_uk.ts b/resources/translations/ausweisapp2_uk.ts index b701b72..4fdae1f 100644 --- a/resources/translations/ausweisapp2_uk.ts +++ b/resources/translations/ausweisapp2_uk.ts @@ -5,7 +5,7 @@ DvcsAttributes revision - efee4b38a0c7 + b9ade3b30f3d @@ -178,6 +178,11 @@ Do you know your six-digit ID card PIN? Ви знаєте шестизначний PIN-код своєї ID-картки? + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + BaseConfirmationPopup @@ -496,6 +501,11 @@ INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card. Ви тричі ввели неправильний шестизначний PIN-код ID-картки. Тепер PIN-код вашої ID-картки заблоковано. Щоб видалити блокування, потрібно спочатку ввести десятизначний PUK-код. + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. + Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + ChangePinViewContent @@ -505,11 +515,21 @@ Якого типу ваш PIN-код? + Six-digit PIN + LABEL ALL_PLATFORMS + Шестизначний PIN-код + + Set by yourself LABEL ALL_PLATFORMS Встановлений вами самостійно + Five-digit Transport PIN + LABEL ALL_PLATFORMS + П’ятизначний транспортний PIN-код + + Received by mail in PIN letter LABEL ALL_PLATFORMS Отриманий поштою в листі з PIN-кодом @@ -523,16 +543,6 @@ Lost, forgotten, or never received it LABEL ALL_PLATFORMS Загубили, забули або ніколи його не отримували - - - Six-digit PIN - LABEL ALL_PLATFORMS - 6-значний PIN-код - - - Five-digit Transport PIN - LABEL ALL_PLATFORMS - 5-значний транспортний PIN-код @@ -665,7 +675,7 @@ Your mobile device has no NFC interface. This is required to read the ID card. However, you can use a separate smartphone as card reader to utilize the eID function.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію онлайн-ідентифікації.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. + Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію eID.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. Open website @@ -695,7 +705,7 @@ The NFC interface of your mobile device does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.<br><br>You can find smartphones compatible with the %1 on our website. LABEL ANDROID IOS - Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не впливає на це обмеження.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. + Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження.<br><br>Ви можете знайти смартфони, сумісні з %1, на нашому сайті. ID card access failed @@ -985,10 +995,6 @@ Створення пари з пристроєм… - The device "%1" has been paired. - Пару з пристроєм «%1» створено. - - Pairing to "%1" failed: ERROR DESKTOP An error occurred while pairing the device. Не вдалося створити пару з пристроєм «%1»: @@ -1469,11 +1475,6 @@ Підтвердьте новий шестизначний PIN-код ID-картки. - Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC). - INFO DESKTOP The pairing code needs to be supplied. - Щоб використовувати смартфон як пристрій читання карток (SaC), почніть на ньому створення пари та введіть показаний на його екрані код створення пари. - - Unknown password type: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error. Невідомий тип пароля: @@ -1612,6 +1613,11 @@ LABEL ANDROID IOS Надіслати PIN-код ID-картки + + Enter the pairing code shown on your smartphone. + INFO DESKTOP The pairing code needs to be supplied. + Введіть код створення пари, який відображається на вашому смартфоні. + GProgressBar @@ -1686,11 +1692,6 @@ GeneralWorkflow - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO DESKTOP The paired devices was removed since it did not respond to connection attempts. It needs to be paired again if it should be used as card reader. - Пару з пристроєм %1 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. - - Attempts LABEL DESKTOP Спроби @@ -1753,6 +1754,11 @@ INFO DESKTOP Перейти до параметрів пристрою читання + + The device "%1" was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. + INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. + Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. + Hint @@ -1765,20 +1771,8 @@ HistoryListItem Click to view details of history entry. + LABEL ANDROID IOS Натисніть, щоб переглянути відомості про запис в історії. - - - today - LABEL ANDROID IOS - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - дд.ММ.рррр Tap for more details @@ -1860,18 +1854,6 @@ Пошук в історії - today - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - дд.ММ.рррр - - Clear history LABEL DESKTOP Очистити історію @@ -1959,7 +1941,10 @@ dd.MM.yyyy - дд.ММ.рррр + LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString +---------- +LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy Write access (update) @@ -2053,15 +2038,15 @@ LocalNetworkInfo - To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed. - INFO IOS Let user know to check the application settings for local network permission - Щоб мати можливість використовувати свій смартфон як пристрій читання карток (SaC), переконайтеся, що доступ до локальної мережі дозволено. - - Go to application settings INFO IOS Link to application settings Перейти до параметрів програми + + Ensure that access to the local network is allowed in your settings. + INFO IOS Let user know to check the application settings for local network permission + Переконайтеся, що доступ до локальної мережі дозволено. + LogTitleBarControls @@ -2164,20 +2149,20 @@ Фільтр + Level + LABEL ANDROID IOS + Рівень + + + Category + LABEL ANDROID IOS + Категорія + + Currently there are no log entries matching your filter. INFO ANDROID IOS No log entries, placeholder text. Наразі немає жодних записів журналу, що відповідають цьому фільтру. - - Level - LABEL ANDROID IOS - Рівень - - - Category - LABEL ANDROID IOS - Категорію - MainView @@ -2577,16 +2562,16 @@ Постачальник - Remote - Віддалений доступ - - Settings Параметри Help Довідка + + + Card reader + Пристрій читання карток @@ -2623,12 +2608,12 @@ NFC scan is not running. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Сканування NFC не виконується. Please start the NFC scan. - INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone. + INFO ANDROID IOS NFC is available and enabled but needs to be started. Почніть сканування NFC. @@ -2666,6 +2651,11 @@ INFO ANDROID The ID card may be inserted, the authentication process may be started. Покладіть ID-картку безпосередньо на задній бік пристрою.<br/><br/>Точне положення ID-картки залежить від пристрою. На анімації показано можливі положення. Утримуйте ID-картку в одному положенні кілька секунд, перш ніж спробувати інше, і не переміщайте її після встановлення контакту. + + The device "%1" wants to use this smartphone as card reader and connect to your id card. + INFO ANDROID IOS %1 will be replaced with the name of the device. + Пристрій «%1» намагається використовувати цей смартфон як пристрій читання карток і встановити з’єднання з вашою ID-карткою. + NumberField @@ -2728,6 +2718,52 @@ + PairingCodeInfoView + + Pairing Information + LABEL ANDROID IOS + Інформація про створення пари + + + Open %1 on your %2other device%3. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3 + Відкрийте %1 на своєму %2іншому пристрої%3. + + + On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font. + Перейдіть на тому пристрої до розділу %1Параметри%2, а тоді виберіть %1Смартфон як пристрій читання карток%2 і %1Керування створенням пари%2. + + + Choose this smartphone in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3 + Виберіть цей смартфон у переліку, щоб створити з ним пару. + + + + PairingProcessInfo + + Open %1 on your smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Відкрийте %1 на своєму смартфоні як пристрій читання карток. + + + On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font. + Виберіть на тому пристрої %1Пристрій читання карток%2, а тоді — %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2. + + + Choose the smartphone in the list shown here to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + У наведеному тут переліку виберіть смартфон, щоб створити з ним пару. + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2. + + + PasswordInfoContent More information @@ -2748,14 +2784,34 @@ Інформація про PIN-код + The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. + INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' + PIN-код картки – це шестизначний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID. + + Where can I find the card PIN? LABEL ALL_PLATFORMS Де я можу дізнатися PIN-код картки? + You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' + Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою п’ятизначного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення шестизначного PIN-коду. + + How do I choose a secure PIN? LABEL ALL_PLATFORMS Як вибрати безпечний PIN-код? + + + For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 + Для свого шестизначного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці. + + + You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. + INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 + Ви можете змінювати свій шестизначний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код. Keep your PIN secret and change it if another person becomes aware of it. @@ -2773,6 +2829,16 @@ Інформація про транспортний PIN-код + The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 + П’ятизначний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки. + + + If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. + INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 + Якщо ви не встановили самостійно обраний шестизначний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду. + + Once you have set a card PIN, the Transport PIN loses its validity. INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 3/3 Після встановлення PIN-коду картки транспортний PIN-код втрачає чинність. @@ -2803,6 +2869,11 @@ Інформація про PUK-код + The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. + INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' + PUK-код – це десятизначний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки. + + Why is the PUK required? LABEL ALL_PLATFORMS Навіщо потрібен PUK-код? @@ -2858,6 +2929,11 @@ Де я можу дізнатися CAN-код картки? + The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. + INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' + CAN-код – це шестизначний номер, який можна знайти в нижній правій частині лицьового боку ID-картки. + + The Card Access Number (CAN) allows to access the imprinted data of the ID card. The CAN is a six-digit number that can be found on the front of the ID card. It is located at the bottom right next to the validity date (marked in red). INFO ALL_PLATFORMS Description text of CAN-allowed authentication Номер доступу до картки (CAN) дає змогу отримати доступ до вихідних даних ID-картки. CAN – це шестизначний номер, який можна знайти на лицьовій стороні ID-картки. Він розташований унизу праворуч від терміну дії (позначено червоним). @@ -2890,6 +2966,11 @@ Ви не знаєте свій PIN-код? + You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? + INFO ALL_PLATFORMS + Ви ще не встановили шестизначний PIN-код картки й не можете знайти лист із транспортним PIN-кодом? + + You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it? INFO ALL_PLATFORMS Ви встановили PIN-код картки під час отримання ID-картки або пізніше самостійно, але вже не пам’ятаєте його? @@ -2905,11 +2986,46 @@ Типи PIN-кодів + Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 1/6 + До вашої ID-картки додається п’ятизначний « PIN-код», який вам потрібно змінити на шестизначний PIN-код, який ви обираєте самостійно. + + + Five-digit Transport PIN + LABEL ALL_PLATFORMS + П’ятизначний транспортний PIN-код + + + The five-digit Transport PIN was sent to you by post after you applied for your ID card. + INFO ALL_PLATFORMS Description text explaining the PINs 2/6 + П’ятизначний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки. + + + The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. + INFO ALL_PLATFORMS Description text explaining the PINs 3/6 + Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей п’ятизначний PIN-код на шестизначний PIN-код, який ви оберете самостійно. + + + Six-digit PIN + LABEL ALL_PLATFORMS + Шестизначний PIN-код + + + This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. + INFO ALL_PLATFORMS Description text explaining the PINs 4/6 + Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш п’ятизначний транспортний PIN-код. + + This PIN allows you to prove online that the ID card belongs to you. No one can use your ID card online without this PIN. INFO ALL_PLATFORMS Description text explaining the PINs 5/6 Цей PIN-код дозволяє вам підтверджувати онлайн, що ID-картка належить саме вам. Без цього PIN-коду ніхто не зможе скористатися вашою ID-карткою в Інтернеті. + You can change your six-digit PIN at any time in AusweisApp2. + INFO ALL_PLATFORMS Description text explaining the PINs 6/6 + Ви можете в будь-який момент змінити свій шестизначний PIN-код у додатку AusweisApp2. + + You can use the PIN Reset Service to request a new card PIN free of charge. LABEL ALL_PLATFORMS Ви можете скористатися службою скидання PIN-коду, щоб безкоштовно надіслати запит на новий PIN-код картки. @@ -2924,86 +3040,6 @@ LABEL ALL_PLATFORMS Hint text for PIN but it is unknown. Якщо ви забули PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду. - - The card PIN is a six-digit PIN that you set yourself. You always need this PIN if you want to use the eID function. - INFO ALL_PLATFORMS Answer to the question 'what is the card pin?' - PIN-код картки – це 6-значний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID. - - - You set the card PIN either directly when you picked up your ID card at the citizens' office (Bürgeramt) or later in AusweisApp2 using the five-digit Transport PIN. Only when you have set a six-digit PIN of your own choice can you use the eID function. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the card PIN?' - Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою 5-значного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення 6-значного PIN-коду. - - - For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither "123456", nor your date of birth, nor any other numbers printed on your ID card. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 1/3 - Для свого 6-значного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці. - - - You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN. - INFO ALL_PLATFORMS Answer to the question 'How do I choose a secure PIN?' paragraph 2/3 - Ви можете змінювати свій 6-значний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код. - - - The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 1/3 - 5-значний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки. - - - If you did not set a self-selected six-digit card PIN when you picked up your ID card, you can do so using the Transport PIN. - INFO ALL_PLATFORMS Answer to the question 'What is the Transport PIN?' paragraph 2/3 - Якщо ви не встановили самостійно обраний 6-значний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду. - - - The PUK is a ten-digit number that you can find in the PIN letter that was sent to you by mail after you applied for your ID card. - INFO ALL_PLATFORMS Answer to the question 'Where do I find the PUK?' - PUK-код – це 10-значний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки. - - - The CAN is a six-digit number that can be found on the bottom right of the front of the ID card. - INFO ALL_PLATFORMS Answer to the question 'Where can I find the CAN?' - CAN-код – це 6-значний номер, який можна знайти в нижній правій частині лицьового боку ID-картки. - - - Your ID card comes with a five-digit 'Transport PIN' which you need to replace with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 1/6 - До вашої ID-картки додається 5-значний «транспортний PIN-код», який вам потрібно змінити на 6-значний PIN-код, який ви обираєте самостійно. - - - Five-digit Transport PIN - LABEL ALL_PLATFORMS - 5-значний транспортний PIN-код - - - The five-digit Transport PIN was sent to you by post after you applied for your ID card. - INFO ALL_PLATFORMS Description text explaining the PINs 2/6 - 5-значний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки. - - - The PIN can only be used once. When you set up the eID function, you will replace this five-digit PIN with a six-digit PIN that you choose yourself. - INFO ALL_PLATFORMS Description text explaining the PINs 3/6 - Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей 5-значний PIN-код на 6-значний PIN-код, який ви оберете самостійно. - - - Six-digit PIN - LABEL ALL_PLATFORMS - 6-значний PIN-код - - - This is a number that you choose yourself when you set up the eID function for the first time. It replaces your five-digit Transport PIN. - INFO ALL_PLATFORMS Description text explaining the PINs 4/6 - Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш 5-значний транспортний PIN-код. - - - You can change your six-digit PIN at any time in AusweisApp2. - INFO ALL_PLATFORMS Description text explaining the PINs 6/6 - Ви можете в будь-який момент змінити свій 6-значний PIN-код у додатку AusweisApp2. - - - You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN? - INFO ALL_PLATFORMS - Ви ще не встановили 6-значний PIN-код картки й не можете знайти лист із транспортним PIN-кодом? - PersonalizationController @@ -3316,19 +3352,6 @@ ProviderDetailHistoryItem - today - LABEL ANDROID IOS - сьогодні - - - yesterday - вчора - - - dd.MM.yyyy - дд.ММ.рррр - - Service: LABEL DESKTOP Служба: @@ -3591,10 +3614,6 @@ Натисніть пробіл, щоб створити пару зі смартфоном «%1». - Click to pair - Натисніть, щоб створити пару - - Remove remote device Видаліть віддалений пристрій @@ -3602,38 +3621,70 @@ RemoteReaderView - Paired remote devices - З’єднані віддалені пристрої - - - Available remote devices - Доступні віддалені пристрої - - - Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here. - Тут відображаються лише пристрої, які вже з’єднано або підключено до однієї мережі Wi-Fi і для яких увімкнено віддалену службу. - - - More information - LABEL DESKTOP - Додаткова інформація + Paired devices + З’єднані пристрої + + + Add pairing + Додавання пари + + + Open the %1 on your Smartphone as card reader. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name. + Відкрийте %1 на своєму смартфоні як пристрій читання карток. + + + Both devices have to be connected to the same WiFi. + Обидва пристрої мають бути підключені до однієї мережі Wi-Fi. + + + On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font + Перейдіть на тому пристрої до розділу %1Пристрій читання карток%2, а тоді виберіть %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2. + + + Choose the device in the list to pair it. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4 + Виберіть пристрій у переліку, щоб створити з ним пару. + + + Last connected + Останнє з’єднання + + + Ensure that the %1 on your Smartphone as card reader has at least version %2. + LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name. + Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2. + + + + RemoteServiceController + + You are about to identify yourself towards the following provider using the device "%1": + LABEL ANDROID IOS + Ви збираєтеся ідентифікувати себе за допомогою пристрою «%1» для такого постачальника: + + + Card reader + LABEL ANDROID IOS + Пристрій читання карток + + + Remote service + LABEL ANDROID IOS + Віддалена служба RemoteServiceSettings - Configure remote service - LABEL ANDROID IOS - Налаштувати віддалену службу + Manage pairings + LABEL ANDROID IOS + Керування створенням пари RemoteServiceView - - Remote service - LABEL ANDROID IOS - Віддалена служба - Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code. ERROR ANDROID IOS An error occurred while pairing the device. @@ -3665,87 +3716,97 @@ Очікування підключення - Remote service ready - LABEL ANDROID IOS - Віддалена служба готова - - Waiting for connection from a paired device... INFO ANDROID IOS Очікування підключення від пристрою, з яким створено пару… - Start the remote access in order to make this smartphone visible and use it as a card reader (SaC). + Pairing code: <b>%1</b> + LABEL ANDROID IOS + Код створення пари: <b>%1</b> + + + Enable WiFi + LABEL ANDROID IOS + Увімкнути Wi-Fi + + + Enable NFC + LABEL ANDROID IOS + Увімкнути NFC + + + Pair device + LABEL ANDROID IOS + Створити пару з пристроєм + + + Allow connection + LABEL ANDROID IOS + Дозволити з’єднання + + + You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop. -If you have not already paired a device, start the pairing now to set up this smartphone as a card reader. +To do this you first have to pair that device with this smartphone. INFO ANDROID IOS - Запустіть віддалений доступ, щоб зробити цей смартфон видимим і використовувати його як пристрій читання карток (SaC). + Ви можете використовувати цей смартфон як пристрій читання карток для %1 на інших пристроях, наприклад, на ноутбуці. -Якщо ви ще не створили пару для пристрою, почніть створення пари зараз, щоб налаштувати цей смартфон як пристрій читання карток. - - - Pairing code: <b>%1</b> - LABEL ANDROID IOS - Код створення пари: <b>%1</b> - - - Both of your devices have to be connected to the same WiFi. - INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. - Обидва ваші пристрої має бути підключено до однієї мережі Wi-Fi. - - - Enable WiFi - LABEL ANDROID IOS - Увімкнути Wi-Fi - - - Enable NFC - LABEL ANDROID IOS - Увімкнути NFC - - - Stop remote service - LABEL ANDROID IOS - Зупинити віддалену службу - - - Start remote service - LABEL ANDROID IOS - Запустити віддалену службу - - - Stop pairing - LABEL ANDROID IOS - Зупинити створення пари - - - Start pairing - LABEL ANDROID IOS - Почати створення пари - - - Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC). +Для цього вам потрібно спочатку створити пару між таким пристроєм і цим смартфоном. + + + Card reader + LABEL ANDROID IOS + Пристрій читання карток + + + Paired Devices INFO ANDROID IOS - Введіть код %1 у %2 на своєму іншому пристрої, щоб використовувати свій смартфон як пристрій читання карток (SaC). + З’єднані пристрої + + + Pair new device + LABEL ANDROID IOS + Створення пари з новим пристроєм + + + Waiting for pairing + LABEL ANDROID IOS + Очікування на створення пари + + + Start pairing of a new device + LABEL ANDROID IOS + Почати створення пари з новим пристроєм + + + Where do I enter the pairing code? + LABEL ANDROID IOS + Куди вводити код створення пари? + + + Enter the pairing code %1 in the %2 on your other device. + INFO ANDROID IOS + Введіть код створення пари %1 у %2 на своєму іншому пристрої. + + + Cancel pairing + LABEL ANDROID IOS + Скасувати створення пари + + + Allow a connection with paired devices to use this Smartphone as a card reader or pair another device. + INFO ANDROID IOS + Надайте дозвіл на встановлення зв’язку зі з’єднаними пристроями, щоб використовувати цей смартфон як пристрій читання карток або створити пару з іншим пристроєм. + + + Paired devices may use this Smartphone as a card reader now. + INFO ANDROID IOS + Тепер з’єднані пристрої можуть використовувати цей смартфон як пристрій читання карток. RemoteServiceViewRemote - - Paired devices - LABEL ANDROID IOS - З’єднані пристрої - - - No device is paired. - LABEL ANDROID IOS - Із жодним пристроєм не створено пару. - - - Click to remove device - LABEL ANDROID IOS - Натисніть, щоб видалити пристрій - Remove pairing INFO ANDROID IOS @@ -3762,16 +3823,6 @@ Видалити - Available devices - LABEL ANDROID IOS - Доступні пристрої - - - No unpaired smartphone as card reader (SaC) available. Please make sure that the smartphone as card reader (SaC) functionality in AusweisApp2 on your other device is activated and that both devices are connected to the same WiFi. - INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network. - Немає жодного з’єднаного смартфона як пристрою читання карток (SaC). Переконайтеся, що функцію смартфона як пристрою для читання карток (SaC) активовано в програмі AusweisApp2 на вашому іншому пристрої і що обидва пристрої підключено до однієї мережі Wi-Fi. - - Please connect your WiFi to use another smartphone as card reader (SaC). INFO ANDROID IOS Wifi is not enabled and no new devices can be paired. Підключіть Wi-Fi, щоб використовувати інший смартфон як пристрій читання карток (SaC). @@ -3782,42 +3833,55 @@ Увімкнути Wi-Fi + Pairing code + LABEL ANDROID IOS + Код створення пари + + + Add pairing + LABEL ANDROID IOS + Додавання пари + + + Click to remove device + LABEL ANDROID IOS + Натисніть, щоб видалити пристрій + + + Last connected + LABEL ANDROID IOS + Останнє з’єднання + + + Available + LABEL ANDROID IOS + Доступно + + + Paired devices + LABEL ANDROID IOS + З’єднані пристрої + + Click to pair LABEL ANDROID IOS Натисніть, щоб створити пару - - Pairing mode - INFO ANDROID IOS - Режим створення пари - - - Start the pairing mode on your smartphone if you haven't done it already. - INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone. - Запустіть режим створення пари на своєму смартфоні, якщо ви ще цього не зробили. - - - Pairing code - LABEL ANDROID IOS - Код створення пари + + + RemoteServiceWifiInfo + + Both devices have to be connected to the same WiFi. + INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network. + Обидва пристрої мають бути підключені до однієї мережі Wi-Fi. RemoteWorkflow - The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader. - INFO ANDROID IOS The paired smartphone was removed since it did not respond to connection attempts. It needs to be paired again before using it. - Пару з пристроєм %1 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток. - - Enable WiFi LABEL ANDROID IOS Увімкнути Wi-Fi - - - Pair device - LABEL ANDROID IOS - Створити пару з пристроєм To use the remote service WiFi has to be activated. Please activate WiFi in your device settings. @@ -3825,19 +3889,9 @@ Для використання віддаленої служби має бути активовано Wi-Fi. Активуйте Wi-Fi у параметрах пристрою. - No paired smartphone as card reader (SaC) with activated "remote service" available. - INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. - Немає жодного з’єднаного смартфона як пристрою читання карток (SaC) з активованою «віддаленою службою». - - Wifi disabled LABEL ANDROID IOS Wi-Fi вимкнено - - - Waiting for connection - LABEL ANDROID IOS - Очікування підключення Determine card @@ -3854,6 +3908,21 @@ INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted. Підключено до %1. Розташуйте інтерфейс NFC смартфона на своїй ID-картці. + + Manage pairings + LABEL ANDROID IOS + Керування створенням пари + + + No smartphone as card reader connected + LABEL ANDROID IOS + Не з’єднано жоден смартфон як пристрій читання карток + + + Allow a connection on a paired smartphone or pair a new smartphone. + INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature. + Надайте дозвіл на встановлення зв’язку на з’єднаному смартфоні або створіть пару з новим смартфоном. + ResultErrorView @@ -4249,16 +4318,6 @@ Введіть PIN-код на цьому пристрої - Remote card reader - LABEL ANDROID IOS - Віддалений пристрій читання карток - - - Configure remote service for another device - LABEL ANDROID IOS - Налаштувати віддалену службу для іншого пристрою - - Save history LABEL ANDROID IOS Зберегти історію @@ -4374,6 +4433,26 @@ 15 days old Logfile LABEL ALL_PLATFORMS Файл журналу строком 15 днів + + + Show requested rights on this device as well + LABEL ANDROID IOS + Показати запит на права також на цьому пристрої + + + Show access rights + LABEL ANDROID IOS + Показати права доступу + + + Manage paired devices and add new devices + LABEL ANDROID IOS + Керування з’єднаними пристроями й додавання нових пристроїв + + + Manage pairings + LABEL ANDROID IOS + Керування створенням пари @@ -4758,6 +4837,15 @@ Continue Продовжити + + You have not yet set up a Smart-eID or it is no longer usable. + +To proceed use your ID card by selecting the NFC interface. If you want to set up a Smart-eID instead, please abort the current process and start the Smart-eID setup from the main screen. + LABEL ANDROID IOS + Ви ще не налаштували Smart-eID або він більше не придатний для використання. + +Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана. + StoreFeedbackPopup @@ -5158,7 +5246,7 @@ You can read our <b>FAQs</b> or <b>write</b> to us... LABEL ANDROID IOS - Ознайомтеся з розділом <b>«Запитання й відповіді»</b> або <b>напишіть</b> нам… + Ознайомтеся з розділом «Запитання й відповіді» або <b>напишіть</b> нам… or @@ -5325,9 +5413,9 @@ Обидва пристрої має бути підключено до однієї мережі Wi-Fi - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні… + Now choose "Card reader" in the AusweisApp2 on your smartphone... + LABEL ANDROID IOS + Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні… Now @@ -5335,9 +5423,9 @@ Зараз - Start pairing - LABEL ANDROID IOS - Почати створення пари + Pair device + LABEL ANDROID IOS + Створити пару з пристроєм Pairing code @@ -5362,7 +5450,7 @@ Select the <b>Smartphone as card reader</b> tab. LABEL ANDROID IOS - Виберіть вкладку <b>Смартфон як пристрій читання карток</b>. + Виберіть вкладку «Смартфон як пристрій читання карток». Select smartphone from list @@ -5475,7 +5563,7 @@ Install AusweisApp2 on both your device without NFC <b>and</b> your smartphone with NFC capability. LABEL ANDROID IOS - Установіть програму AusweisApp2 на пристрої без NFC <b>та</b> смартфоні з функцією NFC. + Установіть програму AusweisApp2 на пристрої <b>без</b> NFC та смартфоні з функцією NFC. Both devices have to be connected to the same WiFi network @@ -5483,9 +5571,9 @@ Обидва пристрої має бути підключено до однієї мережі Wi-Fi - Now choose "Remote" in the AusweisApp2 on your smartphone... - LABEL ANDROID IOS - Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні… + Now choose "Card reader" in the AusweisApp2 on your smartphone... + LABEL ANDROID IOS + Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні… Now @@ -5493,9 +5581,9 @@ Зараз - Start pairing - LABEL ANDROID IOS - Почати створення пари + Pair device + LABEL ANDROID IOS + Створити пару з пристроєм Pairing code @@ -5513,19 +5601,19 @@ Під час першого використання смартфона як пристрою читання карток (SaC) iOS запитає вашого дозволу на доступ до локальної мережі. Цей дозвіл потрібен для пошуку вашого SaC та підключення до нього. Після першого запиту ви завжди можете отримати доступ до дозволу в параметрах iOS для цієї програми. - Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>. + Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>. LABEL IOS - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть <b>Налаштувати віддалену службу</b>. + Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть «Керування створенням пари». Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>. LABEL ANDROID - Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть <b>Смартфон як пристрій читання карток</b>. + Тепер відкрийте програму AusweisApp2 на пристрої <b>без</b> NFC і виберіть «Смартфон як пристрій читання карток». Now select <b>Settings</b>. LABEL ANDROID IOS - Тепер виберіть <b>Параметри</b>. + Тепер виберіть «Параметри». Choose smartphone from list @@ -5681,7 +5769,7 @@ On every authentication you get displayed <b>who</b> wants to access <b>which</b> data LABEL ANDROID IOS - Під час кожної автентифікації відображаються відомості, <b>хто</b> хоче отримати доступ та до <b>яких</b> даних, + Під час кожної автентифікації відображаються відомості, <b>хто</b> хоче отримати доступ та до <b>яких</b> даних. and you consent to the request with your six-digit PIN. @@ -5744,7 +5832,7 @@ The <b>integrated self-authentication</b> is a special service to view the data saved on your ID card. LABEL ANDROID IOS - Служба <b>вбудованої самоавтентифікації</b> – це спеціальна служба для перегляду даних, збережених на ID-картці. + <b>Служба вбудованої самоавтентифікації</b> – це спеціальна служба для перегляду даних, збережених на ID-картці. And this is how it works @@ -5923,6 +6011,24 @@ Checksum link: LABEL DESKTOP Link to download checksum to verify the downloaded update file. Посилання на контрольну суму: + + + + Utils + + today + LABEL ALL_PLATFORMS + сьогодні + + + yesterday + LABEL ALL_PLATFORMS + вчора + + + dd.MM.yyyy + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -6318,7 +6424,7 @@ d. MMMM yyyy, hh:mm:ss AP - LABEL DESKTOP Timestamp, formatted according to the selected language + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString d MMMM yyyy р., hh:mm:ss @@ -6528,8 +6634,8 @@ dd.MM.yyyy, hh:mm:ss - LABEL DESKTOP Timestamp - дд.ММ.рррр, гг:хх:сс + LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + dd.MM.yyyy, hh:mm:ss Last connection: %1 @@ -6793,9 +6899,9 @@ Не вдалося виконати автентифікацію. - Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. - ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - Ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження. + The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction. + ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + Довжину даних, надісланих на ID-картку, відхилено. Дані неправильні або ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження. No certificate description available. @@ -7095,7 +7201,8 @@ governikus::HistoryModelSearchFilter dd.MM.yyyy - дд.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy @@ -7147,7 +7254,8 @@ dd.MM.yyyy hh:mm:ss - дд.ММ.рррр гг:хх:сс + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString + dd.MM.yyyy hh:mm:ss The logfile is disabled. @@ -7206,7 +7314,8 @@ governikus::NotificationModel hh:mm:ss - гг:хх:сс + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString + hh:mm:ss @@ -7299,7 +7408,7 @@ dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7324,12 +7433,12 @@ dd.MM.yyyy - LABEL ALL_PLATFORMS - дд.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy hh:mm AP - LABEL ALL_PLATFORMS + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm @@ -7475,6 +7584,7 @@ hh:mm:ss AP + LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString hh:mm:ss @@ -7531,11 +7641,6 @@ З’єднаний, але не підтримується - Paired, but unavailable - LABEL ALL_PLATFORMS - З’єднаний, але недоступний - - Unsupported LABEL ALL_PLATFORMS Не підтримується @@ -7547,6 +7652,7 @@ dd.MM.yyyy hh:mm AP + LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString dd.MM.yyyy hh:mm @@ -7558,6 +7664,16 @@ No smartphone as card reader (Sac) available. Please make sure to activate the "remote service" on your smartphone and to connect both devices to the same WiFi. See %1 for details of use. INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network. Немає жодного смартфона як пристрою читання карток (SaC). Переконайтеся, що ви активували «віддалену службу» на своєму смартфоні та підключили обидва пристрої до однієї мережі Wi-Fi. Відомості про використання див. в розділі %1. + + + Unavailable + LABEL ALL_PLATFORMS + Недоступно + + + Click to pair + LABEL ALL_PLATFORMS + Натисніть, щоб створити пару @@ -7590,6 +7706,11 @@ Увімкніть NFC, щоб використовувати свій смартфон як пристрій читання карток (SaC). + + Pairing with %1 successful. + LABEL ALL_PLATFORMS + Створено пару з %1. + governikus::RemoteServiceSettings @@ -7613,15 +7734,18 @@ dd.MM.yyyy - дд.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString + dd.MM.yyyy xx.MM.yyyy - xx.ММ.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day + xx.MM.yyyy xx.xx.yyyy - xx.xx.рррр + LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month + xx.xx.yyyy Family name @@ -7761,6 +7885,14 @@ Access denied. INFO IOS The current session was interrupted because of a wrong password. Немає доступу. + + + + governikus::StateEstablishPaceChannel + + The secure channel is opened + INFO ALL_PLATFORMS First status message after the PIN was entered. + Захищений канал відкрито @@ -8096,7 +8228,7 @@ The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface. INFO DESKTOP Content of the popup that is shown when the AA2 is closed and the close/minimize info was not disabled. macOS specific if autostart is enabled. - Програма залишається доступною через піктограму в системному лотку. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача. + Програма залишається доступною через піктограму на панелі меню. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача. diff --git a/resources/updatable-files/supported-providers.json b/resources/updatable-files/supported-providers.json index 132632c..5ed26ee 100644 --- a/resources/updatable-files/supported-providers.json +++ b/resources/updatable-files/supported-providers.json @@ -219,18 +219,16 @@ "": "Auskunft aus den Zentralen Registern des Kraftfahrt-Bundesamtes" }, "longDescription": { - "": "Mit der Anwendung können Privatpersonen eine Auskunft aus dem Fahreignungsregister (Punkteauskunft), dem Zentralen Fahrzeugregister (Fahrzeugzulassungen), dem Zentralen Fahrerlaubnisregister (Führerschein) sowie dem Berufskraftfahrerqualifikationsregister des Kraftfahrt-Bundesamtes erhalten. Diese umfasst ausgewählte Daten, die zu der jeweiligen Person gespeichert sind.
  • Die Online-Auskunft aus dem Zentralen Fahrzeugregister umfasst Informationen zur Fahrzeugbeschreibung, den Halterdaten, der Haftpflichtversicherung, der letzten Haupt- bzw. Sicherheitsüberprüfung, der Fahrzeughistorie und den zulassungsrechtlich relevanten Ereignissen. Daten von vormaligen Haltern und interne Verwaltungsdaten sind von der Auskunft ausgenommen.
  • Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.
  • Die Online-Auskunft aus dem Zentralen Fahrerlaubnisregister umfasst Informationen zu Fahrerlaubnissen, die seit dem 01.01.1999 erteilt, erweitert oder umgeschrieben wurden. Über die anderen vor dem 01.01.1999 ausgestellten Führerscheine führt nur die jeweils ausstellende Fahrerlaubnisbehörde eine Kartei/Datei.
  • Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.
" - }, - "address": "https://www.kba-online.de/registerauskunft/ora/web", + "": "Mit der Anwendung können Privatpersonen eine Auskunft aus dem Fahreignungsregister (Punkteauskunft), dem Zentralen Fahrzeugregister (Fahrzeugzulassungen), dem Zentralen Fahrerlaubnisregister (Führerschein) sowie dem Berufskraftfahrerqualifikationsregister des Kraftfahrt-Bundesamtes erhalten. Diese umfasst ausgewählte Daten, die zu der jeweiligen Person gespeichert sind.
  • Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.
  • Die Online-Auskunft aus dem Zentralen Fahrzeugregister umfasst Informationen zur Fahrzeugbeschreibung, den Halterdaten, der Haftpflichtversicherung, der letzten Haupt- bzw. Sicherheitsüberprüfung, der Fahrzeughistorie und den zulassungsrechtlich relevanten Ergebnissen. Daten von vormaligen Haltern und interne Verwaltungsdaten sind von der Auskunft ausgenommen.
  • Die Online-Auskunft aus dem Zentralen Fahrerlaubnisregister umfasst Informationen zu Fahrerlaubnissen, die seit dem 01.01.1999 erteilt, erweitert oder umgeschrieben wurden. Über die anderen vor dem 01.01.1999 ausgestellten Führerscheine führt nur die jeweils ausstellende Fahrerlaubnisbehörde eine Kartei/Datei.
  • Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.
" + }, + "address": "https://www.kba-online.de/registerauskunft/app", "homepage": "https://www.kba.de", "phone": "+49 461 316 0", "email": "kba@kba.de", "postalAddress": "Kraftfahrt-Bundesamt
Fördestraße 16
24944 Flensburg", - "icon": "KraftfahrtBundesamt_icon.png", - "category": "citizen", - "subjectUrls": [ - "https://www.kba-online.de" - ] + "icon": "KraftfahrtBundesamt_icon.svg", + "category": "citizen", + "subjectUrlInfo": "Using service from bundID (https://id.bund.de)." }, { "shortName": { @@ -289,9 +287,7 @@ "postalAddress": "Ministerium für Wissenschaft, Energie, Klimaschutz und Umwelt des Landes Sachsen-Anhalt
Leipziger Straße 58
39112 Magdeburg", "icon": "BafoegDigital_icon.svg", "category": "citizen", - "subjectUrls": [ - "https://id.bund.de" - ] + "subjectUrlInfo": "Using service from bundID (https://id.bund.de)." }, { "shortName": { @@ -463,24 +459,6 @@ }, { "shortName": { - "": "Stadt Magdeburg - iKFZ" - }, - "longName": { - "": "Stadt Magdeburg - Internetbasierte Fahrzeugzulassung" - }, - "longDescription": { - "": "Die internetbasierte Außerbetriebsetzung und Wiederzulassung eines Kraftfahrzeuges können über das Portal der Landeshauptstadt Magdeburg beantragt werden." - }, - "address": "https://www.magdeburg.de/loadDocument.phtml?ObjSvrID=37&ObjID=27929", - "homepage": "https://www.magdeburg.de/Start/B%C3%BCrger-Stadt/Verwaltung-Service/B%C3%BCrgerService", - "phone": "+49 391 54 00", - "email": "info@magdeburg.de", - "postalAddress": "Landeshauptstadt Magdeburg
Alter Markt 6
39104 Magdeburg", - "category": "citizen", - "subjectUrlInfo": "Using service from Serviceportal Sachsen-Anhalt (https://bk.sachsen-anhalt-connect.de)" - }, - { - "shortName": { "": "Stadt Netphen" }, "longName": { @@ -656,7 +634,8 @@ "category": "citizen", "subjectUrls": [ "https://www.buergerserviceportal.de", - "https://bayernid.freistaat.bayern" + "https://bayernid.freistaat.bayern", + "https://id.bayernportal.de" ] }, { @@ -2129,20 +2108,22 @@ }, { "shortName": { - "": "Online-Bürgerdienste Nürnberg" - }, - "longName": { - "": "Online-Bürgerdienste der Stadt Nürnberg" - }, - "longDescription": { - "": "Die Stadt Nürnberg bietet Ihnen mit ihrem Bürgerserviceportal ,Mein.Nürnberg' erstmals die Möglichkeit, Ihre Verwaltungsangelegenheiten komplett elektronisch abzuwickeln - von der Antragstellung bis zur Rückmeldung der Bescheide oder Schriftstücke in Ihren persönlichen Bereich auf dem Portal. Alle Online-Dienste der Stadt Nürnberg wurden zudem für die Nutzung mit mobilen Endgeräten optimiert.
Bei immer mehr Verfahren akzeptiert die Stadtverwaltung einen Unterschriftersatz durch die Online-Ausweisfunktion.
Jeder Online-Dienst der Stadt Nürnberg, der die Online-Ausweisfunktion nutzt, ist an dem Hinweis 'mit eID' erkennbar. Derzeit sind dies z. B.:
  • Aufenthaltstitel beantragen
  • Gaststättenrechtliche Erlaubnis für den Ausschank von Alkohol beantragen
  • Hunde - Negativzeugnis für Kampfhunde beantragen
  • Kfz-Halterauskunft beantragen
  • Melderegister - Widerspruch gegen Datenübermittlung
  • Veranstaltung, Messe, Markt beantragen
" - }, - "address": "https://www.nuernberg.de/internet/onlinedienste", - "homepage": "https://www.nuernberg.de", - "phone": "+49 9 11 2 31 8613", - "email": "poststelle@stadt.nuernberg.de", - "postalAddress": "Amt für Organisation, Informationsverarbeitung und Zentrale Dienste
E-Government-Büro
Rathausplatz 2
III. OG
90403 Nürnberg", - "category": "citizen", + "": "Mein Nürnberg" + }, + "longName": { + "": "Mein Nürnberg - Die digitale Serviceplattform der Stadt Nürnberg" + }, + "longDescription": { + "": "Über die Serviceplattform 'Mein Nürnberg' können Sie schnell, einfach und von zuhause aus Ihre Behördengänge erledigen! Kein langes Anstehen, Warten oder Nummer Ziehen. Mit einem persönlichen 'Mein Nürnberg'-Account bleiben Sie bequem zuhause und erledigen alles von dort - und das rund um die Uhr. Sie sparen sich nicht nur den Weg in die Behörde, sondern können auch den aktuellen Status Ihres Antrages einsehen. Melden Sie sich jetzt an! Das Angebot an Online-Diensten wird ständig erweitert. Ob Sie Ihr Anliegen bereits digital erledigen können, finden Sie über den Behördenwegweiser Nürnberg oder direkt über die Internetseiten der jeweiligen Ämter heraus." + }, + "address": "https://www.nuernberg.de/internet/mein_nuernberg", + "homepage": "https://www.nuernberg.de/internet/stadtportal", + "phone": "+49 9 11 2 31 4 50 00", + "email": "online-services@stadt.nuernberg.de", + "postalAddress": "Stadt Nürnberg
Amt für Digitalisierung und Prozessorganisation Rathausplatz 2
90403 Nürnberg", + "category": "citizen", + "image": "MeinNuernberg_image.jpg", + "icon": "MeinNuernberg_icon.png", "subjectUrls": [ "https://meinkonto.nuernberg.de" ] @@ -2345,6 +2326,159 @@ "subjectUrls": [ "https://www.foerderportal-zeus.de" ] + }, + { + "shortName": { + "": "Landkreis Elbe-Elster" + }, + "longName": { + "": "Landkreis Elbe-Elster - Online Dienste" + }, + "longDescription": { + "": "Bürgerinnen und Bürger im Landkreis Elbe-Elster können viele Behördengänge digital erledigen.
Je nach Anforderung der jeweiligen Verwaltungsleistung benötigen Sie ein kostenloses Bürgerkonto 'BundID'. Damit können Sie sich elektronisch identifizieren. Sie weisen sich also online gegenüber diesen Leistungen aus." + }, + "address": "https://www.lkee.de/Service-Verwaltung/Online-Dienste", + "homepage": "https://www.lkee.de", + "phone": "+49 3535 460", + "email": "eap@lkee.de", + "postalAddress": "Landkreis Elbe-Elster
Der Landrat
Ludwig-Jahn-Str. 2
04916 Herzberg / Elster", + "image": "lkee_image.jpg", + "icon": "lkee_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Landesportal Brandenburg (https://e-ident.brandenburg.de)." + }, + { + "shortName": { + "": "Online-Services der Landeshauptstadt München" + }, + "longName": { + "": "Online-Services der Landeshauptstadt München" + }, + "longDescription": { + "": "Die Landeshauptstadt München verfügt über eine Vielzahl an Online-Services. Diese können Sie hier einsehen und nutzen." + }, + "address": "https://stadt.muenchen.de/infos/online-services.html", + "homepage": "https://www.muenchen.de", + "email": "rathaus@muenchen.de", + "postalAddress": "Landeshauptstadt München
80313 München", + "image": "LandeshauptstadtMuenchen_image.png", + "icon": "LandeshauptstadtMuenchen_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "Antrag auf Elterngeld in Bayern" + }, + "longName": { + "": "Antrag auf Elterngeld in Bayern" + }, + "longDescription": { + "": "Den Antrag auf Elterngeld können Sie in Bayern bei der Landesbehörde Zentrum Bayern Familie und Soziales (ZBFS) stellen. Die Abfragen im Online-Verfahren werden individuell auf Ihre Angaben abgestimmt und Sie erhalten eine Checkliste mit den benötigten Unterlagen. Der Antrag kann digital unterschieben werden." + }, + "address": "https://www.elterngeld.bayern.de/onlineantrag/default.aspx", + "homepage": "https://www.zbfs.bayern.de", + "email": "poststelle@zbfs.bayern.de", + "postalAddress": "Zentrum Bayern Familie und Soziales
95440 Bayreuth", + "icon": "ZBFS_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." + }, + { + "shortName": { + "": "bundID" + }, + "longName": { + "": "bundID - Ihr Zugang zur digitalen Verwaltung. Einfach. Sicher." + }, + "address": "https://id.bund.de", + "homepage": "https://id.bund.de", + "longDescription": { + "": " Die BundID bietet Ihnen ein zentrales Konto zur Identifizierung für alle Ihre Online-Anträge (z. B. mit einem Online-Ausweis). Sie können das Formular Ihres Online-Antrags durch das Hinterlegen Ihrer persönlichen Daten vorausfüllen lassen. Das spart Zeit, ist sicher und bewahrt Sie vor Tippfehlern.

Sie erhalten alle Bescheide und Nachrichten in Bezug auf den Online-Antrag bequem in Ihr elektronisches Postfach in Ihrem BundID-Konto." + }, + "postalAddress": "Bundesministerium des Innern und für Heimat
Alt-Moabit 140
10557 Berlin", + "category": "citizen", + "subjectUrls": [ + "https://id.bund.de" + ] + }, + { + "shortName": { + "": "Stadt Oberhausen" + }, + "longName": { + "": "Stadt Oberhausen" + }, + "address": "https://serviceportal.oberhausen.de/home", + "homepage": "https://www.oberhausen.de", + "email": "info@oberhausen.de", + "longDescription": { + "": "Im Serviceportal der Stadt Oberhausen finden Sie alle Online-Leistungen der Stadtverwaltung, von der Beantragung einer Personenstandsurkunde über die Anmeldung eines Autos bis zur Beantragung eines Bewohnerparkausweises. Einzelne Leistungen erfordern hierbei auch die Authentifizierung mit dem elektronischen Personalausweis und der AusweisApp2." + }, + "postalAddress": "Stadt Oberhausen
Schwartzstraße 72
46042 Oberhausen", + "icon": "StadtOberhausen_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)." + }, + { + "shortName": { + "": "Digitale Rentenübersicht" + }, + "longName": { + "": "Digitale Rentenübersicht - Zentrale Stelle für die Digitale Rentenübersicht (Deutsche Rentenversicherung Bund)" + }, + "address": "https://app.rentenuebersicht.de", + "homepage": "https://www.rentenuebersicht.de", + "phone": "+49 800 1000 787", + "email": "digitalerentenuebersicht@drv-bund.de", + "longDescription": { + "": "Mit der Online-Ausweisfunktion im neuen Personalausweis können Sie ...
  • Ihre individuellen Altersvorsorge-Ansprüche der gesetzlichen, betrieblichen und privaten Altersvorsorge bequem digital abrufen und
  • die Informationen zum Stand Ihrer Altersvorsorge-Ansprüche als Grundlage für eine weitere unabhängige Beratung herunterladen.
" + }, + "postalAddress": "Deutsche Rentenversicherung Bund Zentrale Stelle für die Digitale Rentenübersicht
10868 Berlin", + "icon": "DigitaleRentenuebersicht_icon.svg", + "category": "citizen", + "subjectUrls": [ + "https://login.deutsche-rentenversicherung.de" + ] + }, + { + "shortName": { + "": "Zoll-Portal" + }, + "longName": { + "": "Zoll-Portal" + }, + "address": "https://www.zoll-portal.de", + "homepage": "https://www.zoll-portal.de", + "email": "Zoll-Portal@zoll.bund.de", + "longDescription": { + "": "Das Zoll-Portal bietet Ihnen einen einfachen und effizienten Zugang zu den Dienstleistungen des Zolls (z.B. Kraftfahrzeugsteuer, Agrardieselvergütung oder Energiesteuer). Nach einmaliger Registrierung können Sie Anträge online abwickeln und Bescheide rechtssicher abrufen. Verwenden Sie für die Registrierung und den Login Ihre Online-Ausweisfunktion und Sie können alle Dienstleistungen und Features uneingeschränkt in Anspruch nehmen." + }, + "postalAddress": "Generalzolldirektion
Am Propsthof 78a
53121 Bonn", + "icon": "ZollPortal_icon.svg", + "image": "ZollPortal_image.svg", + "category": "citizen", + "subjectUrls": [ + "https://www.zoll-portal.de" + ] + }, + { + "shortName": { + "": "Stadt Augsburg - Digitale Bürgerservices nutzen" + }, + "longName": { + "": "Stadt Augsburg - Digitale Bürgerservices nutzen" + }, + "address": "https://www.augsburg.de/online-services", + "homepage": "https://www.augsburg.de", + "email": "augsburg@augsburg.de", + "longDescription": { + "": "Für viele Leistungen ist der Weg ins Amt nicht nötig: Sie können zahlreiche Leistungen online beantragen und falls nötig bequem von zu Hause aus bezahlen. Eine Liste der Online-Services finden Sie auf der Webseite der Stadt Augsburg.

Voraussetzung für einige Online-Services ist die BayernID. Zur Registrierung können Sie Ihren Online-Ausweis mit dazugehöriger PIN, einem geeigneten Smartphone oder Tablet und der installierten AusweisApp2 nutzen.

Informationen zur Registrierung in der BayernID können Sie nachlesen (https://id.bayernportal.de/).

Ein Beispiel ist die internetbasierte Fahrzeugzulassung und Fahrzeugabmeldung, die von der Kfz-Zulassungsbehörde in Augsburg angeboten wird. Weitere Informationen finden Sie auf der Internetseite der Online-Zulassungsbehörde." + }, + "postalAddress": "Stadt Augsburg
Rathausplatz 1
86150 Augsburg", + "icon": "StadtAugsburg_icon.png", + "category": "citizen", + "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)." } ] } diff --git a/src/android/MainActivity.java b/src/android/MainActivity.java index b4d2d60..4ad65b3 100644 --- a/src/android/MainActivity.java +++ b/src/android/MainActivity.java @@ -207,11 +207,22 @@ } + private void convertChromeOsIntent(Intent pIntent) + { + if (pIntent != null && pIntent.getAction().equals("org.chromium.arc.intent.action.VIEW")) + { + LogHandler.getLogger().info("Convert Intent action " + pIntent.getAction() + " to " + Intent.ACTION_VIEW); + pIntent.setAction(Intent.ACTION_VIEW); + } + } + + @Override public void onCreate(Bundle savedInstanceState) { setTheme(R.style.AppTheme); + convertChromeOsIntent(getIntent()); LogHandler.getLogger().info("onCreate: " + getIntent()); super.onCreate(savedInstanceState); @@ -256,6 +267,7 @@ @Override protected void onNewIntent(Intent newIntent) { + convertChromeOsIntent(newIntent); cIntent = newIntent; setIntent(newIntent); LogHandler.getLogger().info("onNewIntent: " + newIntent); diff --git a/src/card/base/CardConnectionWorker.cpp b/src/card/base/CardConnectionWorker.cpp index bb159fe..37aaa89 100644 --- a/src/card/base/CardConnectionWorker.cpp +++ b/src/card/base/CardConnectionWorker.cpp @@ -133,7 +133,7 @@ ResponseApduResult result = card->transmit(commandApdu); if (result.mResponseApdu.getStatusCode() == StatusCode::WRONG_LENGTH) { - return {CardReturnCode::EXTENDED_LENGTH_MISSING}; + return {CardReturnCode::WRONG_LENGTH}; } if (mSecureMessaging) @@ -141,7 +141,7 @@ result.mResponseApdu = mSecureMessaging->decrypt(result.mResponseApdu); if (result.mResponseApdu.isEmpty()) { - qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must no be re-used."; + qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must not be re-used."; stopSecureMessaging(); return {CardReturnCode::COMMAND_FAILED}; diff --git a/src/card/base/apdu/CommandApdu.cpp b/src/card/base/apdu/CommandApdu.cpp index 7ad0b9b..24b3e56 100644 --- a/src/card/base/apdu/CommandApdu.cpp +++ b/src/card/base/apdu/CommandApdu.cpp @@ -12,13 +12,6 @@ Q_DECLARE_LOGGING_CATEGORY(card) - -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #define HEX hex -#else - #define HEX Qt::hex -#endif - constexpr std::byte CLA {0x00}; constexpr std::byte CLA_PROPRIETARY {0x80}; @@ -128,12 +121,12 @@ if (mData.size() > EXTENDED_MAX_LC) { - qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC; + qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC; } if (mLe > EXTENDED_MAX_LE) { - qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE; + qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE; } } @@ -148,12 +141,12 @@ { if (mData.size() > EXTENDED_MAX_LC) { - qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC; + qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC; } if (mLe > EXTENDED_MAX_LE) { - qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE; + qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE; } } @@ -210,7 +203,7 @@ return Ins(mIns); } - qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << HEX << mIns; + qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << Qt::hex << mIns; return Ins::UNKNOWN; } diff --git a/src/card/base/command/DidAuthenticateEAC2Command.cpp b/src/card/base/command/DidAuthenticateEAC2Command.cpp index b4936f8..cea6160 100644 --- a/src/card/base/command/DidAuthenticateEAC2Command.cpp +++ b/src/card/base/command/DidAuthenticateEAC2Command.cpp @@ -190,7 +190,7 @@ break; case StatusCode::WRONG_LENGTH: - return CardReturnCode::EXTENDED_LENGTH_MISSING; + return CardReturnCode::WRONG_LENGTH; default: qCWarning(card) << "TA PSO:Verify Certificate failed:" << psoResult.getStatusCode(); diff --git a/src/card/base/pinpad/EstablishPaceChannelOutput.cpp b/src/card/base/pinpad/EstablishPaceChannelOutput.cpp index d2e6635..57f66e2 100644 --- a/src/card/base/pinpad/EstablishPaceChannelOutput.cpp +++ b/src/card/base/pinpad/EstablishPaceChannelOutput.cpp @@ -115,7 +115,7 @@ case CardReturnCode::PUK_INOPERATIVE: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: return EstablishPaceChannelErrorCode::UnexpectedDataInInput; case CardReturnCode::INVALID_CAN: diff --git a/src/card/simulator/SimulatorReaderManagerPlugIn.cpp b/src/card/simulator/SimulatorReaderManagerPlugIn.cpp index 43afb95..38f0cc2 100644 --- a/src/card/simulator/SimulatorReaderManagerPlugIn.cpp +++ b/src/card/simulator/SimulatorReaderManagerPlugIn.cpp @@ -60,9 +60,12 @@ if (mSimulatorReader) { mSimulatorReader->disconnectReader(pError); + + auto info = mSimulatorReader->getReaderInfo(); + mSimulatorReader.reset(); + Q_EMIT fireReaderRemoved(info); } ReaderManagerPlugIn::stopScan(pError); - mSimulatorReader.reset(); } diff --git a/src/card/smart/SmartManager.cpp b/src/card/smart/SmartManager.cpp index 06e7bcb..62edfb1 100644 --- a/src/card/smart/SmartManager.cpp +++ b/src/card/smart/SmartManager.cpp @@ -395,13 +395,6 @@ } -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #define HEX hex -#else - #define HEX Qt::hex -#endif - - QDebug operator<<(QDebug pDbg, const EidStatus& pStatus) { const auto& toString = [](const EidStatus& status){ @@ -430,7 +423,7 @@ }; QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pStatus) << " 0x" << HEX << static_cast(pStatus); + pDbg.nospace() << toString(pStatus) << " 0x" << Qt::hex << static_cast(pStatus); return pDbg; } @@ -460,7 +453,7 @@ }; QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pInfo) << " 0x" << HEX << static_cast(pInfo); + pDbg.nospace() << toString(pInfo) << " 0x" << Qt::hex << static_cast(pInfo); return pDbg; } @@ -493,6 +486,6 @@ }; QDebugStateSaver saver(pDbg); - pDbg.nospace() << toString(pResult) << " 0x" << HEX << static_cast(pResult); + pDbg.nospace() << toString(pResult) << " 0x" << Qt::hex << static_cast(pResult); return pDbg; } diff --git a/src/diagnosis/DiagnosisConnectionTest.cpp b/src/diagnosis/DiagnosisConnectionTest.cpp index b4f1be9..93d7e61 100644 --- a/src/diagnosis/DiagnosisConnectionTest.cpp +++ b/src/diagnosis/DiagnosisConnectionTest.cpp @@ -159,7 +159,14 @@ mConnectionTestWithProxyDone = false; mConnectionTestWithoutProxyDone = false; - const auto& proxy = QNetworkProxy::applicationProxy(); + const QUrl& testUrl = QUrl(Env::getSingleton()->getUpdateServerBaseUrl()); + const auto& proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(testUrl)); + const auto& proxy = proxies.constFirst(); + if (proxies.size() > 1) + { + qDebug() << "More than one proxy found, using first proxy:" << proxy; + } + if (proxy.type() == QNetworkProxy::ProxyType::NoProxy) { mIsProxySet = false; @@ -175,7 +182,6 @@ mProxyCapabilities = getProxyCapabilitiesAsQString(proxy.capabilities()); } - const QUrl& testUrl = QUrl(Env::getSingleton()->getUpdateServerBaseUrl()); if (mIsProxySet) { mPingSocketToProxy.reset(); diff --git a/src/diagnosis/DiagnosisModel.cpp b/src/diagnosis/DiagnosisModel.cpp index bb2f13a..d6f4315 100644 --- a/src/diagnosis/DiagnosisModel.cpp +++ b/src/diagnosis/DiagnosisModel.cpp @@ -339,7 +339,7 @@ QDateTime timestampValue = mContext->getTimestamp(); if (timestampValue.isValid()) { - //: LABEL DESKTOP Timestamp, formatted according to the selected language + //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString QString timestamp = LanguageLoader::getInstance().getUsedLocale().toString(timestampValue, tr("d. MMMM yyyy, hh:mm:ss AP")); //: LABEL DESKTOP mTimestampSection << ContentItem(tr("Time of diagnosis"), timestamp); @@ -706,7 +706,7 @@ if (!info.getFingerprint().isEmpty()) { - //: LABEL DESKTOP Timestamp + //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const QString& timestamp = LanguageLoader::getInstance().getUsedLocale().toString(info.getLastConnected(), tr("dd.MM.yyyy, hh:mm:ss")); //: LABEL DESKTOP mRemoteDeviceSection << ContentItem(info.getNameEscaped(), tr("Last connection: %1").arg(timestamp)); diff --git a/src/export/PdfExporter.cpp b/src/export/PdfExporter.cpp index c22ccd0..8cbc97c 100644 --- a/src/export/PdfExporter.cpp +++ b/src/export/PdfExporter.cpp @@ -113,7 +113,7 @@ {tr("Date"), //: LABEL ALL_PLATFORMS tr("Details")}); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP"); const auto& infos = Env::getSingleton()->getHistorySettings().getHistoryInfos(); for (const auto& entry : infos) @@ -142,9 +142,9 @@ closeTable(); const auto& now = QDateTime::currentDateTime(); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString QString date = locale.toString(now, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString QString time = locale.toString(now, tr("hh:mm AP")); //: LABEL ALL_PLATFORMS const auto& headline = tr("At %1 %2 the following data were saved:").arg(date, time); @@ -181,9 +181,9 @@ closeTable(); const auto& locale = LanguageLoader::getInstance().getUsedLocale(); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString QString date = locale.toString(pDate, tr("dd.MM.yyyy")); - //: LABEL ALL_PLATFORMS + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString QString time = locale.toString(pDate, tr("hh:mm AP")); //: LABEL ALL_PLATFORMS const auto& headline = tr("At %1 %2 the following data has been read out of your ID card:").arg(date, time); diff --git a/src/external/smart/README.md b/src/external/smart/README.md deleted file mode 100644 index 0e5ea87..0000000 --- a/src/external/smart/README.md +++ /dev/null @@ -1,56 +0,0 @@ -eid-applet-service jni bridge -============================= - -- Current `eid_applet_interface.h` version: `0.16.0` -- Current `eid-applet-service-lib.aar` version: `0.10.3-180` - -## Availability - -If you have access to the `partner.bdr.de` network, the -`eid-applet-service-lib` library is also available through the -artifactory maven repository. `app/build.gradle` integration: - -```gradle - implementation "de.bdr.android.eid-applet-service-lib:eid-applet-service-lib:0.10.3-180" -``` - -Parse and set the credentials within the root `build.gradle`. - -```gradle -allprojects { - repositories { - // ... - maven { - url 'https://partner.bdr.de/artifactory/mid-mvn/' - credentials { - username "Your_User_Name" - password "Your_Password_Or_API_Key" - } - } - } -} -``` - -## Usage - -To use the service library, it must first be initialized correctly. The -function `initializeService(JNIEnv *mEnv, jobject mApplicationContext)` -must be called so that the `JNIEnv` reference and the android -`ApplicationContext` can be passed correctly. If the functionality is no -longer needed, the service can be released by the function -`shutdownService()`. If a function is called without previous -initialization of the library, the return value of the function contains -a corresponding error message. The function could not be executed -successfully. - -## Additional remarks - -- Currently used ndk version: `21.3.6528147` - -License -------- - -``` -Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH -``` - diff --git a/src/global/CardReturnCode.cpp b/src/global/CardReturnCode.cpp index 047d811..f021c0f 100644 --- a/src/global/CardReturnCode.cpp +++ b/src/global/CardReturnCode.cpp @@ -32,8 +32,8 @@ case CardReturnCode::PROTOCOL_ERROR: return GlobalStatus::Code::Card_Protocol_Error; - case CardReturnCode::EXTENDED_LENGTH_MISSING: - return GlobalStatus::Code::Workflow_No_Extended_Length_Error; + case CardReturnCode::WRONG_LENGTH: + return GlobalStatus::Code::Workflow_Wrong_Length_Error; case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: return GlobalStatus::Code::Card_Unexpected_Transmit_Status; @@ -99,7 +99,7 @@ case CardReturnCode::UNKNOWN: case CardReturnCode::COMMAND_FAILED: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: case CardReturnCode::OK: case CardReturnCode::OK_PUK: diff --git a/src/global/CardReturnCode.h b/src/global/CardReturnCode.h index a9222ff..8a4da31 100644 --- a/src/global/CardReturnCode.h +++ b/src/global/CardReturnCode.h @@ -37,7 +37,7 @@ PUK_INOPERATIVE, NO_ACTIVE_PIN_SET, PROTOCOL_ERROR, - EXTENDED_LENGTH_MISSING, + WRONG_LENGTH, UNEXPECTED_TRANSMIT_STATUS) diff --git a/src/global/ECardApiResult.cpp b/src/global/ECardApiResult.cpp index e412c0f..163d7e5 100644 --- a/src/global/ECardApiResult.cpp +++ b/src/global/ECardApiResult.cpp @@ -103,7 +103,7 @@ addConversionElement(GlobalStatus::Code::Card_Unexpected_Transmit_Status, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Card_NewPin_Invalid_Length, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Workflow_AlreadyInProgress_Error, Minor::AL_Unknown_Error); - addConversionElement(GlobalStatus::Code::Workflow_No_Extended_Length_Error, Minor::AL_Unknown_Error); + addConversionElement(GlobalStatus::Code::Workflow_Wrong_Length_Error, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Card_Not_Found, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Card_Communication_Error, Minor::AL_Unknown_Error); addConversionElement(GlobalStatus::Code::Card_Input_TimeOut, Minor::AL_Unknown_Error); diff --git a/src/global/FailureCode.h b/src/global/FailureCode.h index 0c4a620..621183e 100644 --- a/src/global/FailureCode.h +++ b/src/global/FailureCode.h @@ -42,10 +42,10 @@ Certificate_Check_Failed_Hash_Mismatch, Certificate_Check_Failed_Same_Origin_Policy_Violation, Certificate_Check_Failed_Hash_Missing_In_Description, - Pre_Verfication_No_Test_Environment, - Pre_Verfication_Invalid_Certificate_Chain, - Pre_Verfication_Invalid_Certificate_Signature, - Pre_Verfication_Certificate_Expired, + Pre_Verification_No_Test_Environment, + Pre_Verification_Invalid_Certificate_Chain, + Pre_Verification_Invalid_Certificate_Signature, + Pre_Verification_Certificate_Expired, Extract_Cvcs_From_Eac1_No_Unique_At, Extract_Cvcs_From_Eac1_No_Unique_Dv, Extract_Cvcs_From_Eac1_At_Missing, @@ -64,7 +64,7 @@ Did_Authenticate_Eac2_Card_Command_Failed, Generic_Send_Receive_Paos_Unhandled, Generic_Send_Receive_Network_Error, - Generic_Send_Receive_Ssl_Error, + Generic_Send_Receive_Tls_Error, Generic_Send_Receive_Server_Error, Generic_Send_Receive_Client_Error, Generic_Send_Receive_Paos_Unknown, @@ -75,12 +75,12 @@ Transmit_Card_Command_Failed, Start_Paos_Response_Missing, Start_Paos_Response_Error, - Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply, + Check_Refresh_Address_Fatal_Tls_Error_Before_Reply, Check_Refresh_Address_Invalid_Ephemeral_Key_Length, Check_Refresh_Address_Service_Unavailable, Check_Refresh_Address_Service_Timeout, Check_Refresh_Address_Proxy_Error, - Check_Refresh_Address_Fatal_Ssl_Error_After_Reply, + Check_Refresh_Address_Fatal_Tls_Error_After_Reply, Check_Refresh_Address_Unknown_Network_Error, Check_Refresh_Address_Invalid_Http_Response, Check_Refresh_Address_Empty, @@ -94,7 +94,7 @@ Generic_Provider_Communication_Network_Error, Generic_Provider_Communication_Invalid_Ephemeral_Key_Length, Generic_Provider_Communication_Certificate_Error, - Generic_Provider_Communication_Ssl_Error, + Generic_Provider_Communication_Tls_Error, Get_SelfAuthData_Invalid_Or_Empty, Change_Pin_No_SetEidPinCommand_Response, Change_Pin_Input_Timeout, diff --git a/src/global/GlobalStatus.cpp b/src/global/GlobalStatus.cpp index 6c89d42..1055a7b 100644 --- a/src/global/GlobalStatus.cpp +++ b/src/global/GlobalStatus.cpp @@ -162,9 +162,9 @@ //: ERROR ALL_PLATFORMS DidAuthenticateEAC2, AA2 or the ID card declined the certificates. return tr("Authentication failed."); - case Code::Workflow_No_Extended_Length_Error: - //: ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length. - return tr("Your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.").arg(QCoreApplication::applicationName()); + case Code::Workflow_Wrong_Length_Error: + //: ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length. + return tr("The length of the data sent to the ID card was not accepted. Either the data is faulty or your card reader does not support Extended Length communication and cannot be used to read the ID card. Unfortunately, the %1 has no influence on this restriction.").arg(QCoreApplication::applicationName()); case Code::Workflow_Certificate_No_Description: //: ERROR_MASKED ALL_PLATFORMS diff --git a/src/global/GlobalStatus.h b/src/global/GlobalStatus.h index 0ac70ca..609fbb5 100644 --- a/src/global/GlobalStatus.h +++ b/src/global/GlobalStatus.h @@ -57,7 +57,7 @@ Workflow_No_Unique_AtCvc, Workflow_No_Unique_DvCvc, Workflow_No_Permission_Error, - Workflow_No_Extended_Length_Error, + Workflow_Wrong_Length_Error, Workflow_Certificate_No_Description, Workflow_Certificate_No_Url_In_Description, Workflow_Certificate_Hash_Error, diff --git a/src/global/LogHandler.cpp b/src/global/LogHandler.cpp index 090a0ea..b69a08d 100644 --- a/src/global/LogHandler.cpp +++ b/src/global/LogHandler.cpp @@ -284,6 +284,9 @@ { QByteArray function(pFunction); + // Remove anonymous namespace + function.replace(QByteArrayLiteral("(anonymous namespace)::"), ""); + // Remove the parameter list function = function.left(function.indexOf('(')); @@ -291,9 +294,13 @@ function.replace(QByteArrayLiteral("governikus::"), ""); // Remove the return type (if any) - if (function.indexOf(' ') != -1) - { - function = function.mid(function.lastIndexOf(' ') + 1); + if (const auto index = function.lastIndexOf(' ') + 1; index > 0) + { + function = function.mid(index); + if (!function.isEmpty() && function.at(0) == '*') + { + function.remove(0, 1); + } } // Trim function name diff --git a/src/ifd/base/ConnectRequest.cpp b/src/ifd/base/ConnectRequest.cpp index 27845ae..eee296f 100644 --- a/src/ifd/base/ConnectRequest.cpp +++ b/src/ifd/base/ConnectRequest.cpp @@ -160,7 +160,8 @@ qCWarning(ifd) << "Connection error:" << pError; mTimer.stop(); - if (pError == QAbstractSocket::SocketError::RemoteHostClosedError) + if (pError == QAbstractSocket::SocketError::RemoteHostClosedError + || pError == QAbstractSocket::SocketError::SslHandshakeFailedError) { Q_EMIT fireConnectionError(mIfdDescriptor, IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION); } diff --git a/src/ifd/base/DataChannel.h b/src/ifd/base/DataChannel.h index 6ed4d37..39c9130 100644 --- a/src/ifd/base/DataChannel.h +++ b/src/ifd/base/DataChannel.h @@ -27,6 +27,7 @@ Q_INVOKABLE virtual void send(const QByteArray& pDataBlock) = 0; Q_INVOKABLE virtual void close() = 0; + [[nodiscard]] virtual bool isPairingConnection() const = 0; [[nodiscard]] virtual const QString& getId() const = 0; Q_SIGNALS: diff --git a/src/ifd/base/IfdDescriptor.cpp b/src/ifd/base/IfdDescriptor.cpp index dc1e762..9ecc362 100644 --- a/src/ifd/base/IfdDescriptor.cpp +++ b/src/ifd/base/IfdDescriptor.cpp @@ -38,11 +38,13 @@ IfdDescriptor::IfdDescriptorData::IfdDescriptorData(const QString& pIfdName, const QString& pIfdId, const QVector& pApiVersions, + const bool pIsPairingAnnounced, const QUrl& pRemoteUrl, bool pIsLocalIfd) : mIfdName(pIfdName) , mIfdId(pIfdId) , mApiVersions(pApiVersions) + , mIsPairingAnnounced(pIsPairingAnnounced) , mUrl(pRemoteUrl) , mIsLocalIfd(pIsLocalIfd) { @@ -57,6 +59,7 @@ return mIfdName == pOther.mIfdName && mIfdId == pOther.mIfdId && mApiVersions == pOther.mApiVersions && + mIsPairingAnnounced == pOther.mIsPairingAnnounced && mUrl == pOther.mUrl; } @@ -79,7 +82,8 @@ const QString& ifdName = pDiscovery.getIfdName(); const QString& ifdId = pDiscovery.getIfdId(); const QVector& supportedApis = pDiscovery.getSupportedApis(); - d = new IfdDescriptorData(ifdName, ifdId, supportedApis, url, pLocalIfd); + const bool isPairing = pDiscovery.getPairing(); + d = new IfdDescriptorData(ifdName, ifdId, supportedApis, isPairing, url, pLocalIfd); } @@ -110,6 +114,12 @@ bool IfdDescriptor::isSupported() const { return IfdVersion(IfdVersion::selectLatestSupported(getApiVersions())).isValid(); +} + + +bool IfdDescriptor::isPairingAnnounced() const +{ + return !isNull() && d->mIsPairingAnnounced; } diff --git a/src/ifd/base/IfdDescriptor.h b/src/ifd/base/IfdDescriptor.h index db91293..9020c50 100644 --- a/src/ifd/base/IfdDescriptor.h +++ b/src/ifd/base/IfdDescriptor.h @@ -30,6 +30,7 @@ IfdDescriptorData(const QString& pIfdName, const QString& pIfdId, const QVector& pApiVersions, + const bool pIsPairingAnnounced, const QUrl& pUrl, bool pIsLocalIfd); @@ -38,6 +39,7 @@ const QString mIfdName; const QString mIfdId; const QVector mApiVersions; + const bool mIsPairingAnnounced; const QUrl mUrl; const bool mIsLocalIfd; @@ -57,6 +59,7 @@ [[nodiscard]] const QString& getIfdId() const; [[nodiscard]] const QVector& getApiVersions() const; [[nodiscard]] bool isSupported() const; + [[nodiscard]] bool isPairingAnnounced() const; [[nodiscard]] const QUrl& getUrl() const; [[nodiscard]] bool isNull() const; [[nodiscard]] bool isLocalIfd() const; diff --git a/src/ifd/base/IfdDispatcher.cpp b/src/ifd/base/IfdDispatcher.cpp index f768214..32e206a 100644 --- a/src/ifd/base/IfdDispatcher.cpp +++ b/src/ifd/base/IfdDispatcher.cpp @@ -89,6 +89,17 @@ } +bool IfdDispatcher::isPairingConnection() const +{ + if (!mDataChannel) + { + return false; + } + + return mDataChannel->isPairingConnection(); +} + + QString IfdDispatcher::getId() const { if (!mDataChannel) diff --git a/src/ifd/base/IfdDispatcher.h b/src/ifd/base/IfdDispatcher.h index cf19516..883d8e8 100644 --- a/src/ifd/base/IfdDispatcher.h +++ b/src/ifd/base/IfdDispatcher.h @@ -46,6 +46,7 @@ explicit IfdDispatcher(IfdVersion::Version pVersion, const QSharedPointer& pDataChannel); ~IfdDispatcher() override; + [[nodiscard]] virtual bool isPairingConnection() const; [[nodiscard]] virtual QString getId() const; [[nodiscard]] virtual const QString& getContextHandle() const; [[nodiscard]] IfdVersion::Version getVersion() const; diff --git a/src/ifd/base/IfdReaderManagerPlugIn.cpp b/src/ifd/base/IfdReaderManagerPlugIn.cpp index 6f1a776..bc2b9b4 100644 --- a/src/ifd/base/IfdReaderManagerPlugIn.cpp +++ b/src/ifd/base/IfdReaderManagerPlugIn.cpp @@ -108,17 +108,21 @@ void IfdReaderManagerPlugIn::onContextEstablished(const QString& pIfdName, const QString& pId) { const auto& dispatcher = mDispatcherList.value(pId); - if (isInitialPairing(pIfdName, pId)) - { - QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection); - } - else - { - QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] { - const QSharedPointer& ifdGetStatus = QSharedPointer::create(); - dispatcher->send(ifdGetStatus); - }, Qt::QueuedConnection); - } + + if (getInfo().getPlugInType() == ReaderManagerPlugInType::REMOTE_IFD) + { + dispatcher->saveRemoteNameInSettings(pIfdName); + if (dispatcher->isPairingConnection()) + { + QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection); + return; + } + } + + QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] { + const QSharedPointer& ifdGetStatus = QSharedPointer::create(); + dispatcher->send(ifdGetStatus); + }, Qt::QueuedConnection); } diff --git a/src/ifd/base/IfdReaderManagerPlugIn.h b/src/ifd/base/IfdReaderManagerPlugIn.h index 97774b0..07e5546 100644 --- a/src/ifd/base/IfdReaderManagerPlugIn.h +++ b/src/ifd/base/IfdReaderManagerPlugIn.h @@ -13,6 +13,10 @@ #include #include + +class test_RemoteIfdReaderManagerPlugIn; + + namespace governikus { @@ -21,6 +25,7 @@ : public ReaderManagerPlugIn { Q_OBJECT + friend class ::test_RemoteIfdReaderManagerPlugIn; private: QMultiMap mReadersForDispatcher; @@ -40,7 +45,6 @@ void removeDispatcher(const QString& pId); [[nodiscard]] const QMap>& getDispatchers() const; - virtual bool isInitialPairing(const QString& pIfdName, const QString& pId) = 0; virtual IfdClient* getIfdClient() = 0; public: diff --git a/src/ifd/base/IfdServer.h b/src/ifd/base/IfdServer.h index c736f94..6814f14 100644 --- a/src/ifd/base/IfdServer.h +++ b/src/ifd/base/IfdServer.h @@ -45,7 +45,7 @@ void firePskChanged(const QByteArray& pPsk); void fireConnectedChanged(bool pConnected); void fireIsRunningChanged(); - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; } // namespace governikus diff --git a/src/ifd/base/ServerMessageHandler.h b/src/ifd/base/ServerMessageHandler.h index f08fd50..26b3c70 100644 --- a/src/ifd/base/ServerMessageHandler.h +++ b/src/ifd/base/ServerMessageHandler.h @@ -35,9 +35,11 @@ virtual void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput&) = 0; virtual void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) = 0; + virtual void setAllowedCardTypes(const QVector& pAllowedCardTypes) = 0; Q_SIGNALS: void fireCardConnected(const QSharedPointer& pConnection); + void fireDisplayTextChanged(const QString& pDisplayText); void fireEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void fireModifyPin(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void fireCardDisconnected(const QSharedPointer& pConnection); diff --git a/src/ifd/base/ServerMessageHandlerImpl.cpp b/src/ifd/base/ServerMessageHandlerImpl.cpp index 0779631..2c142aa 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.cpp +++ b/src/ifd/base/ServerMessageHandlerImpl.cpp @@ -40,10 +40,12 @@ } -ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, const QVector& pAllowedPlugInTypes) +ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, + const QVector& pAllowedTypes) : ServerMessageHandler() , mDispatcher(Env::create(pDataChannel), &QObject::deleteLater) - , mAllowedPlugInTypes(pAllowedPlugInTypes) + , mAllowedPlugInTypes(pAllowedTypes) + , mAllowedCardTypes(pAllowedTypes) , mCardConnections() { connect(mDispatcher.data(), &IfdDispatcherServer::fireReceived, this, &ServerMessageHandlerImpl::onMessage); @@ -216,6 +218,7 @@ if (!progressMessage.isNull()) { cardConnection->setProgressMessage(progressMessage); + Q_EMIT fireDisplayTextChanged(progressMessage); } qCDebug(ifd) << "Transmit card APDU for" << slotHandle; @@ -334,6 +337,12 @@ const auto& response = QSharedPointer::create(pSlotHandle, ccid, minor); mDispatcher->send(response); +} + + +void ServerMessageHandlerImpl::setAllowedCardTypes(const QVector& pAllowedCardTypes) +{ + mAllowedCardTypes = pAllowedCardTypes; } @@ -444,19 +453,19 @@ } } + mDispatcher->send(QSharedPointer::create(pInfo, mAllowedCardTypes.contains(pInfo.getPlugInType()))); +} + + +void ServerMessageHandlerImpl::onReaderRemoved(const ReaderInfo& pInfo) +{ + if (!mAllowedPlugInTypes.contains(pInfo.getPlugInType())) + { + return; + } + mDispatcher->send(QSharedPointer::create(pInfo)); } -void ServerMessageHandlerImpl::onReaderRemoved(const ReaderInfo& pInfo) -{ - if (!mAllowedPlugInTypes.contains(pInfo.getPlugInType())) - { - return; - } - - mDispatcher->send(QSharedPointer::create(pInfo)); -} - - } // namespace governikus diff --git a/src/ifd/base/ServerMessageHandlerImpl.h b/src/ifd/base/ServerMessageHandlerImpl.h index b6f21a2..b52f534 100644 --- a/src/ifd/base/ServerMessageHandlerImpl.h +++ b/src/ifd/base/ServerMessageHandlerImpl.h @@ -33,6 +33,7 @@ private: const QSharedPointer mDispatcher; QVector mAllowedPlugInTypes; + QVector mAllowedCardTypes; QMap> mCardConnections; [[nodiscard]] QString slotHandleForReaderName(const QString& pReaderName) const; @@ -54,10 +55,11 @@ public: explicit ServerMessageHandlerImpl(const QSharedPointer& pDataChannel, - const QVector& pAllowedPlugInTypes = Enum::getList()); + const QVector& pAllowedTypes = Enum::getList()); void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput& pChannelOutput) override; void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) override; + void setAllowedCardTypes(const QVector& pAllowedCardTypes) override; }; diff --git a/src/ifd/base/TlsServer.cpp b/src/ifd/base/TlsServer.cpp index b369c11..18d9c73 100644 --- a/src/ifd/base/TlsServer.cpp +++ b/src/ifd/base/TlsServer.cpp @@ -45,6 +45,12 @@ { close(); mPsk.clear(); +} + + +bool TlsServer::hasPsk() const +{ + return !mPsk.isEmpty(); } diff --git a/src/ifd/base/TlsServer.h b/src/ifd/base/TlsServer.h index 4df443c..9022fde 100644 --- a/src/ifd/base/TlsServer.h +++ b/src/ifd/base/TlsServer.h @@ -44,6 +44,7 @@ void setPsk(const QByteArray& pPsk); void stopListening(); virtual bool startListening(quint16 pPort) = 0; + [[nodiscard]] bool hasPsk() const; Q_SIGNALS: void fireNewConnection(QTcpSocket* pSocket); diff --git a/src/ifd/base/WebSocketChannel.cpp b/src/ifd/base/WebSocketChannel.cpp index 855d298..35c2092 100644 --- a/src/ifd/base/WebSocketChannel.cpp +++ b/src/ifd/base/WebSocketChannel.cpp @@ -5,6 +5,7 @@ #include "WebSocketChannel.h" #include "RemoteServiceSettings.h" +#include "SecureStorage.h" #include #include @@ -94,6 +95,13 @@ } +bool WebSocketChannel::isPairingConnection() const +{ + const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); + return pairingCiphers.contains(mConnection->sslConfiguration().sessionCipher()); +} + + const QString& WebSocketChannel::getId() const { return mId; diff --git a/src/ifd/base/WebSocketChannel.h b/src/ifd/base/WebSocketChannel.h index 40214b8..8ae6399 100644 --- a/src/ifd/base/WebSocketChannel.h +++ b/src/ifd/base/WebSocketChannel.h @@ -35,6 +35,7 @@ void send(const QByteArray& pDataBlock) override; void close() override; + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] const QString& getId() const override; private Q_SLOTS: diff --git a/src/ifd/base/messages/IfdStatus.cpp b/src/ifd/base/messages/IfdStatus.cpp index 6b33e1e..8679ef2 100644 --- a/src/ifd/base/messages/IfdStatus.cpp +++ b/src/ifd/base/messages/IfdStatus.cpp @@ -81,13 +81,13 @@ } -IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo) +IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard) : IfdMessage(IfdMessageType::IFDStatus) , mSlotName(pReaderInfo.getName()) , mHasPinPad(!pReaderInfo.isBasicReader()) , mMaxApduLength(pReaderInfo.getMaxApduLength()) , mConnectedReader(pReaderInfo.isValid()) - , mCardAvailable(pReaderInfo.hasCard()) + , mCardAvailable(pReaderInfo.hasCard() && pPublishCard) { if (!mHasPinPad && pReaderInfo.getPlugInType() == ReaderManagerPlugInType::NFC) { diff --git a/src/ifd/base/messages/IfdStatus.h b/src/ifd/base/messages/IfdStatus.h index 885db63..0acdfdc 100644 --- a/src/ifd/base/messages/IfdStatus.h +++ b/src/ifd/base/messages/IfdStatus.h @@ -33,7 +33,7 @@ void parsePinPad(const QJsonObject& pMessageObject); public: - explicit IfdStatus(const ReaderInfo& pReaderInfo); + explicit IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard = true); explicit IfdStatus(const QJsonObject& pMessageObject); ~IfdStatus() override = default; diff --git a/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp b/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp index 3a43d5f..c5f7f65 100644 --- a/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp +++ b/src/ifd/local/LocalIfdReaderManagerPlugIn.cpp @@ -97,14 +97,6 @@ } -bool LocalIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId) -{ - Q_UNUSED(pIfdName) - Q_UNUSED(pId) - return false; -} - - bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed() { if (mServiceConnected) diff --git a/src/ifd/local/LocalIfdReaderManagerPlugIn.h b/src/ifd/local/LocalIfdReaderManagerPlugIn.h index ea81612..7e68ebe 100644 --- a/src/ifd/local/LocalIfdReaderManagerPlugIn.h +++ b/src/ifd/local/LocalIfdReaderManagerPlugIn.h @@ -36,7 +36,6 @@ void stopScan(const QString& pError = QString()) override; protected: - bool isInitialPairing(const QString& pIfdName, const QString& pId) override; LocalIfdClient* getIfdClient() override; void addDispatcher(const QSharedPointer& pDispatcher) override; diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp index 837ae73..3ceede9 100644 --- a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp +++ b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.cpp @@ -40,12 +40,13 @@ const RemoteServiceSettings& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); for (const QSharedPointer& remoteDevice : pRemoteDevices) { - if (!remoteDevice->getIfdDescriptor().isSupported()) + const auto& ifdDescriptor = remoteDevice->getIfdDescriptor(); + if (!ifdDescriptor.isSupported() || ifdDescriptor.isPairingAnnounced()) { continue; } - const QString ifdId = remoteDevice->getIfdDescriptor().getIfdId(); + const QString ifdId = ifdDescriptor.getIfdId(); // If already connected: skip. if (getDispatchers().contains(ifdId)) @@ -106,19 +107,3 @@ { return Env::getSingleton(); } - - -bool RemoteIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId) -{ - RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); - auto info = settings.getRemoteInfo(pId); - bool initialPairing = false; - if (info.getNameEscaped().isEmpty()) - { - initialPairing = true; - } - info.setNameUnescaped(pIfdName); - settings.updateRemoteInfo(info); - - return initialPairing; -} diff --git a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h index 68bbb35..47104fd 100644 --- a/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h +++ b/src/ifd/remote/RemoteIfdReaderManagerPlugIn.h @@ -40,7 +40,6 @@ void stopScan(const QString& pError = QString()) override; protected: - bool isInitialPairing(const QString& pIfdName, const QString& pId) override; IfdClient* getIfdClient() override; }; diff --git a/src/ifd/remote/RemoteIfdServer.cpp b/src/ifd/remote/RemoteIfdServer.cpp index 16c81a0..f9f6d60 100644 --- a/src/ifd/remote/RemoteIfdServer.cpp +++ b/src/ifd/remote/RemoteIfdServer.cpp @@ -32,7 +32,8 @@ const auto& remoteServiceSettings = Env::getSingleton()->getRemoteServiceSettings(); const auto& ifdId = QString::fromLatin1(remoteServiceSettings.getCertificate().toPem()); quint16 port = mWebSocketServer->getServerPort(); - mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port)); + bool isPairing = mWebSocketServer->isPairingAnnounced(); + mRemoteReaderAdvertiser.reset(Env::create(ifdName, ifdId, port, isPairing)); } Q_EMIT fireConnectedChanged(pConnected); diff --git a/src/ifd/remote/RemoteReaderAdvertiser.cpp b/src/ifd/remote/RemoteReaderAdvertiser.cpp index d49fa85..91e8ecd 100644 --- a/src/ifd/remote/RemoteReaderAdvertiser.cpp +++ b/src/ifd/remote/RemoteReaderAdvertiser.cpp @@ -18,9 +18,9 @@ namespace governikus { -template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort) +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool& pIsPairing) { - return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort); + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pIsPairing); } @@ -51,7 +51,7 @@ } -RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval, bool pPairing) +RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing, int pTimerInterval) : RemoteReaderAdvertiser() , mHandler(Env::create(false)) , mTimerId(startTimer(pTimerInterval)) diff --git a/src/ifd/remote/RemoteReaderAdvertiser.h b/src/ifd/remote/RemoteReaderAdvertiser.h index bd71340..1c5dd0e 100644 --- a/src/ifd/remote/RemoteReaderAdvertiser.h +++ b/src/ifd/remote/RemoteReaderAdvertiser.h @@ -53,7 +53,7 @@ public: ~RemoteReaderAdvertiserImpl() override; - RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval = 1000, bool pPairing = false); + RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing = false, int pTimerInterval = 1000); void setPairing(bool pEnabled) override; }; diff --git a/src/ifd/remote/RemoteTlsServer.cpp b/src/ifd/remote/RemoteTlsServer.cpp index 9ce2daa..6829089 100644 --- a/src/ifd/remote/RemoteTlsServer.cpp +++ b/src/ifd/remote/RemoteTlsServer.cpp @@ -110,10 +110,11 @@ const auto& pairingCiphers = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers(); if (pairingCiphers.contains(cfg.sessionCipher())) { - qCDebug(ifd) << "Pairing completed | Add certificate:" << cfg.peerCertificate(); - settings.addTrustedCertificate(cfg.peerCertificate()); + const auto& sslCertificate = cfg.peerCertificate(); + qCDebug(ifd) << "Pairing completed | Add certificate:" << sslCertificate; + settings.addTrustedCertificate(sslCertificate); setPairing(false); - Q_EMIT firePairingCompleted(); + Q_EMIT firePairingCompleted(sslCertificate); } else { diff --git a/src/ifd/remote/RemoteTlsServer.h b/src/ifd/remote/RemoteTlsServer.h index 39fc7a1..648b557 100644 --- a/src/ifd/remote/RemoteTlsServer.h +++ b/src/ifd/remote/RemoteTlsServer.h @@ -32,7 +32,7 @@ void onSslErrors(const QList& pErrors) override; Q_SIGNALS: - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; } // namespace governikus diff --git a/src/ifd/remote/RemoteWebSocketServer.h b/src/ifd/remote/RemoteWebSocketServer.h index 91a614b..938f3c5 100644 --- a/src/ifd/remote/RemoteWebSocketServer.h +++ b/src/ifd/remote/RemoteWebSocketServer.h @@ -22,11 +22,12 @@ ~RemoteWebSocketServer() override; [[nodiscard]] virtual bool isPairingConnection() const = 0; + [[nodiscard]] virtual bool isPairingAnnounced() const = 0; virtual void setPairing(bool pEnable = true) = 0; [[nodiscard]] virtual QSslCertificate getCurrentCertificate() const = 0; Q_SIGNALS: - void firePairingCompleted(); + void firePairingCompleted(const QSslCertificate& pCertificate); }; diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.cpp b/src/ifd/remote/RemoteWebSocketServerImpl.cpp index da8b913..963ea83 100644 --- a/src/ifd/remote/RemoteWebSocketServerImpl.cpp +++ b/src/ifd/remote/RemoteWebSocketServerImpl.cpp @@ -103,6 +103,12 @@ } +bool RemoteWebSocketServerImpl::isPairingAnnounced() const +{ + return mRemoteTlsServer->hasPsk(); +} + + void RemoteWebSocketServerImpl::setPairing(bool pEnable) { mRemoteTlsServer->setPairing(pEnable); diff --git a/src/ifd/remote/RemoteWebSocketServerImpl.h b/src/ifd/remote/RemoteWebSocketServerImpl.h index 6089f00..ba7d8bf 100644 --- a/src/ifd/remote/RemoteWebSocketServerImpl.h +++ b/src/ifd/remote/RemoteWebSocketServerImpl.h @@ -45,6 +45,7 @@ const QSharedPointer& getMessageHandler() const override; [[nodiscard]] bool isPairingConnection() const override; + [[nodiscard]] bool isPairingAnnounced() const override; void setPairing(bool pEnable = true) override; [[nodiscard]] QSslCertificate getCurrentCertificate() const override; }; diff --git a/src/network/NetworkManager.cpp b/src/network/NetworkManager.cpp index 369fc8b..bd935af 100644 --- a/src/network/NetworkManager.cpp +++ b/src/network/NetworkManager.cpp @@ -5,11 +5,8 @@ #include "NetworkManager.h" #include "AppSettings.h" +#include "LogHandler.h" #include "NetworkReplyError.h" -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - #include "NetworkReplyTimeout.h" -#endif -#include "LogHandler.h" #include "SecureStorage.h" #include "TlsChecker.h" #include "VersionInfo.h" @@ -335,10 +332,6 @@ --mOpenConnectionCount; }); connect(this, &NetworkManager::fireShutdown, pResponse, &QNetworkReply::abort, Qt::QueuedConnection); - -#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - NetworkReplyTimeout::setTimeout(this, pResponse, 30000); -#endif } return QSharedPointer(pResponse, &QObject::deleteLater); diff --git a/src/network/NetworkReplyTimeout.cpp b/src/network/NetworkReplyTimeout.cpp deleted file mode 100644 index 14acf8d..0000000 --- a/src/network/NetworkReplyTimeout.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -#include "NetworkReplyTimeout.h" - -#include - -using namespace governikus; - -NetworkReplyTimeout::NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout) - : QObject(pReply) -{ - Q_ASSERT(pReply); - if (pReply == nullptr) - { - return; - } - - connect(&mTimer, &QTimer::timeout, this, &NetworkReplyTimeout::onTimeout); - mTimer.setSingleShot(true); - mTimer.setInterval(pTimeout); - mTimer.start(); -} - - -void NetworkReplyTimeout::onTimeout() -{ - auto* reply = static_cast(parent()); - if (reply != nullptr && reply->isRunning()) - { - reply->abort(); - } -} - - -void NetworkReplyTimeout::onShutdown() -{ - mTimer.stop(); - onTimeout(); -} - - -void NetworkReplyTimeout::setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeout) -{ - // since the QNetworkReply is set as parent, we don't need to care about destruction - const auto* timeout = new NetworkReplyTimeout(pReply, pTimeout); - connect(pManager, &NetworkManager::fireShutdown, timeout, &NetworkReplyTimeout::onShutdown); -} diff --git a/src/network/NetworkReplyTimeout.h b/src/network/NetworkReplyTimeout.h deleted file mode 100644 index 729e46d..0000000 --- a/src/network/NetworkReplyTimeout.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany - */ - -/*! - * \brief Utility class to set a timeout on a QNetworkReply - */ - -#pragma once - -#include "NetworkManager.h" - -#include -#include - -namespace governikus -{ - -class NetworkReplyTimeout - : public QObject -{ - Q_OBJECT - - private: - QTimer mTimer; - - NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout); - - private Q_SLOTS: - void onTimeout(); - void onShutdown(); - - public: - /*! - * Set the timeout in milli-seconds on the specified QNetworkReply. - */ - static void setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeoutMilliSeconds); -}; - -} // namespace governikus diff --git a/src/services/Service.cpp b/src/services/Service.cpp index eab8254..2b6ad7d 100644 --- a/src/services/Service.cpp +++ b/src/services/Service.cpp @@ -25,14 +25,16 @@ { case UpdateType::APPCAST: mExplicitSuccessMessage = pForceUpdate; -#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) - mTimer.start(mOneDayInMs); - if (pForceUpdate || Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + if (Env::getSingleton()->getGeneralSettings().isAutoUpdateAvailable()) { - Q_UNUSED(Env::getSingleton()->checkAppUpdate(pForceUpdate)) - break; + mTimer.start(mOneDayInMs); + if (pForceUpdate || Env::getSingleton()->getGeneralSettings().isAutoUpdateCheck()) + { + Q_UNUSED(Env::getSingleton()->checkAppUpdate(pForceUpdate)) + break; + } } -#endif + Q_FALLTHROUGH(); case UpdateType::PROVIDER: diff --git a/src/settings/GeneralSettings.cpp b/src/settings/GeneralSettings.cpp index 4e5cbc7..c0ac3dc 100644 --- a/src/settings/GeneralSettings.cpp +++ b/src/settings/GeneralSettings.cpp @@ -447,7 +447,7 @@ bool GeneralSettings::isAutoUpdateAvailable() const { -#if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) || defined(Q_OS_MACOS) +#if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) return true; #else diff --git a/src/settings/RemoteServiceSettings.cpp b/src/settings/RemoteServiceSettings.cpp index a105833..6edd21a 100644 --- a/src/settings/RemoteServiceSettings.cpp +++ b/src/settings/RemoteServiceSettings.cpp @@ -29,6 +29,7 @@ SETTINGS_NAME(SETTINGS_GROUP_NAME_REMOTEREADER, "remotereader") SETTINGS_NAME(SETTINGS_NAME_DEVICE_NAME, "serverName") SETTINGS_NAME(SETTINGS_NAME_PIN_PAD_MODE, "pinPadMode") +SETTINGS_NAME(SETTINGS_NAME_SHOW_ACCESS_RIGHTS, "showAccessRights") SETTINGS_NAME(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES, "trustedCertificates") SETTINGS_NAME(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM, "certificate") SETTINGS_NAME(SETTINGS_NAME_TRUSTED_REMOTE_INFO, "trustedRemoteInfo") @@ -84,13 +85,26 @@ bool RemoteServiceSettings::getPinPadMode() const { - return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), false).toBool(); + return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), true).toBool(); } void RemoteServiceSettings::setPinPadMode(bool pPinPadMode) { mStore->setValue(SETTINGS_NAME_PIN_PAD_MODE(), pPinPadMode); + save(mStore); +} + + +bool RemoteServiceSettings::getShowAccessRights() const +{ + return mStore->value(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), false).toBool(); +} + + +void RemoteServiceSettings::setShowAccessRights(bool pShowAccessRights) +{ + mStore->setValue(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), pShowAccessRights); save(mStore); } @@ -229,6 +243,11 @@ RemoteServiceSettings::RemoteInfo RemoteServiceSettings::getRemoteInfo(const QSslCertificate& pCertificate) const { + if (pCertificate.isNull()) + { + return RemoteInfo(); + } + return getRemoteInfo(generateFingerprint(pCertificate)); } @@ -322,8 +341,13 @@ iter.next(); if (iter.value().getFingerprint() == pInfo.getFingerprint()) { + const bool hadNoNameYet = iter.value().mName.isEmpty(); iter.setValue(pInfo); setRemoteInfos(infos); + if (hadNoNameYet) + { + Q_EMIT fireInitialDeviceNameSet(pInfo.getNameEscaped()); + } return true; } } diff --git a/src/settings/RemoteServiceSettings.h b/src/settings/RemoteServiceSettings.h index 97f2bb9..658973c 100644 --- a/src/settings/RemoteServiceSettings.h +++ b/src/settings/RemoteServiceSettings.h @@ -89,6 +89,9 @@ [[nodiscard]] bool getPinPadMode() const; void setPinPadMode(bool pPinPadMode); + [[nodiscard]] bool getShowAccessRights() const; + void setShowAccessRights(bool pShowAccessRights); + [[nodiscard]] QList getTrustedCertificates() const; void addTrustedCertificate(const QSslCertificate& pCertificate); void removeTrustedCertificate(const QSslCertificate& pCertificate); @@ -112,6 +115,7 @@ Q_SIGNALS: void fireTrustedCertificatesChanged(); void fireTrustedRemoteInfosChanged(); + void fireInitialDeviceNameSet(const QString& pName); }; diff --git a/src/ui/json/MessageDispatcher.cpp b/src/ui/json/MessageDispatcher.cpp index 03bb84f..45e5930 100644 --- a/src/ui/json/MessageDispatcher.cpp +++ b/src/ui/json/MessageDispatcher.cpp @@ -387,9 +387,10 @@ #ifdef Q_OS_IOS { const auto allowedStates = {MsgType::ENTER_PIN, MsgType::ENTER_CAN, MsgType::ENTER_PUK, MsgType::ENTER_NEW_PIN}; - const auto lastPaceResult = mContext.getContext()->getLastPaceResult(); - return handleCurrentState(cmdType, allowedStates, [lastPaceResult] { - switch (lastPaceResult) + const auto& workflowContext = mContext.getContext(); + return handleCurrentState(cmdType, allowedStates, [&workflowContext] { + workflowContext->setInterruptRequested(true); + switch (workflowContext->getLastPaceResult()) { case CardReturnCode::OK: case CardReturnCode::OK_PUK: diff --git a/src/ui/qml/ApplicationModel.cpp b/src/ui/qml/ApplicationModel.cpp index dcc7c90..88eb64b 100644 --- a/src/ui/qml/ApplicationModel.cpp +++ b/src/ui/qml/ApplicationModel.cpp @@ -6,6 +6,7 @@ #include "context/AuthContext.h" #include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" #include "BuildHelper.h" @@ -225,6 +226,10 @@ if (mContext.objectCast()) { return Workflow::WORKFLOW_AUTHENTICATION; + } + if (mContext.objectCast()) + { + return Workflow::WORKFLOW_REMOTE_SERVICE; } return Workflow::WORKFLOW_NONE; } diff --git a/src/ui/qml/ApplicationModel.h b/src/ui/qml/ApplicationModel.h index 472499d..d028710 100644 --- a/src/ui/qml/ApplicationModel.h +++ b/src/ui/qml/ApplicationModel.h @@ -97,6 +97,7 @@ WORKFLOW_SELF_AUTHENTICATION, WORKFLOW_AUTHENTICATION, WORKFLOW_SMART, + WORKFLOW_REMOTE_SERVICE, WORKFLOW_NONE }; Q_ENUM(Workflow) diff --git a/src/ui/qml/CertificateDescriptionModel.cpp b/src/ui/qml/CertificateDescriptionModel.cpp index 10df268..adecdd9 100644 --- a/src/ui/qml/CertificateDescriptionModel.cpp +++ b/src/ui/qml/CertificateDescriptionModel.cpp @@ -5,6 +5,8 @@ #include "CertificateDescriptionModel.h" #include "LanguageLoader.h" +#include "context/AuthContext.h" +#include "context/IfdServiceContext.h" using namespace governikus; @@ -21,9 +23,14 @@ QSharedPointer CertificateDescriptionModel::getCertificateDescription() const { - if (mContext && mContext->getDidAuthenticateEac1()) + if (const auto authContext = mContext.objectCast(); authContext && authContext->getDidAuthenticateEac1()) { - return mContext->getDidAuthenticateEac1()->getCertificateDescription(); + return authContext->getDidAuthenticateEac1()->getCertificateDescription(); + } + + if (const auto ifdContext = mContext.objectCast(); ifdContext && ifdContext->getCertificateDescription()) + { + return ifdContext->getCertificateDescription(); } return QSharedPointer(); @@ -85,13 +92,17 @@ } -void CertificateDescriptionModel::resetContext(const QSharedPointer& pContext) +void CertificateDescriptionModel::resetContext(const QSharedPointer& pContext) { mContext = pContext; - if (mContext) + if (auto authContext = pContext.objectCast()) { - connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); - connect(mContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(authContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); + } + else if (auto ifdContext = pContext.objectCast()) + { + connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed); } onDidAuthenticateEac1Changed(); @@ -121,9 +132,9 @@ QString CertificateDescriptionModel::getValidity() const { - if (mContext && mContext->getAccessRightManager() && mContext->getAccessRightManager()->getTerminalCvc()) + if (const auto authContext = mContext.objectCast(); authContext&& authContext->getAccessRightManager() && authContext->getAccessRightManager()->getTerminalCvc()) { - const CVCertificateBody body = mContext->getAccessRightManager()->getTerminalCvc()->getBody(); + const CVCertificateBody body = authContext->getAccessRightManager()->getTerminalCvc()->getBody(); const auto locale = LanguageLoader::getInstance().getUsedLocale(); const auto effectiveDate = locale.toString(body.getCertificateEffectiveDate(), QLocale::ShortFormat); const auto expirationDate = locale.toString(body.getCertificateExpirationDate(), QLocale::ShortFormat); diff --git a/src/ui/qml/CertificateDescriptionModel.h b/src/ui/qml/CertificateDescriptionModel.h index c2adc3a..00735db 100644 --- a/src/ui/qml/CertificateDescriptionModel.h +++ b/src/ui/qml/CertificateDescriptionModel.h @@ -10,7 +10,7 @@ #include "Env.h" #include "asn1/CertificateDescription.h" -#include "context/AuthContext.h" +#include "context/WorkflowContext.h" #include #include @@ -32,7 +32,7 @@ private: QVector> mData; - QSharedPointer mContext; + QSharedPointer mContext; CertificateDescriptionModel(); ~CertificateDescriptionModel()override = default; @@ -54,7 +54,7 @@ TEXT }; - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); [[nodiscard]] QString getSubjectName() const; [[nodiscard]] QString getSubjectUrl() const; diff --git a/src/ui/qml/ChatModel.cpp b/src/ui/qml/ChatModel.cpp index e658a48..dfc78a6 100644 --- a/src/ui/qml/ChatModel.cpp +++ b/src/ui/qml/ChatModel.cpp @@ -11,13 +11,15 @@ #include "AppSettings.h" #include "asn1/AccessRoleAndRight.h" #include "asn1/CVCertificate.h" +#include "context/AuthContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" using namespace governikus; ChatModel::ChatModel() : QAbstractListModel() - , mAuthContext() + , mContext() , mAllRights() , mOptionalRights() , mSelectedRights() @@ -49,9 +51,9 @@ } -void ChatModel::resetContext(const QSharedPointer& pContext) -{ - mAuthContext = pContext; +void ChatModel::resetContext(const QSharedPointer& pContext) +{ + mContext = pContext; beginResetModel(); @@ -61,9 +63,13 @@ endResetModel(); - if (!pContext.isNull()) - { - connect(pContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); + if (auto authContext = pContext.objectCast()) + { + connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); + } + else if (auto ifdContext = pContext.objectCast()) + { + connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged); } } @@ -113,32 +119,41 @@ QVariant ChatModel::data(const QModelIndex& pIndex, int pRole) const { - if (pIndex.isValid() && pIndex.row() < rowCount()) - { - auto right = mAllRights.at(pIndex.row()); - if (pRole == Qt::DisplayRole || pRole == NAME_ROLE) + if (!pIndex.isValid() || pIndex.row() >= rowCount()) + { + return QVariant(); + } + + const auto& right = mAllRights.at(pIndex.row()); + switch (pRole) + { + case Qt::DisplayRole: + case NAME_ROLE: { QString displayText = AccessRoleAndRightsUtil::toDisplayText(right); if (right == AccessRight::AGE_VERIFICATION) { - displayText += QStringLiteral(" (%1)").arg(mAuthContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + if (auto authContext = mContext.objectCast()) + { + displayText += QStringLiteral(" (%1)").arg(authContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge()); + } } return displayText; } - if (pRole == OPTIONAL_ROLE) - { + + case OPTIONAL_ROLE: return mOptionalRights.contains(right); - } - if (pRole == SELECTED_ROLE) - { + + case SELECTED_ROLE: return mSelectedRights.contains(right); - } - if (pRole == WRITE_RIGHT) - { + + case WRITE_RIGHT: return AccessRoleAndRightsUtil::isWriteAccessRight(right); - } - } - return QVariant(); + + default: + Q_UNREACHABLE(); + return QVariant(); + } } @@ -185,9 +200,11 @@ void ChatModel::transferAccessRights() { - Q_ASSERT(mAuthContext->getAccessRightManager()); - - *mAuthContext->getAccessRightManager() = mSelectedRights; + if (auto authContext = mContext.objectCast()) + { + Q_ASSERT(authContext->getAccessRightManager()); + *authContext->getAccessRightManager() = mSelectedRights; + } } diff --git a/src/ui/qml/ChatModel.h b/src/ui/qml/ChatModel.h index cf2dc05..f50db10 100644 --- a/src/ui/qml/ChatModel.h +++ b/src/ui/qml/ChatModel.h @@ -15,7 +15,8 @@ #include #include "Env.h" -#include "context/AuthContext.h" +#include "context/AccessRightManager.h" +#include "context/WorkflowContext.h" class test_ChatModel; @@ -36,7 +37,7 @@ Q_PROPERTY(QSortFilterProxyModel * write READ getFilterWriteModel CONSTANT) private: - QSharedPointer mAuthContext; + QSharedPointer mContext; QList mAllRights; QSet mOptionalRights; QSet mSelectedRights; @@ -63,7 +64,7 @@ void onAuthenticationDataChanged(QSharedPointer pAccessRightManager); public: - void resetContext(const QSharedPointer& pContext = QSharedPointer()); + void resetContext(const QSharedPointer& pContext = QSharedPointer()); [[nodiscard]] int rowCount(const QModelIndex& = QModelIndex()) const override; [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override; diff --git a/src/ui/qml/HistoryModelSearchFilter.cpp b/src/ui/qml/HistoryModelSearchFilter.cpp index 1acf6d8..2a7bed3 100644 --- a/src/ui/qml/HistoryModelSearchFilter.cpp +++ b/src/ui/qml/HistoryModelSearchFilter.cpp @@ -25,6 +25,7 @@ } const QModelIndex& modelIndex = dataSourceModel->index(pSourceRow, 0); + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString if (dataSourceModel->data(modelIndex, HistoryModel::DATETIME).toDateTime().toString(tr("dd.MM.yyyy")).contains(mFilterString, Qt::CaseInsensitive) || dataSourceModel->data(modelIndex, HistoryModel::SUBJECT).toString().contains(mFilterString, Qt::CaseInsensitive) || dataSourceModel->data(modelIndex, HistoryModel::PURPOSE).toString().contains(mFilterString, Qt::CaseInsensitive) diff --git a/src/ui/qml/LogModel.cpp b/src/ui/qml/LogModel.cpp index dd6782d..d5d1095 100644 --- a/src/ui/qml/LogModel.cpp +++ b/src/ui/qml/LogModel.cpp @@ -125,6 +125,7 @@ { if (!entry.isEmpty()) { + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString logFileNames += LanguageLoader::getInstance().getUsedLocale().toString(LogHandler::getFileDate(QFileInfo(entry)), tr("dd.MM.yyyy hh:mm:ss")); } } diff --git a/src/ui/qml/NotificationModel.cpp b/src/ui/qml/NotificationModel.cpp index ad03e02..f5074c7 100644 --- a/src/ui/qml/NotificationModel.cpp +++ b/src/ui/qml/NotificationModel.cpp @@ -41,6 +41,7 @@ } beginInsertRows(QModelIndex(), mNotificationEntries.size(), mNotificationEntries.size()); + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString const auto& time = QTime::currentTime().toString(tr("hh:mm:ss")); mNotificationEntries.append({pCategoryName, time, pMsg}); endInsertRows(); diff --git a/src/ui/qml/PinResetInformationModel.cpp b/src/ui/qml/PinResetInformationModel.cpp index 160903c..0a0af91 100644 --- a/src/ui/qml/PinResetInformationModel.cpp +++ b/src/ui/qml/PinResetInformationModel.cpp @@ -4,9 +4,12 @@ #include "PinResetInformationModel.h" +#include "LanguageLoader.h" #include "ProviderConfiguration.h" + using namespace governikus; + PinResetInformationModel::PinResetInformationModel() : QObject() @@ -25,6 +28,11 @@ if (homepage.isEmpty()) { return tr("https://www.personalausweisportal.de/EN"); + } + + if (LanguageLoader::getLocaleCode() != QStringLiteral("de")) + { + return homepage + QStringLiteral("/en"); } return homepage; diff --git a/src/ui/qml/ReaderModel.cpp b/src/ui/qml/ReaderModel.cpp index bb60348..19b65e4 100644 --- a/src/ui/qml/ReaderModel.cpp +++ b/src/ui/qml/ReaderModel.cpp @@ -255,6 +255,7 @@ return QString(); } + //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString const auto& updateTime = LanguageLoader::getInstance().getUsedLocale().toString(mConnectedReadersUpdateTime, tr("hh:mm:ss AP")); //: LABEL ALL_PLATFORMS return tr("The list of card readers was last updated at %1.").arg(updateTime); diff --git a/src/ui/qml/RemoteDeviceFilterModel.cpp b/src/ui/qml/RemoteDeviceFilterModel.cpp new file mode 100644 index 0000000..8a8e7ff --- /dev/null +++ b/src/ui/qml/RemoteDeviceFilterModel.cpp @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#include "RemoteDeviceFilterModel.h" + +#include "RemoteDeviceModel.h" + +using namespace governikus; +using namespace std::placeholders; + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction) + : QSortFilterProxyModel() + , mFilterToApply(pFilterFunction) +{ + QSortFilterProxyModel::setSourceModel(pSourceModel); +} + + +RemoteDeviceFilterModel::ShowAvailableAndPaired RemoteDeviceFilterModel::showAvailableAndPaired = {}; +RemoteDeviceFilterModel::ShowUnavailableAndPaired RemoteDeviceFilterModel::showUnavailableAndPaired = {}; +RemoteDeviceFilterModel::ShowActivePairingMode RemoteDeviceFilterModel::showActivePairingMode = {}; + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::availableNotPairing, this, _1, _2)) +{ +} + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::unavailableAndPaired, this, _1, _2)) +{ +} + + +RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode) + : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::isPairing, this, _1, _2)) +{ +} + + +bool RemoteDeviceFilterModel::available(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + const bool isNetworkVisible = sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE).toBool(); + return isNetworkVisible; +} + + +bool RemoteDeviceFilterModel::isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED).toBool(); +} + + +bool RemoteDeviceFilterModel::availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return available(pSourceRow, pSourceParent) && !isPairing(pSourceRow, pSourceParent); +} + + +bool RemoteDeviceFilterModel::unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return !available(pSourceRow, pSourceParent) && isDevicePaired(pSourceRow, pSourceParent); +} + + +bool RemoteDeviceFilterModel::isPairing(int pSourceRow, const QModelIndex& pSourceParent) const +{ + const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent); + return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING).toBool(); +} + + +bool RemoteDeviceFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const +{ + return mFilterToApply(pSourceRow, pSourceParent); +} diff --git a/src/ui/qml/RemoteDeviceFilterModel.h b/src/ui/qml/RemoteDeviceFilterModel.h new file mode 100644 index 0000000..b9ab5b5 --- /dev/null +++ b/src/ui/qml/RemoteDeviceFilterModel.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +#pragma once + +#include + +class test_RemoteDeviceFilterModel; + +namespace governikus +{ + +class RemoteDeviceFilterModel + : public QSortFilterProxyModel +{ + friend class ::test_RemoteDeviceFilterModel; + + private: + using FilterFunctionType = std::function; + FilterFunctionType mFilterToApply; + + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction); + + public: + struct ShowAvailableAndPaired {}; + struct ShowUnavailableAndPaired {}; + struct ShowActivePairingMode {}; + + static ShowAvailableAndPaired showAvailableAndPaired; + static ShowUnavailableAndPaired showUnavailableAndPaired; + static ShowActivePairingMode showActivePairingMode; + + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired); + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired); + RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode); + + ~RemoteDeviceFilterModel() override = default; + + private: + [[nodiscard]] bool available(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const; + + [[nodiscard]] bool availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const; + [[nodiscard]] bool isPairing(int pSourceRow, const QModelIndex& pSourceParent) const; + + protected: + [[nodiscard]] bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override; +}; + +} // namespace governikus diff --git a/src/ui/qml/RemoteDeviceModel.cpp b/src/ui/qml/RemoteDeviceModel.cpp index e994d42..06406ed 100644 --- a/src/ui/qml/RemoteDeviceModel.cpp +++ b/src/ui/qml/RemoteDeviceModel.cpp @@ -16,17 +16,16 @@ using namespace governikus; -RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& pId, - const QSharedPointer& pRemoteDeviceListEntry) - : mDeviceName(pDeviceNameEscaped) - , mId(pId) +RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QSharedPointer& pListEntry) + : mDeviceName(RemoteServiceSettings::escapeDeviceName(pListEntry->getIfdDescriptor().getIfdName())) + , mId(pListEntry->getIfdDescriptor().getIfdId()) , mPaired(false) + , mIsPairing(pListEntry->getIfdDescriptor().isPairingAnnounced()) , mNetworkVisible(false) , mConnected(false) - , mSupported(pRemoteDeviceListEntry->getIfdDescriptor().isSupported()) + , mSupported(pListEntry->getIfdDescriptor().isSupported()) , mLastConnected() - , mRemoteDeviceListEntry(pRemoteDeviceListEntry) + , mRemoteDeviceListEntry(pListEntry) { Q_ASSERT(!mDeviceName.contains(QLatin1Char('<'))); } @@ -37,11 +36,13 @@ bool pNetworkVisible, bool pConnected, bool pSupported, + bool pIsPairing, const QDateTime& pLastConnected, const QSharedPointer& pRemoteDeviceListEntry) : mDeviceName(pDeviceNameEscaped) , mId(pId) , mPaired(true) + , mIsPairing(pIsPairing) , mNetworkVisible(pNetworkVisible) , mConnected(pConnected) , mSupported(pSupported) @@ -56,6 +57,7 @@ : mDeviceName(pDeviceNameEscaped) , mId() , mPaired(false) + , mIsPairing(false) , mNetworkVisible(false) , mConnected(false) , mSupported(false) @@ -87,6 +89,18 @@ void RemoteDeviceModelEntry::setPaired(bool pPaired) { mPaired = pPaired; +} + + +bool RemoteDeviceModelEntry::isPairing() const +{ + return mIsPairing; +} + + +void RemoteDeviceModelEntry::setIsPairing(bool pIsPairing) +{ + mIsPairing = pIsPairing; } @@ -191,7 +205,9 @@ roles.insert(IS_NETWORK_VISIBLE, QByteArrayLiteral("isNetworkVisible")); roles.insert(IS_SUPPORTED, QByteArrayLiteral("isSupported")); roles.insert(IS_PAIRED, QByteArrayLiteral("isPaired")); + roles.insert(IS_PAIRING, QByteArrayLiteral("isPairing")); roles.insert(LINK_QUALITY, QByteArrayLiteral("linkQualityInPercent")); + roles.insert(IS_LAST_ADDED_DEVICE, QByteArrayLiteral("isLastAddedDevice")); return roles; } @@ -220,6 +236,12 @@ { //: LABEL ALL_PLATFORMS return tr("Not connected"); + } + + if (pRemoteDeviceModelEntry.isPairing()) + { + //: LABEL ALL_PLATFORMS + return tr("Click to pair"); } if (pRemoteDeviceModelEntry.isPaired()) @@ -235,7 +257,7 @@ return tr("Paired, but unsupported"); } //: LABEL ALL_PLATFORMS - return tr("Paired, but unavailable"); + return tr("Unavailable"); } if (!pRemoteDeviceModelEntry.isSupported()) @@ -259,6 +281,7 @@ bool visible = false; bool connected = false; bool supported = true; + bool isPairing = false; QSharedPointer deviceListEntry; for (const auto& availableReader : availableReaders) { @@ -267,6 +290,7 @@ visible = true; connected = connectedDeviceIDs.contains(availableReader.getId()); supported = availableReader.isSupported(); + isPairing = availableReader.isPairing(); deviceListEntry = availableReader.getRemoteDeviceListEntry(); break; } @@ -284,6 +308,7 @@ visible, connected, supported, + isPairing, pairedReader.getLastConnected(), deviceListEntry); addOrUpdateReader(modelEntry); @@ -336,10 +361,9 @@ const auto& announcingRemoteDevices = Env::getSingleton()->getAnnouncingRemoteDevices(); QVector presentReaders; - for (auto deviceListEntry : announcingRemoteDevices) - { - const auto& deviceDescriptor = deviceListEntry->getIfdDescriptor(); - auto modelEntry = RemoteDeviceModelEntry(RemoteServiceSettings::escapeDeviceName(deviceDescriptor.getIfdName()), deviceDescriptor.getIfdId(), deviceListEntry); + for (auto& deviceListEntry : announcingRemoteDevices) + { + auto modelEntry = RemoteDeviceModelEntry(deviceListEntry); presentReaders.append(modelEntry); } @@ -382,6 +406,7 @@ const auto& reader = mAllRemoteReaders.at(pIndex.row()); switch (pRole) { + case Qt::DisplayRole: case REMOTE_DEVICE_NAME: return reader.getDeviceNameEscaped(); @@ -391,6 +416,8 @@ case LAST_CONNECTED: { const auto& locale = LanguageLoader::getInstance().getUsedLocale(); + + //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP"); return locale.toString(reader.getLastConnected(), dateTimeFormat); } @@ -407,8 +434,14 @@ case IS_PAIRED: return isPaired(pIndex); + case IS_PAIRING: + return isPairing(pIndex); + case LINK_QUALITY: return reader.getLinkQuality(); + + case IS_LAST_ADDED_DEVICE: + return mLastPairedDevice.getFingerprint() == reader.getId(); } return QVariant(); @@ -448,6 +481,17 @@ } return mAllRemoteReaders.at(pIndex.row()).isPaired(); +} + + +bool RemoteDeviceModel::isPairing(const QModelIndex& pIndex) const +{ + if (!indexIsValid(pIndex)) + { + return false; + } + + return mAllRemoteReaders.at(pIndex.row()).isPairing(); } @@ -585,6 +629,14 @@ } +void RemoteDeviceModel::setLastPairedReader(const QSslCertificate& pCert) +{ + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + mLastPairedDevice = settings.getRemoteInfo(pCert); + Q_EMIT dataChanged(index(0), index(rowCount() - 1), {IS_LAST_ADDED_DEVICE}); +} + + void RemoteDeviceModel::onDeviceDisconnected(GlobalStatus::Code pCloseCode, const QString& pId) { Q_UNUSED(pCloseCode) diff --git a/src/ui/qml/RemoteDeviceModel.h b/src/ui/qml/RemoteDeviceModel.h index 5fe5a91..a052888 100644 --- a/src/ui/qml/RemoteDeviceModel.h +++ b/src/ui/qml/RemoteDeviceModel.h @@ -21,6 +21,7 @@ #include class test_RemoteDeviceModel; +class test_RemoteDeviceFilterModel; namespace governikus { @@ -33,6 +34,7 @@ QString mDeviceName; QString mId; bool mPaired; + bool mIsPairing; bool mNetworkVisible; bool mConnected; bool mSupported; @@ -40,20 +42,21 @@ QSharedPointer mRemoteDeviceListEntry; public: - RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, - const QString& mId, - const QSharedPointer& pRemoteDeviceListEntry); + explicit RemoteDeviceModelEntry(const QSharedPointer& pListEntry); RemoteDeviceModelEntry(const QString& pDeviceNameEscaped, const QString& mId, bool pNetworkVisible, bool pConnected, bool pSupported, + bool pIsPairing, const QDateTime& pLastConnected, const QSharedPointer& pRemoteDeviceListEntry); explicit RemoteDeviceModelEntry(const QString& pDeviceNameEscaped = QStringLiteral("UnknownReader")); [[nodiscard]] bool isPaired() const; void setPaired(bool pPaired); + [[nodiscard]] bool isPairing() const; + void setIsPairing(bool pIsPairing); [[nodiscard]] const QString& getId() const; void setId(const QString& pId); [[nodiscard]] bool isNetworkVisible() const; @@ -75,10 +78,12 @@ Q_OBJECT Q_PROPERTY(QString emptyListDescriptionString READ getEmptyListDescriptionString NOTIFY fireModelChanged) friend class ::test_RemoteDeviceModel; + friend class ::test_RemoteDeviceFilterModel; private: QMap mPairedReaders; QVector mAllRemoteReaders; + RemoteServiceSettings::RemoteInfo mLastPairedDevice; const bool mShowPairedReaders; const bool mShowUnpairedReaders; QTimer mTimer; @@ -112,7 +117,9 @@ IS_NETWORK_VISIBLE, IS_SUPPORTED, IS_PAIRED, - LINK_QUALITY + IS_PAIRING, + LINK_QUALITY, + IS_LAST_ADDED_DEVICE }; RemoteDeviceModel(QObject* pParent = nullptr, bool pShowPairedReaders = true, bool pShowUnpairedReaders = true); @@ -124,11 +131,14 @@ [[nodiscard]] QSharedPointer getRemoteDeviceListEntry(const QModelIndex& pIndex) const; [[nodiscard]] QSharedPointer getRemoteDeviceListEntry(const QString& pDeviceId) const; [[nodiscard]] bool isPaired(const QModelIndex& pIndex) const; + [[nodiscard]] bool isPairing(const QModelIndex& pIndex) const; [[nodiscard]] bool isSupported(const QModelIndex& pIndex) const; void forgetDevice(const QModelIndex& pIndex); void forgetDevice(const QString& pDeviceId); [[nodiscard]] QString getEmptyListDescriptionString() const; + + void setLastPairedReader(const QSslCertificate& pCert); public Q_SLOTS: void setDetectRemoteDevices(bool pNewStatus); diff --git a/src/ui/qml/RemoteServiceModel.cpp b/src/ui/qml/RemoteServiceModel.cpp index 1daf081..ad4e070 100644 --- a/src/ui/qml/RemoteServiceModel.cpp +++ b/src/ui/qml/RemoteServiceModel.cpp @@ -17,6 +17,12 @@ using namespace governikus; + + +namespace +{ +const QRegularExpression percentMatcher = QRegularExpression(QStringLiteral("(\\s|^)(100|\\d{1,2}) ?%")); +} // namespace RemoteServiceModel::RemoteServiceModel() @@ -28,8 +34,10 @@ , mPairingRequested(false) , mErrorMessage() , mPsk() - , mAvailableRemoteDevices(this, false, true) - , mKnownDevices(this, true, false) + , mAllDevices(this, true, true) + , mAvailableDevicesInPairingMode(&mAllDevices, RemoteDeviceFilterModel::showActivePairingMode) + , mAvailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showAvailableAndPaired) + , mUnavailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showUnavailableAndPaired) , mConnectionInfo() , mConnectedServerDeviceNames() , mRememberedServerEntry() @@ -42,6 +50,11 @@ , mRequiresLocalNetworkPermission(false) #endif { + QQmlEngine::setObjectOwnership(&mAllDevices, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mAvailableDevicesInPairingMode, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mAvailablePairedDevices, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(&mUnavailablePairedDevices, QQmlEngine::CppOwnership); + const auto readerManager = Env::getSingleton(); connect(readerManager, &ReaderManager::firePluginAdded, this, &RemoteServiceModel::onEnvironmentChanged); connect(readerManager, &ReaderManager::fireStatusChanged, this, &RemoteServiceModel::onEnvironmentChanged); @@ -59,6 +72,14 @@ connect(ifdClient, &IfdClient::fireDeviceVanished, this, &RemoteServiceModel::fireRemoteReaderVisibleChanged); connect(ifdClient, &IfdClient::fireCertificateRemoved, this, &RemoteServiceModel::fireCertificateRemoved); + connect(this, &WorkflowModel::fireReaderPlugInTypeChanged, this, &RemoteServiceModel::onReaderPlugInTypesChanged); + + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + connect(&settings, &RemoteServiceSettings::fireInitialDeviceNameSet, this, [](const QString& pName){ + //: LABEL ALL_PLATFORMS + Env::getSingleton()->showFeedback(tr("Pairing with %1 successful.").arg(pName)); + }); + QMetaObject::invokeMethod(this, &RemoteServiceModel::onEnvironmentChanged, Qt::QueuedConnection); } @@ -114,9 +135,41 @@ } +void RemoteServiceModel::onPairingCompleted(const QSslCertificate& pCertificate) +{ + mAllDevices.setLastPairedReader(pCertificate); + Q_EMIT firePairingCompleted(); +} + + void RemoteServiceModel::onTranslationChanged() { onEnvironmentChanged(); +} + + +void RemoteServiceModel::onReaderPlugInTypesChanged(bool pExplicitStart) +{ + if (!mContext) + { + return; + } + + const auto& plugInType = getReaderPlugInType(); + if (mContext->getIfdServer() && mContext->getIfdServer()->getMessageHandler()) + { + mContext->getIfdServer()->getMessageHandler()->setAllowedCardTypes({plugInType}); + } + auto* readerManager = Env::getSingleton(); + readerManager->stopScanAll(); +#ifdef Q_OS_IOS + if (plugInType != ReaderManagerPlugInType::NFC || pExplicitStart) +#else + Q_UNUSED(pExplicitStart) +#endif + { + readerManager->startScan(plugInType); + } } @@ -170,22 +223,33 @@ } -RemoteDeviceModel* RemoteServiceModel::getAvailableRemoteDevices() -{ - return &mAvailableRemoteDevices; -} - - -RemoteDeviceModel* RemoteServiceModel::getKnownDevices() -{ - return &mKnownDevices; +RemoteDeviceModel* RemoteServiceModel::getAllDevices() +{ + return &mAllDevices; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getAvailablePairedDevices() +{ + return &mAvailablePairedDevices; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getAvailableDevicesInPairingMode() +{ + return &mAvailableDevicesInPairingMode; +} + + +RemoteDeviceFilterModel* RemoteServiceModel::getUnavailablePairedDevices() +{ + return &mUnavailablePairedDevices; } void RemoteServiceModel::setDetectRemoteDevices(bool pNewStatus) { - mAvailableRemoteDevices.setDetectRemoteDevices(pNewStatus); - mKnownDevices.setDetectRemoteDevices(pNewStatus); + mAllDevices.setDetectRemoteDevices(pNewStatus); } @@ -208,9 +272,21 @@ } +QVector RemoteServiceModel::getSupportedReaderPlugInTypes() const +{ +#if __has_include("SmartManager.h") + return {ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SMART}; + +#else + return {ReaderManagerPlugInType::NFC}; + +#endif +} + + bool RemoteServiceModel::rememberServer(const QString& pDeviceId) { - mRememberedServerEntry = mAvailableRemoteDevices.getRemoteDeviceListEntry(pDeviceId); + mRememberedServerEntry = mAllDevices.getRemoteDeviceListEntry(pDeviceId); return !mRememberedServerEntry.isNull(); } @@ -227,7 +303,7 @@ } else { - Q_EMIT firePairingSuccess(deviceName); + Q_EMIT firePairingSuccess(); } } @@ -236,11 +312,13 @@ { if (mContext && pConnected) { - const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); - const QString peerName = settings.getRemoteInfo(mContext->getIfdServer()->getCurrentCertificate()).getNameEscaped(); //: INFO ANDROID IOS The smartphone is connected as card reader (SaK) and currently processing an authentication request. The user is asked to pay attention the its screen. - mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(peerName); + mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(getConnectedClientName()); Q_EMIT fireConnectionInfoChanged(); + } + else if (mContext) + { + mContext->setReaderPlugInTypes({}); } Q_EMIT fireConnectedChanged(); } @@ -275,8 +353,9 @@ mPsk = pPsk; }); connect(mContext->getIfdServer().data(), &IfdServer::firePskChanged, this, &RemoteServiceModel::firePskChanged); + connect(mContext.data(), &IfdServiceContext::fireDisplayTextChanged, this, &RemoteServiceModel::fireDisplayTextChanged); connect(mContext->getIfdServer().data(), &IfdServer::fireConnectedChanged, this, &RemoteServiceModel::onConnectionInfoChanged); - connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::firePairingCompleted); + connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::onPairingCompleted); connect(mContext.data(), &IfdServiceContext::fireCardConnected, this, &RemoteServiceModel::onCardConnected); connect(mContext.data(), &IfdServiceContext::fireCardDisconnected, this, &RemoteServiceModel::onCardDisconnected); connect(mContext.data(), &IfdServiceContext::fireEstablishPaceChannelUpdated, this, &RemoteServiceModel::fireEstablishPaceChannelUpdated); @@ -357,6 +436,20 @@ } +QString RemoteServiceModel::getDisplayText() const +{ + QString displayText = mContext ? mContext->getDisplayText() : QString(); + return displayText.remove(percentMatcher); +} + + +int RemoteServiceModel::getPercentage() const +{ + QString displayText = mContext ? mContext->getDisplayText() : QString(); + return percentMatcher.match(displayText).captured(2).toInt(); +} + + QString RemoteServiceModel::getConnectionInfo() const { return mConnectionInfo; @@ -372,6 +465,25 @@ bool RemoteServiceModel::getRemoteReaderVisible() const { return Env::getSingleton()->hasAnnouncingRemoteDevices(); +} + + +QString RemoteServiceModel::getTransactionInfo() const +{ + return QString(); +} + + +QString RemoteServiceModel::getConnectedClientName() const +{ + if (mContext) + { + const auto& sslCertificate = mContext->getIfdServer()->getCurrentCertificate(); + const RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + return settings.getRemoteInfo(sslCertificate).getNameEscaped(); + } + + return QString(); } @@ -405,7 +517,7 @@ void RemoteServiceModel::forgetDevice(const QString& pId) { - mKnownDevices.forgetDevice(pId); + mAllDevices.forgetDevice(pId); } diff --git a/src/ui/qml/RemoteServiceModel.h b/src/ui/qml/RemoteServiceModel.h index 6b1741e..efc04af 100644 --- a/src/ui/qml/RemoteServiceModel.h +++ b/src/ui/qml/RemoteServiceModel.h @@ -10,6 +10,7 @@ #include "Env.h" #include "ReaderManager.h" +#include "RemoteDeviceFilterModel.h" #include "RemoteDeviceModel.h" #include "WorkflowModel.h" #include "WorkflowRequest.h" @@ -34,15 +35,21 @@ Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY fireEnvironmentChanged) Q_PROPERTY(bool isPairing READ isPairing NOTIFY firePskChanged) Q_PROPERTY(QByteArray psk READ getPsk NOTIFY firePskChanged) + Q_PROPERTY(QString displayText READ getDisplayText NOTIFY fireDisplayTextChanged) + Q_PROPERTY(int percentage READ getPercentage NOTIFY fireDisplayTextChanged) Q_PROPERTY(bool connectedToPairedDevice READ isConnectedToPairedDevice NOTIFY fireConnectedChanged) Q_PROPERTY(QString connectionInfo READ getConnectionInfo NOTIFY fireConnectionInfoChanged) Q_PROPERTY(QString connectedServerDeviceNames READ getConnectedServerDeviceNames NOTIFY fireConnectedServerDeviceNamesChanged) - Q_PROPERTY(RemoteDeviceModel * availableRemoteDevices READ getAvailableRemoteDevices CONSTANT) - Q_PROPERTY(RemoteDeviceModel * knownDevices READ getKnownDevices CONSTANT) + Q_PROPERTY(RemoteDeviceModel * allDevices READ getAllDevices CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * availableDevicesInPairingMode READ getAvailableDevicesInPairingMode CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * availablePairedDevices READ getAvailablePairedDevices CONSTANT) + Q_PROPERTY(RemoteDeviceFilterModel * unavailablePairedDevices READ getUnavailablePairedDevices CONSTANT) Q_PROPERTY(bool detectRemoteDevices READ detectRemoteDevices WRITE setDetectRemoteDevices NOTIFY fireDetectionChanged) Q_PROPERTY(bool enableTransportPinLink READ enableTransportPinLink NOTIFY fireEstablishPaceChannelUpdated) Q_PROPERTY(bool remoteReaderVisible READ getRemoteReaderVisible NOTIFY fireRemoteReaderVisibleChanged) Q_PROPERTY(bool requiresLocalNetworkPermission MEMBER mRequiresLocalNetworkPermission CONSTANT) + Q_PROPERTY(QString transactionInfo READ getTransactionInfo NOTIFY fireTransactionInfoChanged) + Q_PROPERTY(QString connectedClientName READ getConnectedClientName NOTIFY fireConnectionInfoChanged) private: QSharedPointer mContext; @@ -52,8 +59,10 @@ bool mPairingRequested; QString mErrorMessage; QByteArray mPsk; - RemoteDeviceModel mAvailableRemoteDevices; - RemoteDeviceModel mKnownDevices; + RemoteDeviceModel mAllDevices; + RemoteDeviceFilterModel mAvailableDevicesInPairingMode; + RemoteDeviceFilterModel mAvailablePairedDevices; + RemoteDeviceFilterModel mUnavailablePairedDevices; QString mConnectionInfo; QString mConnectedServerDeviceNames; QSharedPointer mRememberedServerEntry; @@ -78,21 +87,27 @@ void onConnectedDevicesChanged(); void onEnvironmentChanged(); void onApplicationStateChanged(const bool pIsAppInForeground); + void onPairingCompleted(const QSslCertificate& pCertificate); public Q_SLOTS: void onTranslationChanged(); + void onReaderPlugInTypesChanged(bool pExplicitStart); public: [[nodiscard]] bool isRunning() const; Q_INVOKABLE void setRunning(bool pState, bool pEnablePairing = false); [[nodiscard]] bool isStarting() const; - [[nodiscard]] RemoteDeviceModel* getAvailableRemoteDevices(); - [[nodiscard]] RemoteDeviceModel* getKnownDevices(); + + [[nodiscard]] RemoteDeviceModel* getAllDevices(); + [[nodiscard]] RemoteDeviceFilterModel* getAvailableDevicesInPairingMode(); + [[nodiscard]] RemoteDeviceFilterModel* getAvailablePairedDevices(); + [[nodiscard]] RemoteDeviceFilterModel* getUnavailablePairedDevices(); void setDetectRemoteDevices(bool pNewStatus); [[nodiscard]] bool detectRemoteDevices() const; Q_INVOKABLE bool rememberServer(const QString& pDeviceId); Q_INVOKABLE void connectToRememberedServer(const QString& pServerPsk); + [[nodiscard]] QVector getSupportedReaderPlugInTypes() const override; void resetRemoteServiceContext(const QSharedPointer& pContext = QSharedPointer()); void setPairing(bool pEnabled); @@ -103,9 +118,13 @@ [[nodiscard]] bool isCanEnableNfc() const; [[nodiscard]] QString getErrorMessage() const; [[nodiscard]] QByteArray getPsk() const; + [[nodiscard]] QString getDisplayText() const; + [[nodiscard]] int getPercentage() const; [[nodiscard]] QString getConnectionInfo() const; [[nodiscard]] QString getConnectedServerDeviceNames() const; [[nodiscard]] bool getRemoteReaderVisible() const; + [[nodiscard]] QString getTransactionInfo() const; + [[nodiscard]] QString getConnectedClientName() const; [[nodiscard]] Q_INVOKABLE bool pinPadModeOn() const; Q_INVOKABLE void forgetDevice(const QString& pId); @@ -118,17 +137,19 @@ void fireIsRunningChanged(); void fireEnvironmentChanged(); void firePskChanged(const QByteArray& pPsk); + void fireDisplayTextChanged(); void fireConnectedChanged(); void fireServerPskChanged(); void fireDetectionChanged(); void firePairingFailed(const QString& pDeviceName, const QString& pErrorMessage); - void firePairingSuccess(const QString& pDeviceName); + void firePairingSuccess(); void firePairingCompleted(); void fireConnectionInfoChanged(); void fireConnectedServerDeviceNamesChanged(); void fireRemoteReaderVisibleChanged(); void fireEstablishPaceChannelUpdated(); void fireCertificateRemoved(const QString& pDeviceName); + void fireTransactionInfoChanged(); }; diff --git a/src/ui/qml/SettingsModel.cpp b/src/ui/qml/SettingsModel.cpp index 95e89d4..fb1ce3b 100644 --- a/src/ui/qml/SettingsModel.cpp +++ b/src/ui/qml/SettingsModel.cpp @@ -165,8 +165,29 @@ void SettingsModel::setPinPadMode(bool pPinPadMode) { - auto& settings = Env::getSingleton()->getRemoteServiceSettings(); - settings.setPinPadMode(pPinPadMode); + if (getPinPadMode() != pPinPadMode) + { + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setPinPadMode(pPinPadMode); + Q_EMIT firePinPadModeChanged(); + } +} + + +bool SettingsModel::getShowAccessRights() const +{ + return Env::getSingleton()->getRemoteServiceSettings().getShowAccessRights(); +} + + +void SettingsModel::setShowAccessRights(bool pShowAccessRights) +{ + if (getShowAccessRights() != pShowAccessRights) + { + auto& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.setShowAccessRights(pShowAccessRights); + Q_EMIT fireShowAccessRightsChanged(); + } } diff --git a/src/ui/qml/SettingsModel.h b/src/ui/qml/SettingsModel.h index 77c8096..374de48 100644 --- a/src/ui/qml/SettingsModel.h +++ b/src/ui/qml/SettingsModel.h @@ -31,6 +31,7 @@ Q_PROPERTY(bool showBetaTesting MEMBER mShowBetaTesting NOTIFY fireDeveloperOptionsChanged) Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri NOTIFY fireDeveloperOptionsChanged) Q_PROPERTY(bool pinPadMode READ getPinPadMode WRITE setPinPadMode NOTIFY firePinPadModeChanged) + Q_PROPERTY(bool showAccessRights READ getShowAccessRights WRITE setShowAccessRights NOTIFY fireShowAccessRightsChanged) Q_PROPERTY(QString serverName READ getServerName WRITE setServerName NOTIFY fireDeviceNameChanged) Q_PROPERTY(bool historyEnabled READ isHistoryEnabled WRITE setHistoryEnabled NOTIFY fireHistoryEnabledChanged) Q_PROPERTY(bool useScreenKeyboard READ isUseScreenKeyboard WRITE setUseScreenKeyboard NOTIFY fireScreenKeyboardChanged) @@ -88,6 +89,9 @@ [[nodiscard]] bool getPinPadMode() const; void setPinPadMode(bool pPinPadMode); + + [[nodiscard]] bool getShowAccessRights() const; + void setShowAccessRights(bool pShowAccessRights); [[nodiscard]] bool isHistoryEnabled() const; void setHistoryEnabled(bool pEnabled); @@ -156,6 +160,7 @@ void fireDeveloperOptionsChanged(); void fireDeviceNameChanged(); void firePinPadModeChanged(); + void fireShowAccessRightsChanged(); void fireHistoryEnabledChanged(); void fireScreenKeyboardChanged(); void fireCanAllowedChanged(); diff --git a/src/ui/qml/UIPlugInQml.cpp b/src/ui/qml/UIPlugInQml.cpp index 7bbce88..527fde5 100644 --- a/src/ui/qml/UIPlugInQml.cpp +++ b/src/ui/qml/UIPlugInQml.cpp @@ -407,6 +407,8 @@ if (auto remoteServiceContext = pContext.objectCast()) { Env::getSingleton()->resetRemoteServiceContext(remoteServiceContext); + Env::getSingleton()->resetContext(remoteServiceContext); + Env::getSingleton()->resetContext(remoteServiceContext); } } @@ -456,6 +458,8 @@ if (pContext.objectCast()) { Env::getSingleton()->resetRemoteServiceContext(); + Env::getSingleton()->resetContext(); + Env::getSingleton()->resetContext(); } #if __has_include("context/PersonalizationContext.h") diff --git a/src/ui/qml/WorkflowModel.cpp b/src/ui/qml/WorkflowModel.cpp index 081c463..d37c06f 100644 --- a/src/ui/qml/WorkflowModel.cpp +++ b/src/ui/qml/WorkflowModel.cpp @@ -56,6 +56,7 @@ connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &WorkflowModel::fireResultChanged); connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &WorkflowModel::fireReaderPlugInTypeChanged); connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireSelectedReaderChanged); + connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireHasCardChanged); connect(mContext.data(), &WorkflowContext::fireIsSmartCardAllowedChanged, this, &WorkflowModel::fireIsSmartCardAllowedChanged); connect(mContext.data(), &WorkflowContext::fireNextWorkflowPending, this, &WorkflowModel::fireNextWorkflowPendingChanged); connect(mContext.data(), &WorkflowContext::fireRemoveCardFeedbackChanged, this, &WorkflowModel::fireRemoveCardFeedbackChanged); @@ -159,11 +160,11 @@ } -void WorkflowModel::startScanIfNecessary() +void WorkflowModel::startScanExplicitly() { if (mContext) { - Q_EMIT mContext->fireReaderPlugInTypesChanged(); + Q_EMIT mContext->fireReaderPlugInTypesChanged(true); } } @@ -187,6 +188,19 @@ } return false; +} + + +bool WorkflowModel::hasCard() const +{ + if (!mContext) + { + return false; + } + + const auto& readerInfos = Env::getSingleton()->getReaderInfos(ReaderFilter({getReaderPlugInType()})); + const auto& readersWithEid = filter([](const ReaderInfo& i){return i.hasEid();}, readerInfos); + return !readersWithEid.isEmpty(); } @@ -465,4 +479,6 @@ mReaderImage = newReaderImage; Q_EMIT fireReaderImageChanged(); } -} + + Q_EMIT fireHasCardChanged(); +} diff --git a/src/ui/qml/WorkflowModel.h b/src/ui/qml/WorkflowModel.h index 287818f..9012e6d 100644 --- a/src/ui/qml/WorkflowModel.h +++ b/src/ui/qml/WorkflowModel.h @@ -39,6 +39,7 @@ Q_PROPERTY(QString statusHintText READ getStatusHintText NOTIFY fireResultChanged) Q_PROPERTY(QString statusHintActionText READ getStatusHintActionText NOTIFY fireResultChanged) Q_PROPERTY(bool showRemoveCardFeedback READ showRemoveCardFeedback WRITE setRemoveCardFeedback NOTIFY fireRemoveCardFeedbackChanged) + Q_PROPERTY(bool hasCard READ hasCard NOTIFY fireHasCardChanged) friend class ::test_WorkflowModel; private: @@ -65,6 +66,7 @@ [[nodiscard]] bool isBasicReader() const; [[nodiscard]] bool isRemoteReader() const; + [[nodiscard]] bool hasCard() const; [[nodiscard]] bool isSmartCardAllowed() const; @@ -86,7 +88,7 @@ Q_INVOKABLE void insertSmartCard(); Q_INVOKABLE void insertSimulator(); Q_INVOKABLE void cancelWorkflow(); - Q_INVOKABLE void startScanIfNecessary(); + Q_INVOKABLE void startScanExplicitly(); Q_INVOKABLE void continueWorkflow(); Q_INVOKABLE void setInitialPluginType(); [[nodiscard]] Q_INVOKABLE bool shouldSkipResultView() const; @@ -104,13 +106,14 @@ Q_SIGNALS: void fireCurrentStateChanged(const QString& pState); void fireResultChanged(); - void fireReaderPlugInTypeChanged(); + void fireReaderPlugInTypeChanged(bool pExplicitStart = false); void fireSelectedReaderChanged(); void fireIsSmartCardAllowedChanged(); void fireReaderImageChanged(); void fireNextWorkflowPendingChanged(); void fireSupportedPlugInTypesChanged(); void fireRemoveCardFeedbackChanged(); + void fireHasCardChanged(); }; diff --git a/src/workflows/base/context/AccessRightManager.cpp b/src/workflows/base/context/AccessRightManager.cpp index bb20512..ac12bee 100644 --- a/src/workflows/base/context/AccessRightManager.cpp +++ b/src/workflows/base/context/AccessRightManager.cpp @@ -68,6 +68,18 @@ } mEffectiveAccessRights = mRequiredAccessRights + mOptionalAccessRights; +} + + +AccessRightManager::AccessRightManager(QSharedPointer pRequiredChat) + : QObject() + , mTerminalCvc() + , mDIDAuthenticateEAC1() + , mOptionalAccessRights() + , mEffectiveAccessRights(pRequiredChat->getAccessRights()) + , mRequiredAccessRights(pRequiredChat->getAccessRights()) +{ + } diff --git a/src/workflows/base/context/AccessRightManager.h b/src/workflows/base/context/AccessRightManager.h index 564bdfd..b866fdb 100644 --- a/src/workflows/base/context/AccessRightManager.h +++ b/src/workflows/base/context/AccessRightManager.h @@ -29,6 +29,7 @@ public: explicit AccessRightManager(QSharedPointer pDIDAuthenticateEAC1, QSharedPointer pTerminalCvc); + explicit AccessRightManager(QSharedPointer pRequiredChat); [[nodiscard]] const QSharedPointer& getTerminalCvc() const diff --git a/src/workflows/base/context/WorkflowContext.cpp b/src/workflows/base/context/WorkflowContext.cpp index 26ee92f..2156879 100644 --- a/src/workflows/base/context/WorkflowContext.cpp +++ b/src/workflows/base/context/WorkflowContext.cpp @@ -47,6 +47,7 @@ , mProgressMessage() , mShowRemoveCardFeedback(false) , mClaimedBy() + , mInterruptRequested(false) { connect(this, &WorkflowContext::fireCancelWorkflow, this, &WorkflowContext::onWorkflowCancelled); } @@ -596,3 +597,15 @@ || acceptedEidTypes.contains(AcceptedEidType::SE_ENDORSED) || acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE)); } + + +bool WorkflowContext::interruptRequested() const +{ + return mInterruptRequested; +} + + +void WorkflowContext::setInterruptRequested(bool pInterruptRequested) +{ + mInterruptRequested = pInterruptRequested; +} diff --git a/src/workflows/base/context/WorkflowContext.h b/src/workflows/base/context/WorkflowContext.h index cb43963..c0e2213 100644 --- a/src/workflows/base/context/WorkflowContext.h +++ b/src/workflows/base/context/WorkflowContext.h @@ -66,6 +66,7 @@ QString mProgressMessage; bool mShowRemoveCardFeedback; QString mClaimedBy; + bool mInterruptRequested; private Q_SLOTS: void onWorkflowCancelled(); @@ -73,7 +74,7 @@ Q_SIGNALS: void fireStateApprovedChanged(bool pApproved); void fireStateChanged(const QString& pNewState); - void fireReaderPlugInTypesChanged(); + void fireReaderPlugInTypesChanged(bool pExplicitStart = false); void fireReaderInfoChanged(); void fireReaderNameChanged(); void fireCardConnectionChanged(); @@ -220,6 +221,9 @@ [[nodiscard]] virtual QVector getAcceptedEidTypes() const = 0; bool isPhysicalCardRequired() const; + + [[nodiscard]] bool interruptRequested() const; + void setInterruptRequested(bool pInterruptRequested); }; } // namespace governikus diff --git a/src/workflows/base/states/AbstractState.cpp b/src/workflows/base/states/AbstractState.cpp index b2bcf92..05f8cab 100644 --- a/src/workflows/base/states/AbstractState.cpp +++ b/src/workflows/base/states/AbstractState.cpp @@ -195,17 +195,6 @@ } -void AbstractState::startNfcScanIfNecessary() -{ -#if defined(Q_OS_IOS) - if (isStartStopEnabled()) - { - Env::getSingleton()->startScan(ReaderManagerPlugInType::NFC); - } -#endif -} - - void AbstractState::stopNfcScanIfNecessary(const QString& pError) { #if defined(Q_OS_IOS) diff --git a/src/workflows/base/states/AbstractState.h b/src/workflows/base/states/AbstractState.h index afb6035..876aa10 100644 --- a/src/workflows/base/states/AbstractState.h +++ b/src/workflows/base/states/AbstractState.h @@ -47,7 +47,6 @@ void updateStatus(const GlobalStatus& pStatus); void updateStartPaosResult(const ECardApiResult& pStartPaosResult); - void startNfcScanIfNecessary(); void stopNfcScanIfNecessary(const QString& pError = QString()); public: diff --git a/src/workflows/base/states/StateCheckRefreshAddress.cpp b/src/workflows/base/states/StateCheckRefreshAddress.cpp index 76dc288..c2cfddf 100644 --- a/src/workflows/base/states/StateCheckRefreshAddress.cpp +++ b/src/workflows/base/states/StateCheckRefreshAddress.cpp @@ -173,7 +173,7 @@ if (TlsChecker::containsFatalError(mReply, pErrors)) { reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()} - }, FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply); + }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_Before_Reply); } } @@ -273,7 +273,7 @@ case NetworkManager::NetworkError::SecurityError: reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()} - }, FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_After_Reply, mReply->errorString()); + }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_After_Reply, mReply->errorString()); break; case NetworkManager::NetworkError::OtherError: diff --git a/src/workflows/base/states/StateCleanUpReaderManager.cpp b/src/workflows/base/states/StateCleanUpReaderManager.cpp index d1a979d..039f85c 100644 --- a/src/workflows/base/states/StateCleanUpReaderManager.cpp +++ b/src/workflows/base/states/StateCleanUpReaderManager.cpp @@ -21,9 +21,7 @@ void StateCleanUpReaderManager::run() { const QSharedPointer context = getContext(); - - const auto& reader = context->getReaderName(); - if (!reader.isEmpty() && !context->getStatus().isError()) + if (const auto& reader = context->getReaderName(); !reader.isEmpty()) { const auto& readerInfo = Env::getSingleton()->getReaderInfo(reader); if (readerInfo.hasCard() && readerInfo.getCardInfo().getCardType() != CardType::SMART_EID) diff --git a/src/workflows/base/states/StateDidAuthenticateEac2.cpp b/src/workflows/base/states/StateDidAuthenticateEac2.cpp index f8dfbae..0737a69 100644 --- a/src/workflows/base/states/StateDidAuthenticateEac2.cpp +++ b/src/workflows/base/states/StateDidAuthenticateEac2.cpp @@ -62,8 +62,8 @@ newStatus = GlobalStatus::Code::Workflow_Card_Removed; break; - case CardReturnCode::EXTENDED_LENGTH_MISSING: - newStatus = GlobalStatus::Code::Workflow_No_Extended_Length_Error; + case CardReturnCode::WRONG_LENGTH: + newStatus = GlobalStatus::Code::Workflow_Wrong_Length_Error; break; default: diff --git a/src/workflows/base/states/StateEnterPacePassword.cpp b/src/workflows/base/states/StateEnterPacePassword.cpp index 8811ae3..be4ef38 100644 --- a/src/workflows/base/states/StateEnterPacePassword.cpp +++ b/src/workflows/base/states/StateEnterPacePassword.cpp @@ -4,6 +4,7 @@ #include "StateEnterPacePassword.h" +#include "ReaderManager.h" #include "VolatileSettings.h" @@ -14,6 +15,9 @@ : AbstractState(pContext) , GenericContextContainer(pContext) { + const auto& readerManager = Env::getSingleton(); + mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateEnterPacePassword::onReaderStatusChanged); + setKeepCardConnectionAlive(); } @@ -49,3 +53,29 @@ AbstractState::onEntry(pEvent); } + + +void StateEnterPacePassword::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const +{ +#if defined(Q_OS_IOS) + const auto& volatileSettings = Env::getSingleton(); + if (!volatileSettings->isUsedAsSDK() || pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) + { + return; + } + + if (!Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) + { + if (getContext()->interruptRequested()) + { + getContext()->setInterruptRequested(false); + } + else + { + Q_EMIT getContext()->fireCancelWorkflow(); + } + } +#else + Q_UNUSED(pInfo) +#endif +} diff --git a/src/workflows/base/states/StateEnterPacePassword.h b/src/workflows/base/states/StateEnterPacePassword.h index f2743e1..869348d 100644 --- a/src/workflows/base/states/StateEnterPacePassword.h +++ b/src/workflows/base/states/StateEnterPacePassword.h @@ -25,6 +25,9 @@ explicit StateEnterPacePassword(const QSharedPointer& pContext); void run() override; + private Q_SLOTS: + void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const; + public: void onEntry(QEvent* pEvent) override; diff --git a/src/workflows/base/states/StateEstablishPaceChannel.cpp b/src/workflows/base/states/StateEstablishPaceChannel.cpp index 5eee410..52b7609 100644 --- a/src/workflows/base/states/StateEstablishPaceChannel.cpp +++ b/src/workflows/base/states/StateEstablishPaceChannel.cpp @@ -22,21 +22,24 @@ void StateEstablishPaceChannel::run() { - if (getContext()->getStatus().isError()) - { - Q_ASSERT(getContext()->getFailureCode().has_value()); + const auto& context = getContext(); + Q_ASSERT(context); + + if (context->getStatus().isError()) + { + Q_ASSERT(context->getFailureCode().has_value()); Q_EMIT firePaceChannelFailed(); return; } QByteArray effectiveChat; QByteArray certificateDescription; - auto authContext = getContext().objectCast(); - mPasswordId = getContext()->getEstablishPaceChannelType(); + const auto& authContext = context.objectCast(); + mPasswordId = context->getEstablishPaceChannelType(); Q_ASSERT(mPasswordId != PacePasswordId::UNKNOWN); if (mPasswordId == PacePasswordId::PACE_PIN || - (mPasswordId == PacePasswordId::PACE_CAN && getContext()->isCanAllowedMode())) + (mPasswordId == PacePasswordId::PACE_CAN && context->isCanAllowedMode())) { if (authContext && authContext->getDidAuthenticateEac1()) { @@ -55,15 +58,15 @@ switch (mPasswordId) { case PacePasswordId::PACE_CAN: - password = getContext()->getCan().toLatin1(); + password = context->getCan().toLatin1(); break; case PacePasswordId::PACE_PIN: - password = getContext()->getPin().toLatin1(); + password = context->getPin().toLatin1(); break; case PacePasswordId::PACE_PUK: - password = getContext()->getPuk().toLatin1(); + password = context->getPuk().toLatin1(); break; case PacePasswordId::UNKNOWN: @@ -72,11 +75,11 @@ break; } - auto cardConnection = getContext()->getCardConnection(); + auto cardConnection = context->getCardConnection(); if (!cardConnection) { qCDebug(statemachine) << "No card connection available."; - getContext()->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND); + context->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND); Q_EMIT fireNoCardConnection(); return; } @@ -91,12 +94,15 @@ return; } + //: INFO ALL_PLATFORMS First status message after the PIN was entered. + context->setProgress(0, tr("The secure channel is opened")); + qDebug() << "Establish connection using" << mPasswordId; Q_ASSERT(!password.isEmpty() || !cardConnection->getReaderInfo().isBasicReader()); if (mPasswordId == PacePasswordId::PACE_PIN && !cardConnection->getReaderInfo().isBasicReader()) { - const auto pinContext = getContext().objectCast(); + const auto pinContext = context.objectCast(); if (pinContext && pinContext->isRequestTransportPin()) { password = QByteArray(5, 0); diff --git a/src/workflows/base/states/StateGenericProviderCommunication.cpp b/src/workflows/base/states/StateGenericProviderCommunication.cpp index 50c5b42..ce66842 100644 --- a/src/workflows/base/states/StateGenericProviderCommunication.cpp +++ b/src/workflows/base/states/StateGenericProviderCommunication.cpp @@ -124,7 +124,7 @@ } const GlobalStatus& status = {GlobalStatus::Code::Network_Ssl_Establishment_Error, infoMap}; - const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Ssl_Error, + const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Tls_Error, { {FailureCode::Info::Network_Error, mReply->errorString()}, {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)}, diff --git a/src/workflows/base/states/StateGenericSendReceive.cpp b/src/workflows/base/states/StateGenericSendReceive.cpp index 9e4f6b5..3289ffb 100644 --- a/src/workflows/base/states/StateGenericSendReceive.cpp +++ b/src/workflows/base/states/StateGenericSendReceive.cpp @@ -102,7 +102,7 @@ {FailureCode::Info::State_Name, getStateName()}, {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)} }; - Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Ssl_Error, infoMap}); + Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Tls_Error, infoMap}); } } diff --git a/src/workflows/base/states/StateMaintainCardConnection.cpp b/src/workflows/base/states/StateMaintainCardConnection.cpp index e66d70d..62e2392 100644 --- a/src/workflows/base/states/StateMaintainCardConnection.cpp +++ b/src/workflows/base/states/StateMaintainCardConnection.cpp @@ -42,7 +42,7 @@ case CardReturnCode::UNDEFINED: case CardReturnCode::COMMAND_FAILED: case CardReturnCode::PROTOCOL_ERROR: - case CardReturnCode::EXTENDED_LENGTH_MISSING: + case CardReturnCode::WRONG_LENGTH: case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS: { Q_ASSERT(!CardReturnCodeUtil::equalsWrongPacePassword(lastPaceResult)); diff --git a/src/workflows/base/states/StatePreVerification.cpp b/src/workflows/base/states/StatePreVerification.cpp index 4e203d6..5576dfa 100644 --- a/src/workflows/base/states/StatePreVerification.cpp +++ b/src/workflows/base/states/StatePreVerification.cpp @@ -53,7 +53,7 @@ { qCritical() << "Using the developer mode is only allowed in a test environment"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_No_Test_Environment); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_No_Test_Environment); return; } @@ -68,14 +68,14 @@ { qCritical() << "Pre-verification failed: cannot build certificate chain"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain); return; } else if (!SignatureChecker(certificateChain).check()) { qCritical() << "Pre-verification failed: signature check failed"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature); return; } else if (!isValid(certificateChain)) @@ -88,7 +88,7 @@ { qCritical() << "Pre-verification failed: certificate not valid"; updateStatus(GlobalStatus::Code::Workflow_Preverification_Error); - Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Certificate_Expired); + Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Certificate_Expired); return; } } diff --git a/src/workflows/ifd/context/IfdServiceContext.cpp b/src/workflows/ifd/context/IfdServiceContext.cpp index cc7145c..ca3d059 100644 --- a/src/workflows/ifd/context/IfdServiceContext.cpp +++ b/src/workflows/ifd/context/IfdServiceContext.cpp @@ -28,10 +28,12 @@ , mIfdServer(pIfdServer) , mNewPin() , mSlotHandle() + , mDisplayText() , mEstablishPaceChannel() , mRequestTransportPin(false) , mAllowToChangePinLength(false) , mEstablishPaceChannelOutput() + , mAccessRightManager() , mModifyPinMessage() , mModifyPinMessageResponseApdu() { @@ -116,10 +118,18 @@ mEstablishPaceChannel = pMessage->getInputData(); mRequestTransportPin = pMessage->getExpectedPinLength() == 5; mAllowToChangePinLength = isPinChangeWorkflow() && pMessage->getExpectedPinLength() == 0; + const auto& chat = mEstablishPaceChannel.getChat(); + if (!chat.isEmpty()) + { + const auto& requiredChat = CHAT::decode(chat); + mAccessRightManager = QSharedPointer::create(requiredChat); + Q_EMIT fireAccessRightManagerCreated(mAccessRightManager); + } } else { mSlotHandle.clear(); + mAccessRightManager.clear(); mEstablishPaceChannel = EstablishPaceChannel(); mRequestTransportPin = false; mAllowToChangePinLength = false; @@ -139,9 +149,43 @@ } +void IfdServiceContext::setDisplayText(const QString& pDisplayText) +{ + if (mDisplayText != pDisplayText) + { + mDisplayText = pDisplayText; + Q_EMIT fireDisplayTextChanged(); + } +} + + +const QString& IfdServiceContext::getDisplayText() const +{ + return mDisplayText; +} + + const EstablishPaceChannel& IfdServiceContext::getEstablishPaceChannel() const { return mEstablishPaceChannel; +} + + +QSharedPointer IfdServiceContext::getAccessRightManager() const +{ + return mAccessRightManager; +} + + +QSharedPointer IfdServiceContext::getCertificateDescription() const +{ + const auto& certDescription = mEstablishPaceChannel.getCertificateDescription(); + if (certDescription.isEmpty()) + { + return QSharedPointer(); + } + + return CertificateDescription::decode(certDescription); } @@ -232,9 +276,5 @@ [[nodiscard]] QVector IfdServiceContext::getAcceptedEidTypes() const { - if (mIfdServer->isLocal()) - { - return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE}; - } - return {AcceptedEidType::CARD_CERTIFIED}; -} + return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE}; +} diff --git a/src/workflows/ifd/context/IfdServiceContext.h b/src/workflows/ifd/context/IfdServiceContext.h index 986ee69..25430d6 100644 --- a/src/workflows/ifd/context/IfdServiceContext.h +++ b/src/workflows/ifd/context/IfdServiceContext.h @@ -9,6 +9,8 @@ #pragma once #include "IfdServer.h" +#include "asn1/CertificateDescription.h" +#include "context/AccessRightManager.h" #include "context/WorkflowContext.h" #include "messages/IfdEstablishPaceChannel.h" #include "messages/IfdModifyPin.h" @@ -32,10 +34,12 @@ QString mNewPin; QString mSlotHandle; + QString mDisplayText; EstablishPaceChannel mEstablishPaceChannel; bool mRequestTransportPin; bool mAllowToChangePinLength; EstablishPaceChannelOutput mEstablishPaceChannelOutput; + QSharedPointer mAccessRightManager; QSharedPointer mModifyPinMessage; ResponseApdu mModifyPinMessageResponseApdu; @@ -47,10 +51,12 @@ Q_SIGNALS: void fireCardConnected(const QSharedPointer& pConnection); + void fireDisplayTextChanged(); void fireCardDisconnected(const QSharedPointer& pConnection); void fireCancelPasswordRequest(); void fireEstablishPaceChannelUpdated(); void fireIsRunningChanged(); + void fireAccessRightManagerCreated(QSharedPointer pAccessRightManager); public: explicit IfdServiceContext(const QSharedPointer& pIfdServer); @@ -70,7 +76,11 @@ void setEstablishPaceChannel(const QSharedPointer& pMessage); [[nodiscard]] const QString& getSlotHandle() const; + void setDisplayText(const QString& pDisplayText); + [[nodiscard]] const QString& getDisplayText() const; [[nodiscard]] const EstablishPaceChannel& getEstablishPaceChannel() const; + [[nodiscard]] QSharedPointer getAccessRightManager() const; + [[nodiscard]] QSharedPointer getCertificateDescription() const; void changePinLength(); [[nodiscard]] bool allowToChangePinLength() const; diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.cpp b/src/workflows/ifd/states/StateProcessIfdMessages.cpp index e94515f..a0b4051 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.cpp +++ b/src/workflows/ifd/states/StateProcessIfdMessages.cpp @@ -29,10 +29,7 @@ const QSharedPointer server = context->getIfdServer(); Q_ASSERT(server); - mConnections += connect(Env::getSingleton(), &ReaderManager::fireStatusChanged, this, &StateProcessIfdMessages::onReaderStatusChanged); - mConnections += connect(Env::getSingleton(), &ReaderManager::fireReaderPropertiesUpdated, this, &StateProcessIfdMessages::onReaderPropertiesUpdated); mConnections += connect(server.data(), &IfdServer::fireMessageHandlerAdded, this, &StateProcessIfdMessages::onMessageHandlerAdded); - mConnections += connect(server.data(), &IfdServer::fireConnectedChanged, this, &StateProcessIfdMessages::onConnectedChanged); const auto messageHandler = server->getMessageHandler(); if (messageHandler) @@ -54,26 +51,12 @@ } mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireCardConnected, this, &StateProcessIfdMessages::onCardConnected, Qt::UniqueConnection); + mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireDisplayTextChanged, this, &StateProcessIfdMessages::onDisplayTextChanged, Qt::UniqueConnection); mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireEstablishPaceChannel, this, &StateProcessIfdMessages::onEstablishPaceChannel, Qt::UniqueConnection); mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireModifyPin, this, &StateProcessIfdMessages::onModifyPin, Qt::UniqueConnection); mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireCardDisconnected, this, &StateProcessIfdMessages::onCardDisconnected, Qt::UniqueConnection); mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::destroyed, this, &StateProcessIfdMessages::onClosed, Qt::UniqueConnection); mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireSecureMessagingStopped, this, &StateProcessIfdMessages::fireSecureMessagingStopped, Qt::UniqueConnection); -} - - -void StateProcessIfdMessages::onConnectedChanged(bool pConnected) -{ - if (pConnected && !getContext()->getIfdServer()->isPairingConnection()) - { - startNfcScanIfNecessary(); - Env::getSingleton()->startScan(ReaderManagerPlugInType::SMART); - } - else - { - stopNfcScanIfNecessary(); - Env::getSingleton()->stopScan(ReaderManagerPlugInType::SMART); - } } @@ -90,42 +73,15 @@ } -void StateProcessIfdMessages::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) +void StateProcessIfdMessages::onCardConnected() { - if (pInfo.getPlugInType() != ReaderManagerPlugInType::NFC) - { - return; - } - - if (Env::getSingleton()->isScanRunning(ReaderManagerPlugInType::NFC)) - { - return; - } - - const auto& context = getContext(); - if (context->getIfdServer()->isConnected()) - { - qCDebug(statemachine) << "Stopping IfdService because NFC was disabled."; - Q_EMIT fireContinue(); - } + mResetContextOnDisconnect = false; } -void StateProcessIfdMessages::onReaderPropertiesUpdated(const ReaderInfo& pInfo) +void StateProcessIfdMessages::onDisplayTextChanged(const QString& pDisplayText) const { - if (Env::getSingleton()->isUsedAsSDK()) - { - if (pInfo.isInsertable() && pInfo.getCardInfo().getCardType() == CardType::NONE) - { - Env::getSingleton()->insert(pInfo); - } - } -} - - -void StateProcessIfdMessages::onCardConnected() -{ - mResetContextOnDisconnect = false; + getContext()->setDisplayText(pDisplayText); } @@ -158,18 +114,11 @@ void StateProcessIfdMessages::onCardDisconnected() { + getContext()->setDisplayText(QString()); if (mResetContextOnDisconnect) { getContext()->reset(); } -} - - -void StateProcessIfdMessages::onEntry(QEvent* pEvent) -{ - onConnectedChanged(getContext()->getIfdServer()->isConnected()); - - AbstractState::onEntry(pEvent); } diff --git a/src/workflows/ifd/states/StateProcessIfdMessages.h b/src/workflows/ifd/states/StateProcessIfdMessages.h index cbf8991..8bd63b7 100644 --- a/src/workflows/ifd/states/StateProcessIfdMessages.h +++ b/src/workflows/ifd/states/StateProcessIfdMessages.h @@ -10,7 +10,6 @@ #pragma once -#include "ReaderManager.h" #include "context/IfdServiceContext.h" #include "states/AbstractState.h" #include "states/GenericContextContainer.h" @@ -38,16 +37,13 @@ private Q_SLOTS: void onMessageHandlerAdded(const QSharedPointer& pHandler); void onClosed(); - void onConnectedChanged(bool pConnected); - void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo); - void onReaderPropertiesUpdated(const ReaderInfo& pInfo); void onCardConnected(); + void onDisplayTextChanged(const QString& pDisplayText) const; void onModifyPin(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void onEstablishPaceChannel(const QSharedPointer& pMessage, const QSharedPointer& pConnection); void onCardDisconnected(); protected: - void onEntry(QEvent* pEvent) override; void onExit(QEvent* pEvent) override; public: diff --git a/src/workflows/selfauth/SelfAuthenticationData.cpp b/src/workflows/selfauth/SelfAuthenticationData.cpp index 0d2b80a..9d6b930 100644 --- a/src/workflows/selfauth/SelfAuthenticationData.cpp +++ b/src/workflows/selfauth/SelfAuthenticationData.cpp @@ -248,8 +248,11 @@ QString SelfAuthenticationData::SelfData::formatDate(const QString& pDate) { static const QVector> formattingPattern({ + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString qMakePair(QStringLiteral("yyyy-MM-dd+hh:mm"), QLatin1String(QT_TR_NOOP("dd.MM.yyyy"))), + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day qMakePair(QStringLiteral("yyyy-MM"), QLatin1String(QT_TR_NOOP("xx.MM.yyyy"))), + //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month qMakePair(QStringLiteral("yyyy"), QLatin1String(QT_TR_NOOP("xx.xx.yyyy"))), }); diff --git a/test/helper/ifd/MockDataChannel.cpp b/test/helper/ifd/MockDataChannel.cpp index 1668e88..22fc300 100644 --- a/test/helper/ifd/MockDataChannel.cpp +++ b/test/helper/ifd/MockDataChannel.cpp @@ -10,8 +10,9 @@ using namespace governikus; -MockDataChannel::MockDataChannel() - : mId(QUuid::createUuid().toString()) +MockDataChannel::MockDataChannel(bool pPairing) + : mPairing(pPairing) + , mId(QUuid::createUuid().toString()) , mReceivedDataBlocks() { } @@ -25,6 +26,12 @@ void MockDataChannel::close() { Q_EMIT fireClosed(GlobalStatus::Code::No_Error); +} + + +bool MockDataChannel::isPairingConnection() const +{ + return mPairing; } diff --git a/test/helper/ifd/MockDataChannel.h b/test/helper/ifd/MockDataChannel.h index 24e4e4b..ecb615e 100644 --- a/test/helper/ifd/MockDataChannel.h +++ b/test/helper/ifd/MockDataChannel.h @@ -22,15 +22,17 @@ Q_OBJECT private: + bool mPairing; QString mId; QVector mReceivedDataBlocks; public: - MockDataChannel(); + explicit MockDataChannel(bool pPairing = false); ~MockDataChannel() override; void send(const QByteArray& pDataBlock) override; void close() override; + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] const QString& getId() const override; void closeAbnormal(); diff --git a/test/helper/ifd/MockIfdDispatcher.cpp b/test/helper/ifd/MockIfdDispatcher.cpp index 480fa1f..065286c 100644 --- a/test/helper/ifd/MockIfdDispatcher.cpp +++ b/test/helper/ifd/MockIfdDispatcher.cpp @@ -24,9 +24,22 @@ MockIfdDispatcher::MockIfdDispatcher(DispatcherState pState) : IfdDispatcherClient(IfdVersion::Version::v2, QSharedPointer::create()) , mState(pState) + , mPairing(false) , mId(QUuid::createUuid().toString()) , mContextHandle(QStringLiteral("#TestContext")) { +} + + +void MockIfdDispatcher::setPairingConnection(bool pPairing) +{ + mPairing = pPairing; +} + + +bool MockIfdDispatcher::isPairingConnection() const +{ + return mPairing; } diff --git a/test/helper/ifd/MockIfdDispatcher.h b/test/helper/ifd/MockIfdDispatcher.h index 47580fe..c4a8961 100644 --- a/test/helper/ifd/MockIfdDispatcher.h +++ b/test/helper/ifd/MockIfdDispatcher.h @@ -30,12 +30,15 @@ private: DispatcherState mState; + bool mPairing; QString mId; QString mContextHandle; public: MockIfdDispatcher(DispatcherState pState = DispatcherState::WithoutReader); + void setPairingConnection(bool pPairing); + [[nodiscard]] bool isPairingConnection() const override; [[nodiscard]] QString getId() const override; [[nodiscard]] const QString& getContextHandle() const override; Q_INVOKABLE void send(const QSharedPointer& pMessage) override; diff --git a/test/qml/Global/test_GButton.qml b/test/qml/Global/test_GButton.qml index a66b7ad..48538e0 100644 --- a/test/qml/Global/test_GButton.qml +++ b/test/qml/Global/test_GButton.qml @@ -32,17 +32,13 @@ } function test_size(data) { let button = createTemporaryQmlObject("import Governikus.Global 1.0; GButton {icon.source: \"" + data.icon + "\"; text: \"" + data.text + "\"}", testCase); - waitForRendering(button); - compare(button.height, data.height); - compare(button.width, data.width); + tryCompare(button, "height", data.height); + tryCompare(button, "width", data.width); } function test_size_data() { - if (Qt.platform.os !== "osx") { - skip(); - } let text = createTemporaryQmlObject("import Governikus.Global 1.0; import Governikus.Style 1.0; GText {textStyle: Style.text.button; text: \"test test test test test test\"}", testCase); - waitForRendering(text); - let longTextWidth = Math.round(text.width + 0.1); + verify(waitForRendering(text)); + let longTextWidth = Math.ceil(text.width); return [{ "tag": "noIconNoText", "icon": "", @@ -72,7 +68,7 @@ "icon": "qrc:///images/identify.svg", "text": "t", "height": Constants.is_desktop ? 39 : 40, - "width": Constants.is_desktop ? 59 : 112 + "width": Constants.is_desktop ? (Qt.platform.os === "linux" ? 64 : 59) : 112 }, { "tag": "withIconLongText", "icon": "qrc:///images/identify.svg", diff --git a/test/qt/configuration/test_ProviderConfiguration.cpp b/test/qt/configuration/test_ProviderConfiguration.cpp index 9bc73f3..45a15dd 100644 --- a/test/qt/configuration/test_ProviderConfiguration.cpp +++ b/test/qt/configuration/test_ProviderConfiguration.cpp @@ -302,7 +302,7 @@ } } - QCOMPARE(attachedEidCounter, 20); + QCOMPARE(attachedEidCounter, 21); } diff --git a/test/qt/configuration/test_ProviderConfigurationParser.cpp b/test/qt/configuration/test_ProviderConfigurationParser.cpp index 447c0c4..ea39abd 100644 --- a/test/qt/configuration/test_ProviderConfigurationParser.cpp +++ b/test/qt/configuration/test_ProviderConfigurationParser.cpp @@ -224,8 +224,8 @@ QTest::addColumn("majorVersion"); QTest::addColumn("count"); - const int all = 113; - const int withEidSupport = 91; + const int all = 120; + const int withEidSupport = 98; QTest::newRow("win") << QOperatingSystemVersion::Windows << -1 << all; QTest::newRow("mac") << QOperatingSystemVersion::MacOS << -1 << all; QTest::newRow("linux") << QOperatingSystemVersion::Unknown << -1 << all; diff --git a/test/qt/global/test_LogHandler.cpp b/test/qt/global/test_LogHandler.cpp index cb6dfe0..a003cfe 100644 --- a/test/qt/global/test_LogHandler.cpp +++ b/test/qt/global/test_LogHandler.cpp @@ -447,6 +447,12 @@ QTest::newRow("createSingleton") << QByteArray("T* governikus::Env::createSingleton() [with T = governikus::AppUpdater]") << QByteArray("Env::createSingleton"); + QTest::newRow("createSingletonPtr") << QByteArray("T *governikus::Env::createSingleton() [T = governikus::NetworkManager]") + << QByteArray("Env::createSingleton"); + + QTest::newRow("processUpdaterRequest") << QByteArray("auto governikus::NetworkManager::processUpdaterRequest(QNetworkRequest &, const std::function (QNetworkRequest &)> &)::(anonymous class)::operator()() const") + << QByteArray("NetworkManager::processUpdaterRequest"); + QTest::newRow("printInfo") << QByteArray("void printInfo()") << QByteArray("printInfo"); @@ -466,6 +472,8 @@ QTest::newRow("UILoader::load") << QByteArray("std::enable_if_t::value, bool> governikus::UILoader::load() const [with T = governikus::UIPlugInJson; std::enable_if_t::value, bool> = bool]") << QByteArray("UILoader::load"); + QTest::newRow("anonymous") << QByteArray("virtual QList (anonymous namespace)::SystemProxyFactory::queryProxy(const QNetworkProxyQuery &)") + << QByteArray("SystemProxyFactory::queryProxy"); } @@ -481,6 +489,15 @@ } + void formatFunctionNullptr() + { + const auto* handler = Env::getSingleton(); + const auto& formattedFunction = handler->formatFunction(nullptr, QByteArray(), 1811); + + QCOMPARE(formattedFunction, QByteArray()); + } + + }; QTEST_GUILESS_MAIN(test_LogHandler) diff --git a/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp b/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp index 4b2e81f..ac743d1 100644 --- a/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp +++ b/test/qt/ifd/remote/test_RemoteIfdReaderManagerPlugin.cpp @@ -111,9 +111,11 @@ Env::set(RemoteIfdClient::staticMetaObject, mIfdClient.data()); mDispatcher1.reset(new MockIfdDispatcher()); + mDispatcher1->setPairingConnection(false); mDispatcher1->moveToThread(&mNetworkThread); mDispatcher2.reset(new MockIfdDispatcher()); + mDispatcher2->setPairingConnection(true); mDispatcher2->moveToThread(&mNetworkThread); mPlugin.reset(new RemoteIfdReaderManagerPlugIn()); @@ -525,6 +527,34 @@ } + void testKeepNormalConnection() + { + QSignalSpy spySend(mDispatcher1.data(), &MockIfdDispatcher::fireSend); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher1); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + spySend.clear(); + + mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher1->getId()); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + QSharedPointer result = qvariant_cast>(spySend.takeFirst().at(0)); + QCOMPARE(result->getType(), IfdMessageType::IFDGetStatus); + } + + + void testClosePairingConnection() + { + QSignalSpy spySend(mDispatcher2.data(), &MockIfdDispatcher::fireSend); + QSignalSpy spyClosed(mDispatcher2.data(), &MockIfdDispatcher::fireClosed); + + Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher2); + QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations + + mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher2->getId()); + QTRY_COMPARE(spyClosed.count(), 1); // clazy:exclude=qstring-allocations + } + + }; QTEST_GUILESS_MAIN(test_RemoteIfdReaderManagerPlugIn) diff --git a/test/qt/ifd/remote/test_RemoteIfdServer.cpp b/test/qt/ifd/remote/test_RemoteIfdServer.cpp index 9ae1000..ea6488b 100644 --- a/test/qt/ifd/remote/test_RemoteIfdServer.cpp +++ b/test/qt/ifd/remote/test_RemoteIfdServer.cpp @@ -98,6 +98,12 @@ } + [[nodiscard]] bool isPairingAnnounced() const override + { + return mPairing; + } + + void setPairing(bool pEnabled = true) override { mPairing = pEnabled; @@ -159,11 +165,11 @@ private Q_SLOTS: void init() { - std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort){ + std::function creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool&){ mAdvertiserMock = new RemoteReaderAdvertiserMock(pIfdName, pIfdId, pPort); return mAdvertiserMock; }; - Env::setCreator(creator); + Env::setCreator(creator); std::function creator2 = [this](){ mWebSocketMock = new RemoteWebSocketServerMock(); return mWebSocketMock; diff --git a/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp b/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp index e1cd782..09ad044 100644 --- a/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp +++ b/test/qt/ifd/remote/test_RemoteReaderAdvertiser.cpp @@ -19,9 +19,9 @@ { -template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pTimerInterval, bool& pPairing) +template<> RemoteReaderAdvertiser* createNewObject(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pInterval, bool& pPairing) { - return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pTimerInterval, pPairing); + return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pPairing, pInterval); } diff --git a/test/qt/ifd/remote/test_RemoteTlsServer.cpp b/test/qt/ifd/remote/test_RemoteTlsServer.cpp index 6e43125..d8ad1eb 100644 --- a/test/qt/ifd/remote/test_RemoteTlsServer.cpp +++ b/test/qt/ifd/remote/test_RemoteTlsServer.cpp @@ -57,6 +57,7 @@ RemoteTlsServer server; server.setPairing(serverPairing); server.startListening(0); + QCOMPARE(server.hasPsk(), serverPairing); auto config = Env::getSingleton()->getTlsConfigRemoteIfd(clientConfig).getConfiguration(); config.setPrivateKey(pair.getKey()); @@ -91,6 +92,7 @@ }); server.setPairing(); server.startListening(0); + QVERIFY(server.hasPsk()); auto config = Env::getSingleton()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getConfiguration(); config.setPrivateKey(pair.getKey()); diff --git a/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp b/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp index 7cd8b28..0b9f3fc 100644 --- a/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp +++ b/test/qt/ifd/remote/test_RemoteWebSocketServer.cpp @@ -176,6 +176,7 @@ PskHandler pskHandler(&client, mServer.data()); mServer->setPairing(); QVERIFY(mServer->listen(QStringLiteral("TestServer"))); + QVERIFY(mServer->isPairingAnnounced()); client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); @@ -279,6 +280,7 @@ PskHandler pskHandler(&client, mServer.data()); mServer->setPairing(); client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort()))); + QVERIFY(mServer->isPairingAnnounced()); QTRY_COMPARE(newConnectionSpy.count(), 1); // clazy:exclude=qstring-allocations QTRY_COMPARE(serverConnectedSpy.count(), 1); // clazy:exclude=qstring-allocations diff --git a/test/qt/ifd/test_IfdConnector.cpp b/test/qt/ifd/test_IfdConnector.cpp index a3ce401..dc2b7e7 100644 --- a/test/qt/ifd/test_IfdConnector.cpp +++ b/test/qt/ifd/test_IfdConnector.cpp @@ -427,11 +427,7 @@ QTRY_COMPARE(spyConnectorError.count(), 1); // clazy:exclude=qstring-allocations QCOMPARE(spyConnectorSuccess.count(), 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - verifyErrorSignal(spyConnectorError, {IfdErrorCode::CONNECTION_ERROR}, serverPort, QStringLiteral("Smartphone1")); -#else verifyErrorSignal(spyConnectorError, {IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION}, serverPort, QStringLiteral("Smartphone1")); -#endif QCOMPARE(spySocketError.count(), 0); QCOMPARE(spySocketSuccess.count(), 0); diff --git a/test/qt/ifd/test_IfdDispatcher.cpp b/test/qt/ifd/test_IfdDispatcher.cpp index 412ed37..1cb2bd0 100644 --- a/test/qt/ifd/test_IfdDispatcher.cpp +++ b/test/qt/ifd/test_IfdDispatcher.cpp @@ -338,6 +338,22 @@ } + void isNormalConnection() + { + const QSharedPointer clientChannel(new MockDataChannel(false)); + const QSharedPointer clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel)); + QVERIFY(!clientDispatcher->isPairingConnection()); + } + + + void isPairingConnection() + { + const QSharedPointer clientChannel(new MockDataChannel(true)); + const QSharedPointer clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel)); + QVERIFY(clientDispatcher->isPairingConnection()); + } + + }; QTEST_GUILESS_MAIN(test_IfdDispatcher) diff --git a/test/qt/ifd/test_ServerMessageHandler.cpp b/test/qt/ifd/test_ServerMessageHandler.cpp index 0bae944..cb9f07d 100644 --- a/test/qt/ifd/test_ServerMessageHandler.cpp +++ b/test/qt/ifd/test_ServerMessageHandler.cpp @@ -603,6 +603,82 @@ } + void ifdTransmit_data() + { + QTest::addColumn("sendProgressMessage"); + + QTest::newRow("Send message") << true; + QTest::newRow("Don't send message") << false; + } + + + void ifdTransmit() + { + QFETCH(bool, sendProgressMessage); + + QSignalSpy logSpy(Env::getSingleton()->getEventHandler(), &LogEventHandler::fireLog); + ServerMessageHandlerImpl serverMessageHandler(mDataChannel); + QString contextHandle; + ensureContext(contextHandle); + + QSignalSpy sendSpy(mDataChannel.data(), &MockDataChannel::fireSend); + + MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("test-reader"); + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + reader->setCard(MockCardConfig({ + {CardReturnCode::OK, QByteArray("9000")} + })); + QTRY_COMPARE(sendSpy.count(), 2); // clazy:exclude=qstring-allocations + const CardInfo cardInfo(CardType::EID_CARD, QSharedPointer(), 3, true); + ReaderInfo info = reader->getReaderInfo(); + info.setCardInfo(cardInfo); + reader->setReaderInfo(info); + QTRY_COMPARE(sendSpy.count(), 3); // clazy:exclude=qstring-allocations + sendSpy.clear(); + + const QByteArray ifdConnectMsg = IfdConnect(QStringLiteral("test-reader"), true).toByteArray(IfdVersion::Version::latest, contextHandle); + mDataChannel->onReceived(ifdConnectMsg); + + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + + const QList& connectResponseArguments = sendSpy.last(); + const QVariant connectResponseVariant = connectResponseArguments.at(0); + QVERIFY(connectResponseVariant.canConvert()); + + const IfdConnectResponse connectResponse(IfdMessage::parseByteArray(connectResponseVariant.toByteArray())); + QVERIFY(!connectResponse.isIncomplete()); + QCOMPARE(connectResponse.getType(), IfdMessageType::IFDConnectResponse); + QCOMPARE(connectResponse.getContextHandle(), contextHandle); + QVERIFY(!connectResponse.getSlotHandle().isEmpty()); + + QVERIFY(!connectResponse.resultHasError()); + QCOMPARE(connectResponse.getResultMinor(), ECardApiResult::Minor::null); + + sendSpy.clear(); + + QSignalSpy displayTextSpy(&serverMessageHandler, &ServerMessageHandler::fireDisplayTextChanged); + // Card connected, try to provoke message. + const QByteArray ifdTransmitMsg = IfdTransmit(connectResponse.getSlotHandle(), QByteArray("ABCDEF"), sendProgressMessage ? QStringLiteral("DummyText") : QString()).toByteArray(IfdVersion::Version::latest, contextHandle); + mDataChannel->onReceived(ifdTransmitMsg); + QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations + + const QList& transmitResponseArguments = sendSpy.last(); + const QVariant transmitResponseVariant = transmitResponseArguments.at(0); + QVERIFY(transmitResponseVariant.canConvert()); + + const IfdTransmitResponse transmitResponse(IfdMessage::parseByteArray(transmitResponseVariant.toByteArray())); + QVERIFY(!transmitResponse.isIncomplete()); + QCOMPARE(transmitResponse.getType(), IfdMessageType::IFDTransmitResponse); + QCOMPARE(transmitResponse.getContextHandle(), contextHandle); + QCOMPARE(transmitResponse.getSlotHandle(), connectResponse.getSlotHandle()); + QVERIFY(!transmitResponse.resultHasError()); + QCOMPARE(transmitResponse.getResultMinor(), ECardApiResult::Minor::null); + QCOMPARE(displayTextSpy.count(), sendProgressMessage ? 1 : 0); + + removeReaderAndConsumeMessages(QStringLiteral("test-reader")); + } + + void ifdEstablishPACEChannelWithBasicReaderNameSendsAL_Unknown_Error() { const bool pinpadModeToSave = Env::getSingleton()->getRemoteServiceSettings().getPinPadMode(); diff --git a/test/qt/settings/test_RemoteServiceSettings.cpp b/test/qt/settings/test_RemoteServiceSettings.cpp index 8dbe07f..168c809 100644 --- a/test/qt/settings/test_RemoteServiceSettings.cpp +++ b/test/qt/settings/test_RemoteServiceSettings.cpp @@ -71,8 +71,16 @@ void testPinPadMode() { RemoteServiceSettings settings; + QCOMPARE(settings.getPinPadMode(), true); + settings.setPinPadMode(false); QCOMPARE(settings.getPinPadMode(), false); - QCOMPARE(settings.getPinPadMode(), false); + } + + + void testShowAccessRights() + { + RemoteServiceSettings settings; + QCOMPARE(settings.getShowAccessRights(), false); settings.setPinPadMode(true); QCOMPARE(settings.getPinPadMode(), true); } diff --git a/test/qt/ui/qml/test_ApplicationModel.cpp b/test/qt/ui/qml/test_ApplicationModel.cpp index 339ba86..5308222 100644 --- a/test/qt/ui/qml/test_ApplicationModel.cpp +++ b/test/qt/ui/qml/test_ApplicationModel.cpp @@ -9,8 +9,10 @@ #include "ApplicationModel.h" #include "MockActivationContext.h" +#include "MockIfdServer.h" #include "context/AuthContext.h" #include "context/ChangePinContext.h" +#include "context/IfdServiceContext.h" #include "context/SelfAuthContext.h" #if __has_include("context/PersonalizationContext.h") #include "context/PersonalizationContext.h" @@ -58,6 +60,7 @@ QTest::addRow("No Context") << QSharedPointer() << ApplicationModel::Workflow::WORKFLOW_NONE; QTest::addRow("AuthContext") << QSharedPointer(new AuthContext(QSharedPointer::create())) << ApplicationModel::Workflow::WORKFLOW_AUTHENTICATION; QTest::addRow("ChangePinContext") << QSharedPointer(new ChangePinContext()) << ApplicationModel::Workflow::WORKFLOW_CHANGE_PIN; + QTest::addRow("IfdServiceContext") << QSharedPointer(new IfdServiceContext(QSharedPointer::create())) << ApplicationModel::Workflow::WORKFLOW_REMOTE_SERVICE; QTest::addRow("SelfAuthContext") << QSharedPointer(new SelfAuthContext()) << ApplicationModel::Workflow::WORKFLOW_SELF_AUTHENTICATION; #if __has_include("context/PersonalizationContext.h") QTest::addRow("PersonalizationContext") << QSharedPointer(new PersonalizationContext(QString())) << ApplicationModel::Workflow::WORKFLOW_SMART; diff --git a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp index 8c52fd1..44281f7 100644 --- a/test/qt/ui/qml/test_CertificateDescriptionModel.cpp +++ b/test/qt/ui/qml/test_CertificateDescriptionModel.cpp @@ -8,8 +8,10 @@ #include "CertificateDescriptionModel.h" +#include "MockIfdServer.h" #include "TestAuthContext.h" #include "TestFileHelper.h" +#include "context/IfdServiceContext.h" #include #include @@ -26,6 +28,19 @@ private: CertificateDescriptionModel* mModel = nullptr; QSharedPointer mContext; + + static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId) + { + const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F"); + const QByteArray certDescription = QByteArray::fromHex("30 8202A4" + " 06 0A 04007F00070301030103" + " A1 0E 0C0C442D547275737420476D6248" + " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E" + " A5 820248" + " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978"); + + return EstablishPaceChannel(pinId, chat, certDescription); + } private Q_SLOTS: void init() @@ -98,6 +113,21 @@ } + void test_IfdContext() + { + auto ifdContext = QSharedPointer::create(QSharedPointer::create()); + mModel->resetContext(ifdContext); + const auto& establishPaceChannel = createDataToParse(PacePasswordId::PACE_PIN); + ifdContext->setEstablishPaceChannel(QSharedPointer::create(QString(), establishPaceChannel, 6)); + + QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider")); + QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::TEXT), QString("Gesamtverband der deutschen Versicherungswirtschaft e.V.\n")); + QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::LABEL), QString("Certificate issuer")); + QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::TEXT), QString("D-Trust GmbH\n")); + QCOMPARE(mModel->data(mModel->index(2), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider information")); + } + + }; QTEST_GUILESS_MAIN(test_CertificateDescriptionModel) diff --git a/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp b/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp new file mode 100644 index 0000000..4d505f3 --- /dev/null +++ b/test/qt/ui/qml/test_RemoteDeviceFilterModel.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany + */ + +/*! + * \brief Unit tests for \ref RemoteDeviceModel + */ + +#include "RemoteDeviceFilterModel.h" + +#include "RemoteDeviceModel.h" + +#include + + +using namespace governikus; + + +class test_RemoteDeviceFilterModel + : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void test_FilterAcceptsRow() + { + QSharedPointer sourceModel = QSharedPointer::create(); + QSharedPointer filterModelAvail = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showAvailableAndPaired); + QSharedPointer filterModelUnavail = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showUnavailableAndPaired); + QSharedPointer filterModelAvailPair = QSharedPointer::create(sourceModel.data(), RemoteDeviceFilterModel::showActivePairingMode); + + const RemoteDeviceModelEntry availableEntry(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + const RemoteDeviceModelEntry unavailableEntry(QString("reader 2"), QString("test id"), false, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + const RemoteDeviceModelEntry availablePairingEntry(QString("reader 2"), QString("test id"), true, false, true, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr); + + sourceModel->mAllRemoteReaders.insert(0, availableEntry); + sourceModel->mAllRemoteReaders.insert(1, unavailableEntry); + sourceModel->mAllRemoteReaders.insert(2, availablePairingEntry); + + QCOMPARE(filterModelAvail->filterAcceptsRow(0, QModelIndex()), true); + QCOMPARE(filterModelAvail->filterAcceptsRow(1, QModelIndex()), false); + + QCOMPARE(filterModelUnavail->filterAcceptsRow(0, QModelIndex()), false); + QCOMPARE(filterModelUnavail->filterAcceptsRow(1, QModelIndex()), true); + + QCOMPARE(filterModelAvailPair->filterAcceptsRow(0, QModelIndex()), false); + QCOMPARE(filterModelAvailPair->filterAcceptsRow(1, QModelIndex()), false); + QCOMPARE(filterModelAvailPair->filterAcceptsRow(2, QModelIndex()), true); + } + + +}; + +QTEST_MAIN(test_RemoteDeviceFilterModel) +#include "test_RemoteDeviceFilterModel.moc" diff --git a/test/qt/ui/qml/test_RemoteDeviceModel.cpp b/test/qt/ui/qml/test_RemoteDeviceModel.cpp index 73fe799..0c80636 100644 --- a/test/qt/ui/qml/test_RemoteDeviceModel.cpp +++ b/test/qt/ui/qml/test_RemoteDeviceModel.cpp @@ -2,6 +2,8 @@ * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany */ +#include "AppSettings.h" +#include "IfdDescriptor.h" #include "RemoteDeviceModel.h" #include @@ -42,6 +44,14 @@ } + void test_IsPairing() + { + QVERIFY(!mEntry->isPairing()); + mEntry->setIsPairing(true); + QVERIFY(mEntry->isPairing()); + } + + void test_DeviceNameEscaped() { QCOMPARE(mEntry->getDeviceNameEscaped(), mName); @@ -76,7 +86,7 @@ RemoteDeviceModelEntry entry1(name); const IfdDescriptor descriptor = IfdDescriptor(); QSharedPointer pointer(new IfdListEntry(descriptor)); - RemoteDeviceModelEntry entry2(name, id, true, true, true, time, pointer); + RemoteDeviceModelEntry entry2(name, id, true, true, true, true, time, pointer); QVERIFY(!entry1.isSupported()); QVERIFY(entry2.isSupported()); @@ -86,15 +96,23 @@ void test_RemoteDeviceListEntry() { const QString name = QStringLiteral("name"); - + const QString id = QStringLiteral("id"); RemoteDeviceModelEntry entry1(name); QCOMPARE(entry1.getRemoteDeviceListEntry(), nullptr); - const IfdDescriptor descriptor = IfdDescriptor(); - QSharedPointer pointer(new IfdListEntry(descriptor)); - const QString id = QStringLiteral("id"); - RemoteDeviceModelEntry entry2(name, id, pointer); - QCOMPARE(entry2.getRemoteDeviceListEntry(), pointer); + const IfdDescriptor defaultDescriptor = IfdDescriptor(); + QSharedPointer listEntry1(new IfdListEntry(defaultDescriptor)); + RemoteDeviceModelEntry entry2(listEntry1); + QCOMPARE(entry2.getRemoteDeviceListEntry(), listEntry1); + + const Discovery discovery = Discovery(name, id, 11111, {IfdVersion::supported()}, true); + const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true); + QSharedPointer listEntry2(new IfdListEntry(descriptor)); + RemoteDeviceModelEntry entry3(listEntry2); + QCOMPARE(entry3.getRemoteDeviceListEntry(), listEntry2); + QCOMPARE(entry3.getId(), id); + QCOMPARE(entry3.getDeviceNameEscaped(), name); + QVERIFY(entry3.isSupported()); } @@ -111,17 +129,27 @@ void test_RoleNames() { + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED)); + QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_STATUS)); QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_NAME)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE)); - QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED)); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceName"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceStatus"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("lastConnected"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("deviceId"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isNetworkVisible"))); QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isSupported"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPaired"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPairing"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("linkQualityInPercent"))); + QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isLastAddedDevice"))); } @@ -139,13 +167,18 @@ QCOMPARE(mModel->getStatus(entry), QString("Not paired")); entry.setPaired(true); - QCOMPARE(mModel->getStatus(entry), QString("Paired, but unavailable")); + QCOMPARE(mModel->getStatus(entry), QString("Unavailable")); entry.setNetworkVisible(true); QCOMPARE(mModel->getStatus(entry), QString("Available")); entry.mSupported = false; QCOMPARE(mModel->getStatus(entry), QString("Paired, but unsupported")); + + entry.setNetworkVisible(true); + entry.mSupported = true; + entry.mIsPairing = true; + QCOMPARE(mModel->getStatus(entry), QString("Click to pair")); } @@ -166,8 +199,11 @@ void test_GetRemoteDeviceListEntryModelIndex() { - QSharedPointer listEntry(new IfdListEntry(IfdDescriptor())); - RemoteDeviceModelEntry entry1(QString("entry 1"), QStringLiteral("01"), listEntry); + const Discovery discovery = Discovery(QStringLiteral("entry 1"), QStringLiteral("01"), 11111, {IfdVersion::supported()}, true); + const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true); + QSharedPointer listEntry(new IfdListEntry(descriptor)); + RemoteDeviceModelEntry entry1(listEntry); + RemoteDeviceModelEntry entry2(QString("entry 2")); mModel->mAllRemoteReaders << entry1 << entry2; @@ -193,7 +229,9 @@ QTest::newRow("network visible") << RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE << 1 << 0 << QVariant(bool(false)); QTest::newRow("supported") << RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED << 0 << 0 << QVariant(bool(true)); QTest::newRow("paired") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true)); + QTest::newRow("is pairing") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true)); QTest::newRow("link quality") << RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY << 0 << 0 << QVariant(int(0)); + QTest::newRow("is last added device") << RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE << 0 << 0 << QVariant(bool(false)); } @@ -206,7 +244,7 @@ QVector readers; QSharedPointer listEntry(new IfdListEntry(IfdDescriptor())); - const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry); + const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry); const RemoteDeviceModelEntry entry2(QString("reader 2")); readers << entry1 << entry2; mModel->mAllRemoteReaders = readers; @@ -215,6 +253,28 @@ } + void test_SetLastPairedReader() + { + const auto cert = QSslCertificate(); + + RemoteServiceSettings& settings = Env::getSingleton()->getRemoteServiceSettings(); + settings.addTrustedCertificate(cert); + + const auto dName = QStringLiteral("myDeviceName"); + const auto dId = QStringLiteral("myDeviceId"); + const auto disco = Discovery(dName, dId, 12345, {IfdVersion::Version::latest}, false); + const auto ifdDesc = IfdDescriptor(disco, QHostAddress(QStringLiteral("127.0.0.1"))); + const QSharedPointer remoteDeviceListEntry(new IfdListEntry(ifdDesc)); + + mModel->addOrUpdateReader(RemoteDeviceModelEntry(remoteDeviceListEntry)); + + QSignalSpy spy(mModel.get(), &RemoteDeviceModel::dataChanged); + mModel->setLastPairedReader(cert); + QTRY_COMPARE(spy.size(), 1); + QVERIFY(mModel->data(mModel->index(0), RemoteDeviceModel::IS_LAST_ADDED_DEVICE).toBool()); + } + + }; QTEST_MAIN(test_RemoteDeviceModel) diff --git a/test/qt/ui/qml/test_RemoteServiceModel.cpp b/test/qt/ui/qml/test_RemoteServiceModel.cpp index 17bb043..c3673be 100644 --- a/test/qt/ui/qml/test_RemoteServiceModel.cpp +++ b/test/qt/ui/qml/test_RemoteServiceModel.cpp @@ -27,19 +27,6 @@ private: RemoteServiceModel* mModel = nullptr; QSharedPointer mContext; - - static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId) - { - const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F"); - const QByteArray certDescription = QByteArray::fromHex("30 8202A4" - " 06 0A 04007F00070301030103" - " A1 0E 0C0C442D547275737420476D6248" - " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E" - " A5 820248" - " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978"); - - return EstablishPaceChannel(pinId, chat, certDescription); - } private Q_SLOTS: void initTestCase() @@ -153,6 +140,86 @@ } + void test_TransactionInfo() + { + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(mModel->getTransactionInfo(), QString()); + } + + + void test_getSupportedReaderPlugInTypes() + { + QVector supportedPlugIns {ReaderManagerPlugInType::NFC}; +#if __has_include("SmartManager.h") + supportedPlugIns << ReaderManagerPlugInType::SMART; +#endif + QCOMPARE(mModel->getSupportedReaderPlugInTypes(), supportedPlugIns); + } + + + void test_DisplayText_data() + { + QTest::addColumn("inputText"); + QTest::addColumn("outputText"); + QTest::addColumn("expectedPercentage"); + + QTest::newRow("positive two digits") << "Dummy Text\n15%" << "Dummy Text" << 15; + QTest::newRow("positive two digits with space") << "Dummy Text\n15 %" << "Dummy Text" << 15; + QTest::newRow("negative two digits") << "Dummy Text\n-15%" << "Dummy Text\n-15%" << 0; + QTest::newRow("positive two digits with percentage") << "Dummy Text\n15%" << "Dummy Text" << 15; + QTest::newRow("Whitespace input") << " " << " " << 0; + QTest::newRow("Special characters") << "!@#$%^&*()" << "!@#$%^&*()" << 0; + QTest::newRow("Digits only") << "12345" << "12345" << 0; + QTest::newRow("Single Digit") << "Dummy Text\n1%" << "Dummy Text" << 1; + QTest::newRow("Triple Digit") << "Dummy Text\n111%" << "Dummy Text\n111%" << 0; + QTest::newRow("100 Percent") << "Dummy Text\n100%" << "Dummy Text" << 100; + QTest::newRow("Quadruple Digit") << "Dummy Text\n1111%" << "Dummy Text\n1111%" << 0; + QTest::newRow("Real Number") << "Dummy Text\n11.1%" << "Dummy Text\n11.1%" << 0; + QTest::newRow("Zero Digit without Space") << "%" << "%" << 0; + QTest::newRow("Single Digit without Space") << "1%" << "" << 1; + QTest::newRow("Double Digit without Space") << "42%" << "" << 42; + QTest::newRow("Triple Digit without Space") << "100%" << "" << 100; + QTest::newRow("Zero Digit with Space") << " %" << " %" << 0; + QTest::newRow("Single Digit with Space") << "1 %" << "" << 1; + QTest::newRow("Double Digit with Space") << "42 %" << "" << 42; + QTest::newRow("Triple Digit with Space") << "100 %" << "" << 100; + + } + + + void test_DisplayText() + { + QFETCH(QString, inputText); + QFETCH(QString, outputText); + QFETCH(int, expectedPercentage); + + QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged); + + mModel->resetRemoteServiceContext(mContext); + mContext->setDisplayText(inputText); + QCOMPARE(spyDisplayTextChanged.count(), 1); + QCOMPARE(mModel->getDisplayText(), outputText); + QCOMPARE(mModel->getPercentage(), expectedPercentage); + } + + + void test_DisplayTextSignals() + { + QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged); + + QCOMPARE(mModel->getDisplayText(), ""); + QCOMPARE(mModel->getPercentage(), 0); + + mModel->resetRemoteServiceContext(mContext); + QCOMPARE(spyDisplayTextChanged.count(), 0); + mContext->setDisplayText("Dummy"); + QCOMPARE(spyDisplayTextChanged.count(), 1); + mContext->setDisplayText("Dummy"); + QCOMPARE(spyDisplayTextChanged.count(), 1); + + } + + }; QTEST_MAIN(test_RemoteServiceModel) diff --git a/test/qt/ui/qml/test_WorkflowModel.cpp b/test/qt/ui/qml/test_WorkflowModel.cpp index 25e8a3e..dfee357 100644 --- a/test/qt/ui/qml/test_WorkflowModel.cpp +++ b/test/qt/ui/qml/test_WorkflowModel.cpp @@ -8,12 +8,16 @@ #include "WorkflowModel.h" +#include "Env.h" #include "MockCardConnectionWorker.h" +#include "MockReaderManagerPlugIn.h" +#include "ReaderManager.h" #include "TestWorkflowContext.h" #include #include +Q_IMPORT_PLUGIN(MockReaderManagerPlugIn) using namespace governikus; @@ -109,6 +113,46 @@ } + void test_startScanExplicitly() + { + const auto readerManager = Env::getSingleton(); + readerManager->init(); + readerManager->isScanRunning(); // just to wait until initialization finished + + QSharedPointer context(new TestWorkflowContext()); + QSignalSpy spy(context.data(), &WorkflowContext::fireReaderPlugInTypesChanged); + + WorkflowModel model; + model.resetWorkflowContext(context); + + model.startScanExplicitly(); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(spy.takeFirst().at(0).toBool(), true); + } + + + void test_hasCard() + { + const auto readerManager = Env::getSingleton(); + readerManager->init(); + readerManager->isScanRunning(); // just to wait until initialization finished + + WorkflowModel model; + QCOMPARE(model.hasCard(), false); + + QSharedPointer context(new TestWorkflowContext()); + model.resetWorkflowContext(context); + QCOMPARE(model.hasCard(), false); + + auto mockReader = MockReaderManagerPlugIn::getInstance().addReader("SomeReaderWithCard"); + auto info = mockReader->getReaderInfo(); + info.setCardInfo(CardInfo(CardType::EID_CARD, QSharedPointer(), 3, false, false, false)); + mockReader->setReaderInfo(info); + model.setReaderPlugInType(ReaderManagerPlugInType::MOCK); + QCOMPARE(model.hasCard(), true); + } + + }; QTEST_MAIN(test_WorkflowModel) diff --git a/test/qt/workflows/context/test_WorkflowContext.cpp b/test/qt/workflows/context/test_WorkflowContext.cpp index f5bee5a..7d9344a 100644 --- a/test/qt/workflows/context/test_WorkflowContext.cpp +++ b/test/qt/workflows/context/test_WorkflowContext.cpp @@ -273,6 +273,18 @@ } + void test_setInterruptRequested() + { + QVERIFY(!mContext->interruptRequested()); + + mContext->setInterruptRequested(true); + QVERIFY(mContext->interruptRequested()); + + mContext->setInterruptRequested(false); + QVERIFY(!mContext->interruptRequested()); + } + + }; QTEST_GUILESS_MAIN(test_WorkflowContext) diff --git a/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp b/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp index f6467ef..7c4d945 100644 --- a/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp +++ b/test/qt/workflows/ifd/test_StateEstablishPaceChannelResponse.cpp @@ -38,6 +38,12 @@ { Q_UNUSED(pSlotHandle) Q_UNUSED(pResponseApdu) + } + + + void setAllowedCardTypes(const QVector& pAllowedCardTypes) override + { + Q_UNUSED(pAllowedCardTypes) } diff --git a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp index 5d53391..dba2e1c 100644 --- a/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp +++ b/test/qt/workflows/ifd/test_StateProcessIfdMessages.cpp @@ -35,8 +35,8 @@ const QSharedPointer context(new IfdServiceContext(mIfdServer)); StateProcessIfdMessages state(context); state.run(); - QCOMPARE(state.mConnections.size(), 4); - QCOMPARE(state.mMessageConnections.size(), 6); + QCOMPARE(state.mConnections.size(), 1); + QCOMPARE(state.mMessageConnections.size(), 7); } @@ -50,7 +50,7 @@ QCOMPARE(state.mMessageConnections.size(), 0); state.onMessageHandlerAdded(messageHandler); - QCOMPARE(state.mMessageConnections.size(), 6); + QCOMPARE(state.mMessageConnections.size(), 7); } @@ -115,6 +115,21 @@ } + void test_OnDisplayTextChanged() + { + const QSharedPointer context(new IfdServiceContext(mIfdServer)); + StateProcessIfdMessages state(context); + QSignalSpy spy(context.data(), &IfdServiceContext::fireDisplayTextChanged); + + state.onDisplayTextChanged(QStringLiteral("dummy text")); + QCOMPARE(spy.count(), 1); + QCOMPARE(context->getDisplayText(), QStringLiteral("dummy text")); + state.onCardDisconnected(); + QCOMPARE(spy.count(), 2); + QCOMPARE(context->getDisplayText(), QStringLiteral("")); + } + + }; QTEST_GUILESS_MAIN(test_StateProcessIfdMessages) diff --git a/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp b/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp index a9dc2ee..270835d 100644 --- a/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp +++ b/test/qt/workflows/states/test_StateEstablishPaceChannel.cpp @@ -97,10 +97,14 @@ mAuthContext->setCardConnection(connection); mAuthContext->setEstablishPaceChannelType(PacePasswordId::PACE_PIN); + QCOMPARE(mAuthContext->getProgressValue(), 0); + QCOMPARE(mAuthContext->getProgressMessage(), QString()); QTest::ignoreMessage(QtDebugMsg, "Establish connection using PACE_PIN"); mState->run(); QCOMPARE(mAuthContext->getEstablishPaceChannelType(), PacePasswordId::PACE_PIN); QCOMPARE(mState->mPasswordId, PacePasswordId::PACE_PIN); + QCOMPARE(mAuthContext->getProgressValue(), 0); + QCOMPARE(mAuthContext->getProgressMessage(), tr("The secure channel is opened")); } diff --git a/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp b/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp index 32d3121..dfed18a 100644 --- a/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp +++ b/test/qt/workflows/states/test_StateGenericProviderCommunication.cpp @@ -131,7 +131,7 @@ QCOMPARE(spy.count(), 1); const auto& failureCode = mState->getContext()->getFailureCode(); - QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Ssl_Error); + QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Tls_Error); QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Network_Error], mState->mReply->errorString()); QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Ssl_Errors], TlsChecker::sslErrorsToString(errorList)); } diff --git a/test/qt/workflows/states/test_StatePreVerification.cpp b/test/qt/workflows/states/test_StatePreVerification.cpp index 4ba2633..9e4da35 100644 --- a/test/qt/workflows/states/test_StatePreVerification.cpp +++ b/test/qt/workflows/states/test_StatePreVerification.cpp @@ -91,7 +91,7 @@ QTRY_COMPARE(spyAbort.count(), isValid ? 0 : 1); // clazy:exclude=qstring-allocations if (!isValid) { - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } } @@ -104,7 +104,7 @@ mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); } @@ -116,7 +116,7 @@ mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain); } @@ -136,7 +136,7 @@ mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature); } @@ -148,7 +148,7 @@ mAuthContext->setStateApproved(); QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations - QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired); + QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired); }