Codebase list ausweisapp2 / b569268
New upstream version 1.26.5 John Paul Adrian Glaubitz 9 months ago
353 changed file(s) with 10641 addition(s) and 6427 deletion(s). Raw diff Collapse all Expand all
5959 set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "Required macOS version")
6060 endif()
6161
62 project(AusweisApp2 VERSION 1.26.4 LANGUAGES ${LANGUAGES})
62 project(AusweisApp2 VERSION 1.26.5 LANGUAGES ${LANGUAGES})
6363
6464 # Set TWEAK if not defined in PROJECT_VERSION above to
6565 # have a valid tweak version without propagating it
0 ARG ALPINE_VERSION=3.17
0 ARG ALPINE_VERSION=3.18
11
22 FROM alpine:$ALPINE_VERSION as builder
33 # Install development stuff
8383 endif()
8484
8585 if (QT6)
86 # Workaround for QTBUG-94066
87 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake")
88 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake")
89 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake")
90 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake")
91 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake")
92 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake")
86 if(QT_VERSION VERSION_LESS "6.4")
87 # Workaround for QTBUG-94066
88 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QSvgPluginTargets.cmake")
89 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QGifPluginTargets.cmake")
90 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QJpegPluginTargets.cmake")
91 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Gui/Qt6QWindowsIntegrationPluginTargets.cmake")
92 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Widgets/Qt6QWindowsVistaStylePluginTargets.cmake")
93 include("${QT_INSTALL_ARCHDATA}/lib/cmake/Qt6Network/Qt6QTlsBackendOpenSSLPluginTargets.cmake")
94 endif()
95
9396 FETCH_TARGET_LOCATION(openSslBackend "${Qt}::QTlsBackendOpenSSLPlugin")
9497 install(FILES ${openSslBackend} DESTINATION tls COMPONENT Runtime)
9598 list(APPEND LIBS ${openSslBackend})
246249 foreach(entry ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi)
247250 install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/background_npa.png DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa_background.png)
248251 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)
252 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)
249253 install(FILES ${RESOURCES_IMG_ANDROID_DIR}/${entry}/${ANDROID_LAUNCHER_ICON} DESTINATION ${ANDROID_PACKAGE_SRC_DIR}/res/mipmap-${entry} COMPONENT Runtime RENAME npa.png)
250254 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)
251255 endforeach()
268272 set(QML_ROOT_PATH [\"${RESOURCES_DIR}/qml\"])
269273 set(ANDROID_ROOT_LOGGER "")
270274 configure_file(${PACKAGING_DIR}/android/fileprovider.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/fileprovider.xml COPYONLY)
275 configure_file(${PACKAGING_DIR}/android/full_backup_content.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/full_backup_content.xml COPYONLY)
276 configure_file(${PACKAGING_DIR}/android/data_extraction_rules.xml ${ANDROID_PACKAGE_SRC_DIR}/res/xml/data_extraction_rules.xml COPYONLY)
271277 endif()
272278
273279 set(ANDROID_SO_NAME libAusweisApp2_${CMAKE_ANDROID_ARCH_ABI}.so)
4848 endif()
4949
5050 if(NOT INTEGRATED_SDK)
51 list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2)
51 list(APPEND QT_COMPONENTS Svg WebSockets Qml Quick QuickControls2 QuickTemplates2 QmlWorkerScript)
5252
53 if(QT_VERSION VERSION_GREATER_EQUAL "5.14")
54 list(APPEND QT_COMPONENTS QmlWorkerScript)
55 endif()
5653 if(NOT DESKTOP AND NOT QT6)
5754 list(APPEND QT_COMPONENTS QuickShapes)
5855 endif()
2424 message(STATUS "ANDROID_BUILD_TOOLS_REVISION: ${ANDROID_BUILD_TOOLS_REVISION}")
2525
2626 message(STATUS "ANDROID_NDK_REVISION: ${ANDROID_NDK_REVISION}")
27 message(STATUS "ANDROID_SDK_REVISION: ${ANDROID_SDK_REVISION}")
2827 endif()
2928
3029
170170 file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE)
171171 file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}")
172172
173 if(USE_SMARTEID AND NOT INTEGRATED_SDK)
173 if(INTEGRATED_SDK)
174 set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.aar")
175 file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE)
176 file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}")
177 elseif(USE_SMARTEID)
174178 set(BUILD_GRADLE_APPEND "${PACKAGING_DIR}/android/build.gradle.append.smarteid")
175179 file(READ "${BUILD_GRADLE_APPEND}" BUILD_GRADLE)
176180 file(APPEND "${CMAKE_INSTALL_PREFIX}/build.gradle" "${BUILD_GRADLE}")
11 # So this file will be called two times and the check needs to respect that
22 # with a "VALIDATOR function" or "if(NOT VARIABLE)".
33
4 if(NOT QMLFORMAT)
4 if(NOT TARGET format.qml)
55 set(QMLFORMAT_MIN_VERSION 6)
66 function(qmlformat_validator validator_result binary)
77 execute_process(COMMAND ${binary} --version OUTPUT_VARIABLE QMLFORMAT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
225225 COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 320 -y 0 -o xhdpi/foreground_npa_preview.png
226226 COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 480 -y 0 -o xxhdpi/foreground_npa_preview.png
227227 COMMAND ${INKSCAPE} adaptive_foreground_preview.svg -d 640 -y 0 -o xxxhdpi/foreground_npa_preview.png
228 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
229
230 add_custom_target(npaicons.android.adaptive.monochrome
231 COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 120 -y 0 -o ldpi/monochrome_npa.png
232 COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 160 -y 0 -o mdpi/monochrome_npa.png
233 COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 240 -y 0 -o hdpi/monochrome_npa.png
234 COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 320 -y 0 -o xhdpi/monochrome_npa.png
235 COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 480 -y 0 -o xxhdpi/monochrome_npa.png
236 COMMAND ${INKSCAPE} adaptive_monochrome_release.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa.png
237 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
238
239 add_custom_target(npaicons.android.adaptive.monochrome.beta
240 COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 120 -y 0 -o ldpi/monochrome_npa_beta.png
241 COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 160 -y 0 -o mdpi/monochrome_npa_beta.png
242 COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 240 -y 0 -o hdpi/monochrome_npa_beta.png
243 COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 320 -y 0 -o xhdpi/monochrome_npa_beta.png
244 COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_beta.png
245 COMMAND ${INKSCAPE} adaptive_monochrome_beta.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_beta.png
246 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
247
248 add_custom_target(npaicons.android.adaptive.monochrome.preview
249 COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 120 -y 0 -o ldpi/monochrome_npa_preview.png
250 COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 160 -y 0 -o mdpi/monochrome_npa_preview.png
251 COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 240 -y 0 -o hdpi/monochrome_npa_preview.png
252 COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 320 -y 0 -o xhdpi/monochrome_npa_preview.png
253 COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 480 -y 0 -o xxhdpi/monochrome_npa_preview.png
254 COMMAND ${INKSCAPE} adaptive_monochrome_preview.svg -d 640 -y 0 -o xxxhdpi/monochrome_npa_preview.png
228255 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
229256
230257 add_custom_target(npaicons.android.launchimage
312339 npaicons.android.adaptive.foreground
313340 npaicons.android.adaptive.foreground.beta
314341 npaicons.android.adaptive.foreground.preview
342 npaicons.android.adaptive.monochrome
343 npaicons.android.adaptive.monochrome.beta
344 npaicons.android.adaptive.monochrome.preview
315345 npaicons.android.launchimage
316346 npaicons.android.launchimage.beta
317347 npaicons.android.launchimage.preview
404434 COMMAND ${PNGQUANT_CMD} xhdpi/foreground_npa_preview.png -- xhdpi/foreground_npa_preview.png
405435 COMMAND ${PNGQUANT_CMD} xxhdpi/foreground_npa_preview.png -- xxhdpi/foreground_npa_preview.png
406436 COMMAND ${PNGQUANT_CMD} xxxhdpi/foreground_npa_preview.png -- xxxhdpi/foreground_npa_preview.png
437 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
438
439 add_custom_target(pngquant.android.adaptive.monochrome
440 COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa.png -- ldpi/monochrome_npa.png
441 COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa.png -- mdpi/monochrome_npa.png
442 COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa.png -- hdpi/monochrome_npa.png
443 COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa.png -- xhdpi/monochrome_npa.png
444 COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa.png -- xxhdpi/monochrome_npa.png
445 COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa.png -- xxxhdpi/monochrome_npa.png
446 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
447
448 add_custom_target(pngquant.android.adaptive.monochrome.beta
449 COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_beta.png -- ldpi/monochrome_npa_beta.png
450 COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_beta.png -- mdpi/monochrome_npa_beta.png
451 COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_beta.png -- hdpi/monochrome_npa_beta.png
452 COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_beta.png -- xhdpi/monochrome_npa_beta.png
453 COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_beta.png -- xxhdpi/monochrome_npa_beta.png
454 COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_beta.png -- xxxhdpi/monochrome_npa_beta.png
455 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
456
457 add_custom_target(pngquant.android.adaptive.monochrome.preview
458 COMMAND ${PNGQUANT_CMD} ldpi/monochrome_npa_preview.png -- ldpi/monochrome_npa_preview.png
459 COMMAND ${PNGQUANT_CMD} mdpi/monochrome_npa_preview.png -- mdpi/monochrome_npa_preview.png
460 COMMAND ${PNGQUANT_CMD} hdpi/monochrome_npa_preview.png -- hdpi/monochrome_npa_preview.png
461 COMMAND ${PNGQUANT_CMD} xhdpi/monochrome_npa_preview.png -- xhdpi/monochrome_npa_preview.png
462 COMMAND ${PNGQUANT_CMD} xxhdpi/monochrome_npa_preview.png -- xxhdpi/monochrome_npa_preview.png
463 COMMAND ${PNGQUANT_CMD} xxxhdpi/monochrome_npa_preview.png -- xxxhdpi/monochrome_npa_preview.png
407464 WORKING_DIRECTORY ${RESOURCES_DIR}/images/android)
408465
409466 add_custom_target(pngquant.android.launchimage
490547 pngquant.android.adaptive.foreground
491548 pngquant.android.adaptive.foreground.beta
492549 pngquant.android.adaptive.foreground.preview
550 pngquant.android.adaptive.monochrome
551 pngquant.android.adaptive.monochrome.beta
552 pngquant.android.adaptive.monochrome.preview
493553 pngquant.android.launchimage
494554 pngquant.android.launchimage.beta
495555 pngquant.android.launchimage.preview
5151 endif()
5252
5353 READ_REVISION(ANDROID_NDK_REVISION ".*Revision = ([0-9|\\.]+)" "${CMAKE_ANDROID_NDK}/source.properties")
54 READ_REVISION(ANDROID_SDK_REVISION ".*Revision=([0-9|\\.]+)" "${ANDROID_SDK}/cmdline-tools/latest/source.properties;${ANDROID_SDK}/tools/source.properties")
5554
5655 set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
5756 set(CMAKE_SYSTEM_NAME Android)
7271 set(CMAKE_ANDROID_ARM_NEON ON)
7372 endif()
7473
75 # Emulate NDK CMake-Variable as Qt 5.14 needs this (Multi-ABI)
76 set(ANDROID_ABI ${CMAKE_ANDROID_ARCH_ABI})
77
78
7974 set(CMAKE_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH} CACHE STRING "android find search path root")
8075 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
8176 set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
156156 the description of the service provider certificate. This condition is not met.
157157 | **Possible Solutions:** :ref:`failure_code_inform_service_provider`.
158158
159 - | **Pre_Verfication_No_Test_Environment**
159 - | **Pre_Verification_No_Test_Environment**
160160 | Occurs when the development mode of AusweisApp2 is activated and a genuine ID card is used.
161161 | **Possible Solutions:** Disable developer mode. The use of genuine ID cards is not permitted with
162162 activated developer mode, as this is only intended to facilitate the commissioning of services
163163 with test ID cards.
164164
165 - | **Pre_Verfication_Invalid_Certificate_Chain**
165 - | **Pre_Verification_Invalid_Certificate_Chain**
166166 | A certificate chain was sent from the server that is unknown to AusweisApp2.
167167 | **Possible Solutions:** :ref:`failure_code_inform_service_provider`.
168168
169 - | **Pre_Verfication_Invalid_Certificate_Signature**
169 - | **Pre_Verification_Invalid_Certificate_Signature**
170170 | At least one signature in the certificate chain used by the server is incorrect.
171171 | **Possible Solutions:** :ref:`failure_code_inform_service_provider`.
172172
173 - | **Pre_Verfication_Certificate_Expired**
173 - | **Pre_Verification_Certificate_Expired**
174174 | The certificate chain used by the server is currently not valid.
175175 | **Possible Solutions:** Make sure your system time is set correctly. If the problem persists,
176176 see :ref:`failure_code_inform_service_provider`.
261261
262262 - | **Generic_Send_Receive_Paos_Unhandled**
263263 | A message was sent by the server in the PAOS communication during authentication, that
264 could be completely processed.
264 could not be completely processed.
265265 | **Possible Solutions:** :ref:`failure_code_contact_support`.
266266
267267 - | **Generic_Send_Receive_Network_Error**
268268 | A network error has occurred in the PAOS communication during authentication.
269269 | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`.
270270
271 - | **Generic_Send_Receive_Ssl_Error**
271 - | **Generic_Send_Receive_Tls_Error**
272272 | An authentication error occurred in the PAOS communication during the TLS handshake. The TLS
273273 certificate is incorrect.
274274 | **Possible Solutions:** :ref:`failure_code_inform_service_provider`.
317317 did not behave as expected by the server.
318318 | **Possible Solutions:** :ref:`failure_code_contact_support`.
319319
320 - | **Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply**
320 - | **Check_Refresh_Address_Fatal_Tls_Error_Before_Reply**
321321 | An error occurred during the TLS handshake when checking the return address after a successful
322322 authentication. The TLS certificate is incorrect.
323323 | **Possible Solutions:** :ref:`failure_code_inform_service_provider`.
340340 didn't work for checking the return address.
341341 | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`.
342342
343 - | **Check_Refresh_Address_Fatal_Ssl_Error_After_Reply**
343 - | **Check_Refresh_Address_Fatal_Tls_Error_After_Reply**
344344 | When checking the return address after successful authentication, the TLS handshake could not
345345 be completed successfully.
346346 | **Possible Solutions:** :ref:`failure_code_fix_connections_problems`.
412412 self-authentication.
413413 | **Possible Solutions:** :ref:`failure_code_inform_service_provider`.
414414
415 - | **Generic_Provider_Communication_Ssl_Error**
415 - | **Generic_Provider_Communication_Tls_Error**
416416 | An error occurred during the TLS handshake when communicating with a service provider. The TLS
417417 certificate is incorrect. This only applies to services that are started from AusweisApp2,
418418 such as self-authentication.
359359 "TLS-Zertifikate in der Beschreibung des Diensteanbieterzertifikats "
360360 "enthalten sind. Diese Bedingung ist nicht erfüllt."
361361
362 msgid "**Pre_Verfication_No_Test_Environment**"
362 msgid "**Pre_Verification_No_Test_Environment**"
363363 msgstr ""
364364
365365 msgid ""
379379 "dieser nur die Inbetriebnahme von Diensten mit Testausweisen erleichtern "
380380 "soll."
381381
382 msgid "**Pre_Verfication_Invalid_Certificate_Chain**"
382 msgid "**Pre_Verification_Invalid_Certificate_Chain**"
383383 msgstr ""
384384
385385 msgid ""
389389 "Vom Server wurde eine Zertifikatskette gesendet, die der AusweisApp2 "
390390 "nicht bekannt ist."
391391
392 msgid "**Pre_Verfication_Invalid_Certificate_Signature**"
392 msgid "**Pre_Verification_Invalid_Certificate_Signature**"
393393 msgstr ""
394394
395395 msgid ""
399399 "Mindestens eine Signatur in der vom Server genutzten Zertifikatskette ist"
400400 " nicht korrekt."
401401
402 msgid "**Pre_Verfication_Certificate_Expired**"
402 msgid "**Pre_Verification_Certificate_Expired**"
403403 msgstr ""
404404
405405 msgid "The certificate chain used by the server is currently not valid."
638638
639639 msgid ""
640640 "A message was sent by the server in the PAOS communication during "
641 "authentication, that could be completely processed."
641 "authentication, that could not be completely processed."
642642 msgstr ""
643643 "Bei einer Authentisierung ist eine Nachricht vom Server in der PAOS-"
644644 "Kommunikation gesendet worden, die nicht vollständig verarbeitet werden "
654654 "Bei einer Authentisierung ist ein Netzwerkfehler in der PAOS-"
655655 "Kommunikation aufgetreten."
656656
657 msgid "**Generic_Send_Receive_Ssl_Error**"
657 msgid "**Generic_Send_Receive_Tls_Error**"
658658 msgstr ""
659659
660660 msgid ""
765765 "geliefert. Die AusweisApp2 oder die Karte hat sich nicht entsprechend der"
766766 " Erwartung des Servers verhalten."
767767
768 msgid "**Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply**"
768 msgid "**Check_Refresh_Address_Fatal_Tls_Error_Before_Reply**"
769769 msgstr ""
770770
771771 msgid ""
814814 " Proxyserver konfiguriert. Dieser hat für die Überprüfung der "
815815 "Rücksprungadresse nicht funktioniert."
816816
817 msgid "**Check_Refresh_Address_Fatal_Ssl_Error_After_Reply**"
817 msgid "**Check_Refresh_Address_Fatal_Tls_Error_After_Reply**"
818818 msgstr ""
819819
820820 msgid ""
975975 "aus der AusweisApp2 heraus gestartet werden, wie zum Beispiel die "
976976 "Selbstauskunft."
977977
978 msgid "**Generic_Provider_Communication_Ssl_Error**"
978 msgid "**Generic_Provider_Communication_Tls_Error**"
979979 msgstr ""
980980
981981 msgid ""
172172 <false/>
173173 <key>remindToClose</key>
174174 <false/>
175 <key>showSetupAssistant</key>
176 <false/>
175 <key>uiStartupModule</key>
176 <string>DEFAULT</string>
177177 <key>transportPinReminder</key>
178178 <false/>
179179 <key>customProxyType</key>
182182 <string>proxy.example.org</string>
183183 <key>customProxyPort</key>
184184 <integer>1337</integer>
185 <key>autoUpdateCheck</key>
186 <false/>
187185 <key>keylessPassword</key>
188186 <true/>
189187 <key>shuffleScreenKeyboard</key>
208206 ======================= =======================
209207 autoCloseWindow AUTOHIDE
210208 remindToClose REMINDTOCLOSE
211 showSetupAssistant ASSISTANT
209 uiStartupModule ASSISTANT
212210 transportPinReminder TRANSPORTPINREMINDER
213211 customProxyType CUSTOMPROXYTYPE
214212 customProxyPort CUSTOMPROXYPORT
215213 customProxyHost CUSTOMPROXYHOST
216 autoUpdateCheck UPDATECHECK
217214 keylessPassword ONSCREENKEYBOARD
218215 shuffleScreenKeyboard SHUFFLESCREENKEYBOARD
219216 visualPrivacy SECURESCREENKEYBOARD
159159 <false/>
160160 <key>remindToClose</key>
161161 <false/>
162 <key>showSetupAssistant</key>
163 <false/>
162 <key>uiStartupModule</key>
163 <string>DEFAULT</string>
164164 <key>transportPinReminder</key>
165165 <false/>
166166 <key>customProxyType</key>
169169 <string>proxy.example.org</string>
170170 <key>customProxyPort</key>
171171 <integer>1337</integer>
172 <key>autoUpdateCheck</key>
173 <false/>
174172 <key>keylessPassword</key>
175173 <true/>
176174 <key>shuffleScreenKeyboard</key>
194192 ======================= =======================
195193 autoCloseWindow AUTOHIDE
196194 remindToClose REMINDTOCLOSE
197 showSetupAssistant ASSISTANT
195 uiStartupModule ASSISTANT
198196 transportPinReminder TRANSPORTPINREMINDER
199197 customProxyType CUSTOMPROXYTYPE
200198 customProxyPort CUSTOMPROXYPORT
201199 customProxyHost CUSTOMPROXYHOST
202 autoUpdateCheck UPDATECHECK
203200 keylessPassword ONSCREENKEYBOARD
204201 shuffleScreenKeyboard SHUFFLESCREENKEYBOARD
205202 visualPrivacy SECURESCREENKEYBOARD
250247
251248 Broadcast on UDP port 24727 in the local subnet have to be receivable by the
252249 AusweisApp2 to use the "Smartphone as Card Reader" functionality.
253 It may be necessary to deactive AP isolation on your router.
250 It may be necessary to deactivate AP isolation on your router.
254251
255252 .. _communicationmodel_en:
256253 .. figure:: CommunicationModel_en.pdf
0 AusweisApp2 1.26.5
1 ^^^^^^^^^^^^^^^^^^
2
3 **Releasedatum:** 25. Juli 2023
4
5
6 Anwender
7 """"""""
8 - Überarbeitung des Kopplungsprozesses der Funktion Smartphone als Kartenleser.
9 Beide an der Kopplung beteiligten Geräte müssen auf Version 1.26.5 aktualisiert werden.
10 Versionen kleiner als 1.26.5 lassen sich nicht mit einer AusweisApp2 1.26.5 koppeln.
11
12 - Die Anzeige des Fortschritts erfolgt jetzt auch auf einem Smartphone als Kartenleser.
13
14 - Der Tastaturmodus auf einem Smartphone als Kartenleser ist jetzt standardmäßig aktiviert.
15
16 - Bei Nutzung des Tastaturmodus auf einem Smartphone als Kartenleser kann in den Einstellungen eine
17 erneute Anzeige der Berechtigungen aktiviert werden.
18
19 - Ergänzung eines monochromen Icons unter Android.
20
21 - Berücksichtigung von Command + W unter macOS.
22
23 - Entfernung der Updatefunktion auf macOS zugunsten des Mac App Store.
24
25 - Kleinere Fehlerbehebungen und Optimierungen.
26
27
28 Entwickler
29 """"""""""
30 - Die Dokumentation für die Installation in Firmennetzwerken unter macOS für die Einstellung zum
31 Einrichtungsassistenten wurde korrigiert.
32
33 - Optimierung der Größe des Android SDK.
34
35 - Aktualisierung von OpenSSL auf die Version 3.0.9.
44 folgender Systeme und Funktionen eingestellt.
55
66 - macOS Catalina 10.15
7 - Android 7
8 - iOS 13
79 - Online-Hilfe
810 - PDF-Export-Funktion der Selbstauskunft
911
33 .. toctree::
44 :maxdepth: 1
55
6 1.26.5
67 1.26.4
78 1.26.3
89 1.26.2
3737 - Die visuelle Hervorhebung des aktiven Elements wird an einigen Stellen
3838 fälschlicherwiese auch aktiviert, wenn die Maus benutzt wurde.
3939
40 - Unter macOS werden im System hinterlegte Proxy-Server nicht erkannt und
41 damit auch nicht automatisch verwendet. Um manuell einen Proxy-Server in
42 der AusweisApp2 zu hinterlegen beachten Sie die Anleitung zur Installation
43 in Firmennetzwerken.
44
4540 Android / iOS
4641 """""""""""""
4742
5353 Im Rahmen der Qualitätssicherung werden die folgenden Browserversionen
5454 getestet.
5555
56 - Chrome 112
56 - Chrome 115
5757
58 - Firefox 112
58 - Firefox 115
5959
60 - Safari 16.4 (macOS)
60 - Safari 16.5 (macOS)
6161
62 - Edge 112
62 - Edge 115
6363
6464
6565
117117 Anbieter umgesetzten Aktivierung. Daher empfehlen wir einen der
118118 folgenden Browser zu verwenden.
119119
120 - Chrome 112 (iOS/Android)
120 - Chrome 115 (iOS/Android)
121121
122 - Firefox 112 (iOS/Android)
122 - Firefox 115 (iOS/Android)
123123
124 - Samsung Internet 20 (Android)
124 - Samsung Internet 22 (Android)
125125
126 - Safari 16.4 (iOS)
126 - Safari 16.5 (iOS)
127127
128128
129129 Kartenleser
55 .. toctree::
66 :maxdepth: 1
77
8 1.26.5
89 1.26.4
910 1.26.3
1011 1.26.2
809809 to unblock the PIN.
810810
811811 - **deactivated**: True if eID function is deactivated, otherwise false.
812 The scan dialog on iOS won't be closed if this is True. You need to
813 send :ref:`interrupt` yourself to show an error message.
812814
813815 - **retryCounter**: Count of possible retries for the PIN. If you enter a PIN
814816 with command :ref:`set_pin` it will be decreased if PIN was incorrect.
2323
2424 .. code-block:: json
2525
26 {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/DEMO"}
26 {"cmd": "RUN_AUTH", "tcTokenURL": "https://test.governikus-eid.de/AusweisAuskunft/WebServiceRequesterServlet"}
2727
2828 {"msg": "AUTH"}
2929
108108 endif()
109109
110110 ################################## Versions
111 set(QT 6.4.1)
112 set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09)
113
114 set(OPENSSL 3.0.8)
115 set(OPENSSL_HASH 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e)
111 include(Versions.cmake)
116112
117113 ################################## Files
118114 set(QT_FILE qt-everywhere-src-${QT}.tar.xz)
0 set(QT 6.4.1)
1 set(QT_HASH e20b850b6134098a7f2e7701cfddfb213c6cf394b9e848e6fbc5b0e89dcfcc09)
2
3 set(OPENSSL 3.0.9)
4 set(OPENSSL_HASH eb1ab04781474360f77c318ab89d8c5a03abc38e63d65a603cabbf1b00a1dc90)
1414 function(PATCH_SOURCES _component)
1515 set(PATCHES_DIR @PROJECT_SOURCE_DIR@/patches)
1616
17 file(GLOB PATCHES "${PATCHES_DIR}/${_component}-*.patch")
17 file(GLOB PATCHES "${PATCHES_DIR}/${_component}*.patch")
1818 PATCH_SOURCES_EXECUTE("${PATCHES}")
1919
2020 if("@CMAKE_BUILD_TYPE@" STREQUAL "DEBUG")
21 file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}-*.patch")
21 file(GLOB PATCHES_DEBUG "${PATCHES_DIR}/debug/${_component}*.patch")
2222 PATCH_SOURCES_EXECUTE("${PATCHES_DEBUG}")
2323 endif()
2424 endfunction()
0 From a16972bcfd33b694fd27d19e85754be74daa4430 Mon Sep 17 00:00:00 2001
0 From c97e9531a9da0ad5ae3bfb7cec90b03475a58a76 Mon Sep 17 00:00:00 2001
11 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
22 Date: Fri, 12 Feb 2021 13:15:00 +0100
33 Subject: Adjust iOS target
77 1 file changed, 1 insertion(+), 1 deletion(-)
88
99 diff --git x/Configurations/15-ios.conf y/Configurations/15-ios.conf
10 index 54d37f63f4..a4ade8d209 100644
10 index 54d37f63f4..7e411b2e3a 100644
1111 --- x/Configurations/15-ios.conf
1212 +++ y/Configurations/15-ios.conf
1313 @@ -25,7 +25,7 @@ my %targets = (
1919 bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR",
2020 asm_arch => 'aarch64',
2121 perlasm_scheme => "ios64",
22 --
23 2.35.1
0 From 8e011194bf8b4e4275f51f76b75a1b22e45e9564 Mon Sep 17 00:00:00 2001
0 From 8353ce61f188109953e327b4bddf65c95e4baf92 Mon Sep 17 00:00:00 2001
11 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
22 Date: Tue, 19 Jan 2021 17:07:51 +0100
33 Subject: android shlib_variant
4040 },
4141
4242 ####################################################################
43 --
44 2.35.1
45
0 From 9faa80071777b8a0b9eca1ab59bf69adb4621d9f Mon Sep 17 00:00:00 2001
1 From: Tomas Mraz <tomas@openssl.org>
2 Date: Tue, 4 Jul 2023 17:30:35 +0200
3 Subject: Do not ignore empty associated data with AES-SIV mode
4
5 The AES-SIV mode allows for multiple associated data items
6 authenticated separately with any of these being 0 length.
7
8 The provided implementation ignores such empty associated data
9 which is incorrect in regards to the RFC 5297 and is also
10 a security issue because such empty associated data then become
11 unauthenticated if an application expects to authenticate them.
12
13 Fixes CVE-2023-2975
14
15 Reviewed-by: Matt Caswell <matt@openssl.org>
16 Reviewed-by: Paul Dale <pauli@openssl.org>
17 (Merged from https://github.com/openssl/openssl/pull/21384)
18
19 (cherry picked from commit c426c281cfc23ab182f7d7d7a35229e7db1494d9)
20 (cherry picked from commit 00e2f5eea29994d19293ec4e8c8775ba73678598)
21 ---
22 .../implementations/ciphers/cipher_aes_siv.c | 18 +++++++++++-------
23 1 file changed, 11 insertions(+), 7 deletions(-)
24
25 diff --git x/providers/implementations/ciphers/cipher_aes_siv.c y/providers/implementations/ciphers/cipher_aes_siv.c
26 index 45010b90db..b396c8651a 100644
27 --- x/providers/implementations/ciphers/cipher_aes_siv.c
28 +++ y/providers/implementations/ciphers/cipher_aes_siv.c
29 @@ -120,14 +120,18 @@ static int siv_cipher(void *vctx, unsigned char *out, size_t *outl,
30 if (!ossl_prov_is_running())
31 return 0;
32
33 - if (inl == 0) {
34 - *outl = 0;
35 - return 1;
36 - }
37 + /* Ignore just empty encryption/decryption call and not AAD. */
38 + if (out != NULL) {
39 + if (inl == 0) {
40 + if (outl != NULL)
41 + *outl = 0;
42 + return 1;
43 + }
44
45 - if (outsize < inl) {
46 - ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
47 - return 0;
48 + if (outsize < inl) {
49 + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
50 + return 0;
51 + }
52 }
53
54 if (ctx->hw->cipher(ctx, out, in, inl) <= 0)
0 From c012334ed713416cc30d6b2ff4dbeca97d1503c3 Mon Sep 17 00:00:00 2001
1 From: Matt Caswell <matt@openssl.org>
2 Date: Thu, 6 Jul 2023 16:36:35 +0100
3 Subject: Fix DH_check() excessive time with over sized modulus
4
5 The DH_check() function checks numerous aspects of the key or parameters
6 that have been supplied. Some of those checks use the supplied modulus
7 value even if it is excessively large.
8
9 There is already a maximum DH modulus size (10,000 bits) over which
10 OpenSSL will not generate or derive keys. DH_check() will however still
11 perform various tests for validity on such a large modulus. We introduce a
12 new maximum (32,768) over which DH_check() will just fail.
13
14 An application that calls DH_check() and supplies a key or parameters
15 obtained from an untrusted source could be vulnerable to a Denial of
16 Service attack.
17
18 The function DH_check() is itself called by a number of other OpenSSL
19 functions. An application calling any of those other functions may
20 similarly be affected. The other functions affected by this are
21 DH_check_ex() and EVP_PKEY_param_check().
22
23 CVE-2023-3446
24
25 Reviewed-by: Paul Dale <pauli@openssl.org>
26 Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com>
27 Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
28 Reviewed-by: Tomas Mraz <tomas@openssl.org>
29 (Merged from https://github.com/openssl/openssl/pull/21451)
30
31 (cherry picked from commit 9e0094e2aa1b3428a12d5095132f133c078d3c3d)
32 (cherry picked from commit 1fa20cf2f506113c761777127a38bce5068740eb)
33 ---
34 crypto/dh/dh_check.c | 6 ++++++
35 include/openssl/dh.h | 6 +++++-
36 2 files changed, 11 insertions(+), 1 deletion(-)
37
38 diff --git x/crypto/dh/dh_check.c y/crypto/dh/dh_check.c
39 index 0b391910d6..84a926998e 100644
40 --- x/crypto/dh/dh_check.c
41 +++ y/crypto/dh/dh_check.c
42 @@ -152,6 +152,12 @@ int DH_check(const DH *dh, int *ret)
43 if (nid != NID_undef)
44 return 1;
45
46 + /* Don't do any checks at all with an excessively large modulus */
47 + if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) {
48 + ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
49 + return 0;
50 + }
51 +
52 if (!DH_check_params(dh, ret))
53 return 0;
54
55 diff --git x/include/openssl/dh.h y/include/openssl/dh.h
56 index b97871eca7..36420f51d8 100644
57 --- x/include/openssl/dh.h
58 +++ y/include/openssl/dh.h
59 @@ -89,7 +89,11 @@ int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **ukm);
60 # include <openssl/dherr.h>
61
62 # ifndef OPENSSL_DH_MAX_MODULUS_BITS
63 -# define OPENSSL_DH_MAX_MODULUS_BITS 10000
64 +# define OPENSSL_DH_MAX_MODULUS_BITS 10000
65 +# endif
66 +
67 +# ifndef OPENSSL_DH_CHECK_MAX_MODULUS_BITS
68 +# define OPENSSL_DH_CHECK_MAX_MODULUS_BITS 32768
69 # endif
70
71 # define OPENSSL_DH_FIPS_MIN_MODULUS_BITS 1024
+0
-43
libs/patches/qt-base-0001-Revert-Fix-usage-of-logging-category-on-Android.patch less more
0 From ca3a694221c62131a384cbabd7dc34f91add9eae Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= <aklitzing@gmail.com>
2 Date: Mon, 25 Jul 2022 17:08:54 +0200
3 Subject: Revert "Fix usage of logging category on Android"
4
5 This reverts commit 87d8ee755bfdef8e72a122789c2e3ed382881a12.
6
7 Change-Id: If19a9d615e01d61c79955cda4789ba1646520ee1
8 ---
9 src/corelib/global/qlogging.cpp | 9 +--------
10 1 file changed, 1 insertion(+), 8 deletions(-)
11
12 diff --git x/qtbase/src/corelib/global/qlogging.cpp y/qtbase/src/corelib/global/qlogging.cpp
13 index 9ac70b3340..737a91dc6e 100644
14 --- x/qtbase/src/corelib/global/qlogging.cpp
15 +++ y/qtbase/src/corelib/global/qlogging.cpp
16 @@ -1450,10 +1450,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
17 } else if (token == messageTokenC) {
18 message.append(str);
19 } else if (token == categoryTokenC) {
20 -#ifndef Q_OS_ANDROID
21 - // Don't add the category to the message on Android
22 message.append(QLatin1StringView(context.category));
23 -#endif
24 } else if (token == typeTokenC) {
25 switch (type) {
26 case QtDebugMsg: message.append("debug"_L1); break;
27 @@ -1701,11 +1698,7 @@ static bool android_default_message_handler(QtMsgType type,
28 break;
29 };
30
31 - // If application name is a tag ensure it has no spaces
32 - // If a category is defined, use it as an Android logging tag
33 - __android_log_print(priority, isDefaultCategory(context.category) ?
34 - qPrintable(QCoreApplication::applicationName().replace(u' ', u'_')) : context.category,
35 - "%s\n", qPrintable(formattedMessage));
36 + __android_log_print(priority, qPrintable(QCoreApplication::applicationName()), "%s\n", qPrintable(formattedMessage));
37
38 return true; // Prevent further output to stderr
39 }
40 --
41 2.38.1
42
+0
-66
libs/patches/qt-base-0002-Revert-Android-Fix-QSettings-when-using-content-URL.patch less more
0 From c6818d0c25f067bc13198b9aa2ca82776a40ad3b Mon Sep 17 00:00:00 2001
1 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
2 Date: Wed, 14 Dec 2022 11:52:12 +0100
3 Subject: Revert "Android: Fix QSettings when using content URL"
4
5 This reverts commit 140ca89a3c2b8d78889d27217f977cd4de10041b.
6 ---
7 src/corelib/io/qsettings.cpp | 21 +++------------------
8 1 file changed, 3 insertions(+), 18 deletions(-)
9
10 diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp
11 index 60622e3aaa..a999aa6996 100644
12 --- x/qtbase/src/corelib/io/qsettings.cpp
13 +++ y/qtbase/src/corelib/io/qsettings.cpp
14 @@ -48,9 +48,8 @@
15 #define Q_XDG_PLATFORM
16 #endif
17
18 -#if !defined(QT_NO_STANDARDPATHS) \
19 - && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID))
20 -# define QSETTINGS_USE_QSTANDARDPATHS
21 +#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
22 +#define QSETTINGS_USE_QSTANDARDPATHS
23 #endif
24
25 // ************************************************************************
26 @@ -1332,15 +1331,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
27 }
28
29 #ifndef QT_BOOTSTRAPPED
30 - QString lockFileName = confFile->name + ".lock"_L1;
31 -
32 -# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS)
33 - // On android and if it is a content URL put the lock file in a
34 - // writable location to prevent permissions issues and invalid paths.
35 - if (confFile->name.startsWith("content:"_L1))
36 - lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
37 - + QFileInfo(lockFileName).fileName();
38 -# endif
39 /*
40 Use a lockfile in order to protect us against other QSettings instances
41 trying to write the same settings at the same time.
42 @@ -1348,7 +1338,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
43 We only need to lock if we are actually writing as only concurrent writes are a problem.
44 Concurrent read and write are not a problem because the writing operation is atomic.
45 */
46 - QLockFile lockFile(lockFileName);
47 + QLockFile lockFile(confFile->name + ".lock"_L1);
48 if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
49 setStatus(QSettings::AccessError);
50 return;
51 @@ -1426,11 +1416,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
52 #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
53 QSaveFile sf(confFile->name);
54 sf.setDirectWriteFallback(!atomicSyncOnly);
55 -# ifdef Q_OS_ANDROID
56 - // QSaveFile requires direct write when using content scheme URL in Android
57 - if (confFile->name.startsWith("content:"_L1))
58 - sf.setDirectWriteFallback(true);
59 -# endif
60 #else
61 QFile sf(confFile->name);
62 #endif
63 --
64 2.39.0
65
+0
-66
libs/patches/qt-base-0003-Android-A11Y-Only-access-the-main-thread-when-it-is-.patch less more
0 From 97d4394f85f120724a9cbe518ba2233b87e48c68 Mon Sep 17 00:00:00 2001
1 From: Julian Greilich <j.greilich@gmx.de>
2 Date: Wed, 4 Jan 2023 16:32:28 +0100
3 Subject: Android A11Y: Only access the main thread when it is not blocked
4
5 When the qtMainLoopThread calls QSGThreadedRenderLoop::polishAndSync(),
6 it waits for the QSGRenderThread.
7
8 In the QSGRenderThread, QAndroidPlatformOpenGLWindow::eglSurface()
9 calls QtAndroid::createSurface() and waits for the "android main
10 thread" to return a valid surface.
11 When the "android main thread" now calls "runInObjectContext" (e.g. by
12 calling QtAndroidAccessibility::childIdListForAccessibleObject()) it
13 waits for the qtMainLoopThread and the program is stuck in a deadlock.
14
15 To prevent this, we protect all BlockedQueuedConnection from the
16 "android main thread" to the qtMainLoopThread by acquiring the
17 AndroidDeadlockProtector.
18 When QAndroidPlatformOpenGLWindow::eglSurface() already acquired the
19 AndroidDeadlockProtector we abort the current A11y call with an emtpy
20 or default value.
21
22 Note: b8a95275440b8a143ee648466fd8b5401ee1e839 already tried to fix
23 this by checking "getSurfaceCount() != 0", but there are situations,
24 where a new surface is being created while an old surface is still
25 present.
26
27 Task-number: QTBUG-105958
28 Pick-to: 6.5 6.4 6.3 6.2 5.15
29 Change-Id: Ie40e8654c99aace9e69b0b8412952fa22c89f071
30 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
31 (cherry picked from commit b832a5ac72c6015b6509d60b75b2ce5d5e570800)
32 ---
33 .../platforms/android/androidjniaccessibility.cpp | 9 +++++++++
34 1 file changed, 9 insertions(+)
35
36 diff --git x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp
37 index 3067cb178a..8990289dc4 100644
38 --- x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp
39 +++ y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp
40 @@ -1,6 +1,7 @@
41 // Copyright (C) 2021 The Qt Company Ltd.
42 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
43
44 +#include "androiddeadlockprotector.h"
45 #include "androidjniaccessibility.h"
46 #include "androidjnimain.h"
47 #include "qandroidplatformintegration.h"
48 @@ -61,6 +62,14 @@ namespace QtAndroidAccessibility
49 template <typename Func, typename Ret>
50 void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
51 {
52 + AndroidDeadlockProtector protector;
53 + if (!protector.acquire()) {
54 + __android_log_print(ANDROID_LOG_WARN, m_qtTag,
55 + "Could not run accessibility call in object context, accessing "
56 + "main thread could lead to deadlock");
57 + return;
58 + }
59 +
60 if (!QtAndroid::blockEventLoopsWhenSuspended()
61 || QGuiApplication::applicationState() != Qt::ApplicationSuspended) {
62 QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal);
63 --
64 2.39.0
65
+0
-49
libs/patches/qt-base-0004-Fix-warning-in-q20algorithm.h-when-xcodebuild-is-use.patch less more
0 From bc1b984a5b1a53c0c9eccc44763aaf0c94294fb7 Mon Sep 17 00:00:00 2001
1 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
2 Date: Mon, 9 Jan 2023 06:54:53 +0100
3 Subject: Fix warning in q20algorithm.h when xcodebuild is used
4
5 q20algorithm.h:150:20: error: unused function template 'operator()'
6 q20algorithm.h:163:20: error: unused function template 'operator()'
7 q20algorithm.h:176:20: error: unused function template 'operator()'
8
9 Fixes: QTBUG-109874
10 Change-Id: If5ccbfffd0b6a53f73f221b45033dab7e4775d89
11 ---
12 src/corelib/global/q20algorithm.h | 6 +++---
13 1 file changed, 3 insertions(+), 3 deletions(-)
14
15 diff --git x/qtbase/src/corelib/global/q20algorithm.h y/qtbase/src/corelib/global/q20algorithm.h
16 index 69dc2d2446..88e8ab08d2 100644
17 --- x/qtbase/src/corelib/global/q20algorithm.h
18 +++ y/qtbase/src/corelib/global/q20algorithm.h
19 @@ -147,7 +147,7 @@ using std::ranges::none_of;
20 [[maybe_unused]] inline constexpr struct { // Niebloid
21 template <typename InputIterator, typename Sentinel,
22 typename Predicate, typename Projection = q20::identity>
23 - constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
24 + [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
25 {
26 while (first != last) {
27 if (std::invoke(pred, std::invoke(proj, *first)))
28 @@ -160,7 +160,7 @@ using std::ranges::none_of;
29 [[maybe_unused]] inline constexpr struct { // Niebloid
30 template <typename InputIterator, typename Sentinel,
31 typename Predicate, typename Projection = q20::identity>
32 - constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
33 + [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
34 {
35 while (first != last) {
36 if (!std::invoke(pred, std::invoke(proj, *first)))
37 @@ -173,7 +173,7 @@ using std::ranges::none_of;
38 [[maybe_unused]] inline constexpr struct { // Niebloid
39 template <typename InputIterator, typename Sentinel,
40 typename Predicate, typename Projection = q20::identity>
41 - constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
42 + [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
43 {
44 while (first != last) {
45 if (std::invoke(pred, std::invoke(proj, *first)))
46 --
47 2.39.0
48
+0
-130
libs/patches/qt-base-0005-macOS-Use-NSStatusItem.menu-to-manage-system-tray-me.patch less more
0 From d5555d3c62cbc8c061de0ae9e1f0c20374b4004e Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@qt.io>
2 Date: Mon, 12 Dec 2022 14:33:41 +0100
3 Subject: macOS: Use NSStatusItem.menu to manage system tray menu
4
5 Using [NSStatusItem popUpStatusItemMenu:] to manually show the menu is
6 deprecated, and was causing various issues when right clicking the menu,
7 such as not unhighlighting the menu item when dismissing the menu, or
8 worse, not quitting the application if a 'Quit' item was triggered from
9 a right click.
10
11 The reason we were using popUpStatusItemMenu instead of the menu
12 property of NSStatusItem was that the latter prevented us from seeing
13 the action message of the NSStatusItem button, which we used to emit
14 the system tray's activated signal, but this can be solved by listing
15 for the menu's tracking state starting.
16
17 Fixes: QTBUG-103515
18 Pick-to: 6.4
19 Change-Id: I686550ebac7d94d8d11b2e3c49ed16a8240cb214
20 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
21 (cherry picked from commit da754d5b6589c9877f0325edb3da5cbc64d966c7)
22 ---
23 .../platforms/cocoa/qcocoasystemtrayicon.h | 3 +-
24 .../platforms/cocoa/qcocoasystemtrayicon.mm | 36 ++++++++++++-------
25 2 files changed, 24 insertions(+), 15 deletions(-)
26
27 diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
28 index 414560e1192..75c33cc5a3f 100644
29 --- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
30 +++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
31 @@ -45,12 +45,11 @@ public:
32 bool isSystemTrayAvailable() const override;
33 bool supportsMessages() const override;
34
35 - void statusItemClicked();
36 + void emitActivated();
37
38 private:
39 NSStatusItem *m_statusItem = nullptr;
40 QStatusItemDelegate *m_delegate = nullptr;
41 - QCocoaMenu *m_menu = nullptr;
42 };
43
44 QT_END_NAMESPACE
45 diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
46 index c004cd69b57..2f7f73b4813 100644
47 --- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
48 +++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
49 @@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init()
50
51 m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this];
52
53 + // In case the status item does not have a menu assigned to it
54 + // we fall back to the item's button to detect activation.
55 m_statusItem.button.target = m_delegate;
56 m_statusItem.button.action = @selector(statusItemClicked);
57 [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown];
58 @@ -81,8 +83,6 @@ void QCocoaSystemTrayIcon::cleanup()
59
60 [m_delegate release];
61 m_delegate = nil;
62 -
63 - m_menu = nullptr;
64 }
65
66 QRect QCocoaSystemTrayIcon::geometry() const
67 @@ -178,12 +178,20 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
68
69 void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
70 {
71 - // We don't set the menu property of the NSStatusItem here,
72 - // as that would prevent us from receiving the action for the
73 - // click, and we wouldn't be able to emit the activated signal.
74 - // Instead we show the menu manually when the status item is
75 - // clicked.
76 - m_menu = static_cast<QCocoaMenu *>(menu);
77 + m_statusItem.menu = menu ? static_cast<QCocoaMenu *>(menu)->nsMenu() : nil;
78 +
79 + if (m_statusItem.menu) {
80 + // When a menu is assigned, NSStatusBarButtonCell will intercept the mouse
81 + // down to pop up the menu, and we never see the NSStatusBarButton action.
82 + // To ensure we emit the 'activated' signal in both cases we detect when
83 + // menu starts tracking, which happens before the menu delegate is sent
84 + // the menuWillOpen callback we use to emit aboutToShow for the menu.
85 + [NSNotificationCenter.defaultCenter addObserver:m_delegate
86 + selector:@selector(statusItemMenuBeganTracking:)
87 + name:NSMenuDidBeginTrackingNotification
88 + object:m_statusItem.menu
89 + ];
90 + }
91 }
92
93 void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip)
94 @@ -226,7 +234,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
95 }
96 }
97
98 -void QCocoaSystemTrayIcon::statusItemClicked()
99 +void QCocoaSystemTrayIcon::emitActivated()
100 {
101 auto *mouseEvent = NSApp.currentEvent;
102
103 @@ -245,9 +253,6 @@ void QCocoaSystemTrayIcon::statusItemClicked()
104 }
105
106 emit activated(activationReason);
107 -
108 - if (NSMenu *menu = m_menu ? m_menu->nsMenu() : nil)
109 - QT_IGNORE_DEPRECATIONS([m_statusItem popUpStatusItemMenu:menu]);
110 }
111
112 QT_END_NAMESPACE
113 @@ -270,7 +275,12 @@ QT_END_NAMESPACE
114
115 - (void)statusItemClicked
116 {
117 - self.platformSystemTray->statusItemClicked();
118 + self.platformSystemTray->emitActivated();
119 +}
120 +
121 +- (void)statusItemMenuBeganTracking:(NSNotification*)notification
122 +{
123 + self.platformSystemTray->emitActivated();
124 }
125
126 - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
127 --
128 2.39.2
129
+0
-44
libs/patches/qt-base-0006-iOS-Don-t-assume-screens-will-not-be-connected-befor.patch less more
0 From e28710e3f175663b030c00d75ee899a9a7b0cdd2 Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@qt.io>
2 Date: Thu, 15 Dec 2022 16:40:34 +0100
3 Subject: iOS: Don't assume screens will not be connected before
4 QIOSIntegration
5
6 When an external screen is connected to an iPad, and the application is
7 starting up on that screen, we will get a connection notification about
8 that screen as part of the initial bootstrap of UIApplicationMain,
9 before we call the user's main().
10
11 Since we initialize and add all available screen on QIOSIntegration
12 creation, we can just ignore the early connection notification.
13
14 This avoids a crash, but the window will not show anything on the
15 external screen, which is a separate issue.
16
17 Pick-to: 6.5 6.4 6.2
18 Fixes: QTBUG-106701
19 Change-Id: I9e0a9736bf602277316bd004e0d01c640feaf319
20 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
21 (cherry picked from commit dd49793bc3b4dd3808f0f24b717c442a5095db14)
22 ---
23 src/plugins/platforms/ios/qiosscreen.mm | 4 ++--
24 1 file changed, 2 insertions(+), 2 deletions(-)
25
26 diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
27 index f144c00fb0a..3d660189af4 100644
28 --- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm
29 +++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
30 @@ -72,8 +72,8 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
31
32 + (void)screenConnected:(NSNotification*)notification
33 {
34 - Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO,
35 - "Screen connected before QIOSIntegration creation");
36 + if (!QIOSIntegration::instance())
37 + return; // Will be added when QIOSIntegration is created
38
39 QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object]));
40 }
41 --
42 2.39.2
43
+0
-57
libs/patches/qt-base-0007-Ignore-removed-changed-screens-if-no-QIOSIntegration.patch less more
0 From ae857fcf8415daafa6b77999dc8a44cd0e5ede7b Mon Sep 17 00:00:00 2001
1 From: Jan Moeller <jan.moeller@governikus.de>
2 Date: Thu, 6 Apr 2023 09:27:16 +0200
3 Subject: Ignore removed/changed screens if no QIOSIntegration instance exists
4
5 QIOSTracker registers itself as handlers for system notifications about
6 changes of the screen environment. If no QIOSIntegration instance
7 exists, newly detected screens are not added to the list of known
8 screens (see screenConnected()). This, in turn, will result in a crash
9 if a screen is disconnected and removed in screenDisconnected() as it
10 is not known to qtPlatformScreenFor() and the function returns a
11 nullptr.
12
13 Consider the QIOSIntegration also whenever a screen is "changed". This
14 is more of a safety measure do avoid crashes for unknown screens.
15
16 This situation occurs if an iOS device is used to mirror the display
17 via AirPlay and no actual QGuiApplication exists, e.g. Qt is only
18 embedded in a Framework.
19
20 Pick-to: 6.5 6.2
21 Fixes: QTBUG-106701
22 Change-Id: Id778fc5afa7c284b0536ee02b1ba2c10321cc5b1
23 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
24 Reviewed-by: Lars Schmertmann <lars.schmertmann@governikus.de>
25 (cherry picked from commit ffdfafc4b47b8267395370199073c292da33dd42)
26 ---
27 src/plugins/platforms/ios/qiosscreen.mm | 6 ++++++
28 1 file changed, 6 insertions(+)
29
30 diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
31 index 3d660189af4..e0216ce6526 100644
32 --- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm
33 +++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
34 @@ -80,6 +80,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
35
36 + (void)screenDisconnected:(NSNotification*)notification
37 {
38 + if (!QIOSIntegration::instance())
39 + return;
40 +
41 QIOSScreen *screen = qtPlatformScreenFor([notification object]);
42 Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about");
43
44 @@ -88,6 +91,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
45
46 + (void)screenModeChanged:(NSNotification*)notification
47 {
48 + if (!QIOSIntegration::instance())
49 + return;
50 +
51 QIOSScreen *screen = qtPlatformScreenFor([notification object]);
52 Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about");
53
54 --
55 2.39.2
56
+0
-140
libs/patches/qt-connectivity-0001-iOS-NFC-Always-ensure-timeout-after-session-invalida.patch less more
0 From 720768b715d432aa084c9c15b994a396a89968a8 Mon Sep 17 00:00:00 2001
1 From: Julian Greilich <j.greilich@gmx.de>
2 Date: Thu, 26 Jan 2023 19:19:21 +0100
3 Subject: iOS NFC: Always ensure timeout after session invalidation
4
5 iOS needs some time after invalidating a session before a new session
6 can be started. Otherwise the NFC dialog of iOS will not show up.
7
8 For restarting a session inside the iOS NearfieldManager, this was
9 already solved with a timeout of 2 seconds.
10
11 This commit fixes the case, that a user of the Nearfieldmanager
12 restarts a session manually too fast.
13
14 Change-Id: Ic91ad225a9cab13ba92523f33a19f44af68575a0
15 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
16 (cherry picked from commit 849ba86ba9a073a266219b6a39786e20f4f3ed7b)
17 (cherry picked from commit 5052cd14c28bbf0ff93c465a4e33bf1dbd48c7dd)
18 ---
19 src/nfc/qnearfieldmanager_ios.mm | 44 +++++++++++++++++++++----------
20 src/nfc/qnearfieldmanager_ios_p.h | 5 +++-
21 2 files changed, 34 insertions(+), 15 deletions(-)
22
23 diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm
24 index 6fd71451..a0651626 100644
25 --- x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm
26 +++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm
27 @@ -25,6 +25,10 @@ QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
28 connect(this, &QNearFieldManagerPrivateImpl::didInvalidateWithError,
29 this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
30 Qt::QueuedConnection);
31 +
32 + sessionTimer.setInterval(2000);
33 + sessionTimer.setSingleShot(true);
34 + connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer);
35 }
36
37 QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
38 @@ -62,7 +66,7 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access
39 if (@available(iOS 13, *))
40 if (NFCTagReaderSession.readingAvailable) {
41 detectionRunning = true;
42 - startSession();
43 + scheduleSession();
44 return true;
45 }
46 return false;
47 @@ -71,16 +75,28 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access
48
49 void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage)
50 {
51 - if (detectionRunning) {
52 - stopSession(errorMessage);
53 - detectionRunning = false;
54 - Q_EMIT targetDetectionStopped();
55 - }
56 + if (!detectionRunning)
57 + return;
58 +
59 + isSessionScheduled = false;
60 + stopSession(errorMessage);
61 + detectionRunning = false;
62 + Q_EMIT targetDetectionStopped();
63 }
64
65 +void QNearFieldManagerPrivateImpl::scheduleSession()
66 +{
67 + if (sessionTimer.isActive()) {
68 + isSessionScheduled = true;
69 + return;
70 + }
71 +
72 + startSession();
73 +}
74
75 void QNearFieldManagerPrivateImpl::startSession()
76 {
77 + isSessionScheduled = false;
78 if (detectionRunning)
79 if (@available(iOS 13, *))
80 [delegate startSession];
81 @@ -132,17 +148,11 @@ void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *tar
82 void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
83 {
84 clearTargets();
85 + sessionTimer.start();
86
87 if (detectionRunning && doRestart)
88 {
89 - if (!isRestarting) {
90 - isRestarting = true;
91 - using namespace std::chrono_literals;
92 - QTimer::singleShot(2s, this, [this](){
93 - isRestarting = false;
94 - startSession();
95 - });
96 - }
97 + scheduleSession();
98 return;
99 }
100
101 @@ -150,4 +160,10 @@ void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
102 Q_EMIT targetDetectionStopped();
103 }
104
105 +void QNearFieldManagerPrivateImpl::onSessionTimer()
106 +{
107 + if (isSessionScheduled)
108 + scheduleSession();
109 +}
110 +
111 QT_END_NAMESPACE
112 diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h
113 index 6aa1574e..b3668ff6 100644
114 --- x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h
115 +++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h
116 @@ -54,9 +54,11 @@ Q_SIGNALS:
117 private:
118 QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) *delegate API_AVAILABLE(ios(13.0)) = nullptr;
119 bool detectionRunning = false;
120 - bool isRestarting = false;
121 + bool isSessionScheduled = false;
122 + QTimer sessionTimer;
123 QList<QNearFieldTargetPrivateImpl *> detectedTargets;
124
125 + void scheduleSession();
126 void startSession();
127 void stopSession(const QString &error);
128 void clearTargets();
129 @@ -65,6 +67,7 @@ private Q_SLOTS:
130 void onTagDiscovered(void *target);
131 void onTargetLost(QNearFieldTargetPrivateImpl *target);
132 void onDidInvalidateWithError(bool doRestart);
133 + void onSessionTimer();
134 };
135
136
137 --
138 2.39.1
139
+0
-102
libs/patches/qt-declarative-0001-qmlformat-fix-omitting-some-comments-while-reformatt.patch less more
0 From f5b5a974f6ad854008c587c9494ae46785e21899 Mon Sep 17 00:00:00 2001
1 From: Semih Yavuz <semih.yavuz@qt.io>
2 Date: Wed, 18 Jan 2023 15:36:23 +0100
3 Subject: qmlformat: fix omitting some comments while reformatting
4
5 We rewrite comments associated to a node on the preVisit call
6 (if they were marked as preComment), or postVisit( if comments were
7 marked as postComments) of the reformatter. If the comment
8 associated with a patternProperty kind of node, neither of these
9 functions are called. Add missing call to previsit/postVist
10 in the pattern property node visit.
11
12 Pick-to: 6.4 6.5
13 Fixes: QTBUG-109074
14 Change-Id: If57968b3f5dbd83aa23dc2cd2bca3608ee841d49
15 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
16 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
17 (cherry picked from commit 444d4f1f3f27a81996d9cbcc0642040b68728260)
18 ---
19 src/qmldom/qqmldomreformatter.cpp | 2 ++
20 .../qmlformat/data/dontRemoveComments.formatted.qml | 13 +++++++++++++
21 .../auto/qml/qmlformat/data/dontRemoveComments.qml | 13 +++++++++++++
22 tests/auto/qml/qmlformat/tst_qmlformat.cpp | 3 +++
23 4 files changed, 31 insertions(+)
24 create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml
25 create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.qml
26
27 diff --git x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp
28 index bb76f8f772..3dfacfc84e 100644
29 --- x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp
30 +++ y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp
31 @@ -301,6 +301,7 @@ protected:
32 for (PatternPropertyList *it = ast; it; it = it->next) {
33 PatternProperty *assignment = AST::cast<PatternProperty *>(it->property);
34 if (assignment) {
35 + preVisit(assignment);
36 bool isStringLike = AST::cast<StringLiteralPropertyName *>(assignment->name)
37 || cast<IdentifierPropertyName *>(assignment->name);
38 if (isStringLike)
39 @@ -316,6 +317,7 @@ protected:
40 accept(assignment->initializer);
41 if (it->next)
42 newLine();
43 + postVisit(assignment);
44 continue;
45 }
46 PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(it->next);
47 diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml
48 new file mode 100644
49 index 0000000000..0c7a2829c9
50 --- /dev/null
51 +++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml
52 @@ -0,0 +1,13 @@
53 +Item {
54 + property var test: [{
55 + // Testing
56 + "foo": "bar"
57 + }]
58 +
59 + onTestChanged: {
60 + fooBar(test, {
61 + // Testing
62 + "foo": "bar"
63 + });
64 + }
65 +}
66 diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml
67 new file mode 100644
68 index 0000000000..1797834879
69 --- /dev/null
70 +++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml
71 @@ -0,0 +1,13 @@
72 +Item {
73 + property var test: [{
74 +// Testing
75 + "foo": "bar"
76 + }]
77 +
78 + onTestChanged: {
79 + fooBar(test, {
80 + // Testing
81 + "foo": "bar"
82 + });
83 + }
84 +}
85 diff --git x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp
86 index 9d7beb23a7..7755095acd 100644
87 --- x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp
88 +++ y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp
89 @@ -276,6 +276,9 @@ void TestQmlformat::testFormat_data()
90 QTest::newRow("forWithLet")
91 << "forWithLet.qml"
92 << "forWithLet.formatted.qml" << QStringList {} << RunOption::OnCopy;
93 + QTest::newRow("dontRemoveComments")
94 + << "dontRemoveComments.qml"
95 + << "dontRemoveComments.formatted.qml" << QStringList {} << RunOption::OnCopy;
96 }
97
98 void TestQmlformat::testFormat()
99 --
100 2.39.1
101
+0
-23
libs/patches/qt-scxml-0001-Make-qtdeclarative-optional-for-CONTAINER_SDK.patch less more
0 From 5a844a0c1b5e9c1b9fb94831afc0724f5deaa7dd Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= <aklitzing@gmail.com>
2 Date: Tue, 12 Apr 2022 10:21:19 +0200
3 Subject: Make qtdeclarative optional for CONTAINER_SDK
4
5 Change-Id: Ia25b91ea5e3716aef4cb096de1052267b70e343d
6 ---
7 dependencies.yaml | 2 +-
8 1 file changed, 1 insertion(+), 1 deletion(-)
9
10 diff --git x/qtscxml/dependencies.yaml y/qtscxml/dependencies.yaml
11 index ee6f92e..7375551 100644
12 --- x/qtscxml/dependencies.yaml
13 +++ y/qtscxml/dependencies.yaml
14 @@ -4,4 +4,4 @@ dependencies:
15 required: true
16 ../qtdeclarative:
17 ref: a514640b2a38391fceaaac3ca01b390ad3d62f31
18 - required: true
19 + required: false
20 --
21 2.38.1
22
+0
-38
libs/patches/qt-scxml-0002-Disable-qtscxml-library.patch less more
0 From ee68d7d67358f92c87720c2f740322fb03ad8299 Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= <aklitzing@gmail.com>
2 Date: Tue, 12 Apr 2022 11:39:12 +0200
3 Subject: Disable qtscxml library
4
5 ---
6 src/CMakeLists.txt | 4 ++--
7 tools/CMakeLists.txt | 2 +-
8 2 files changed, 3 insertions(+), 3 deletions(-)
9
10 diff --git x/qtscxml/src/CMakeLists.txt y/qtscxml/src/CMakeLists.txt
11 index f1b7c2b..7e28acc 100644
12 --- x/qtscxml/src/CMakeLists.txt
13 +++ y/qtscxml/src/CMakeLists.txt
14 @@ -1,8 +1,8 @@
15
16 -add_subdirectory(scxml)
17 +#add_subdirectory(scxml)
18 add_subdirectory(statemachine)
19 if(TARGET Qt::Qml)
20 add_subdirectory(statemachineqml)
21 - add_subdirectory(scxmlqml)
22 +# add_subdirectory(scxmlqml)
23 endif()
24 add_subdirectory(plugins)
25 diff --git x/qtscxml/tools/CMakeLists.txt y/qtscxml/tools/CMakeLists.txt
26 index 9726a78..956f904 100644
27 --- x/qtscxml/tools/CMakeLists.txt
28 +++ y/qtscxml/tools/CMakeLists.txt
29 @@ -1,4 +1,4 @@
30
31 if(QT_FEATURE_commandlineparser)
32 - add_subdirectory(qscxmlc)
33 + #add_subdirectory(qscxmlc)
34 endif()
35 --
36 2.38.1
37
+0
-27
libs/patches/qt-tools-0001-Disable-linguist-but-keep-translation-tools.patch less more
0 From 125584904a64497ae50b227ef326e0fc12683a4b Mon Sep 17 00:00:00 2001
1 From: Jan Moeller <jan.moeller@governikus.de>
2 Date: Mon, 14 Feb 2022 13:46:46 +0100
3 Subject: Disable linguist but keep translation tools
4
5 Change-Id: I1c54eb0e7bb86ec0861b54b5abe753c86bb57dd9
6 ---
7 src/linguist/CMakeLists.txt | 3 ---
8 1 file changed, 3 deletions(-)
9
10 diff --git x/qttools/src/linguist/CMakeLists.txt y/qttools/src/linguist/CMakeLists.txt
11 index 16ff9f559..fde23b0c4 100644
12 --- x/qttools/src/linguist/CMakeLists.txt
13 +++ y/qttools/src/linguist/CMakeLists.txt
14 @@ -14,9 +14,6 @@ add_subdirectory(lrelease)
15 add_subdirectory(lrelease-pro)
16 add_subdirectory(lupdate)
17 add_subdirectory(lupdate-pro)
18 -if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png)
19 - add_subdirectory(linguist)
20 -endif()
21
22 # special case begin
23 # Create a fake module that would emulate the Qt5::LinguistTools CMake Config package
24 --
25 2.38.1
26
+0
-3235
libs/patches/qt-tools-0002-Revert-Move-UiTools-and-UiPlugin-modules-to-a-upper-.patch less more
0 From d6c550d3ef01a50e100acd4fa44a2d6fbd376cbb Mon Sep 17 00:00:00 2001
1 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
2 Date: Wed, 9 Nov 2022 09:49:38 +0100
3 Subject: Revert "Move UiTools and UiPlugin modules to a upper level
4 sub-directory"
5
6 This partially reverts commit 6af882fa2f45f73ec2ba4066d5ae3ad072d0c5ee.
7
8 Change-Id: I247e2189577b74d813a210ace0b49d672a90975e
9 ---
10 src/CMakeLists.txt | 5 -
11 src/designer/src/CMakeLists.txt | 2 +
12 .../src/designer/doc/qtdesigner.qdocconf | 4 +-
13 src/designer/src/uiplugin/CMakeLists.txt | 27 +
14 src/designer/src/uiplugin/customwidget.h | 62 ++
15 src/designer/src/uiplugin/customwidget.qdoc | 269 ++++++
16 .../src/uiplugin/qdesignerexportwidget.h | 24 +
17 src/designer/src/uitools/CMakeLists.txt | 47 +
18 src/designer/src/uitools/qtuitoolsglobal.h | 24 +
19 src/designer/src/uitools/quiloader.cpp | 914 ++++++++++++++++++
20 src/designer/src/uitools/quiloader.h | 61 ++
21 src/designer/src/uitools/quiloader_p.h | 77 ++
22 src/uiplugin/CMakeLists.txt | 27 -
23 src/uiplugin/customwidget.h | 62 --
24 src/uiplugin/customwidget.qdoc | 269 ------
25 src/uiplugin/qdesignerexportwidget.h | 24 -
26 src/uitools/CMakeLists.txt | 47 -
27 src/uitools/qtuitoolsglobal.h | 24 -
28 src/uitools/quiloader.cpp | 914 ------------------
29 src/uitools/quiloader.h | 61 --
30 src/uitools/quiloader_p.h | 77 --
31 sync.profile | 4 +-
32 22 files changed, 1511 insertions(+), 1514 deletions(-)
33 create mode 100644 src/designer/src/uiplugin/CMakeLists.txt
34 create mode 100644 src/designer/src/uiplugin/customwidget.h
35 create mode 100644 src/designer/src/uiplugin/customwidget.qdoc
36 create mode 100644 src/designer/src/uiplugin/qdesignerexportwidget.h
37 create mode 100644 src/designer/src/uitools/CMakeLists.txt
38 create mode 100644 src/designer/src/uitools/qtuitoolsglobal.h
39 create mode 100644 src/designer/src/uitools/quiloader.cpp
40 create mode 100644 src/designer/src/uitools/quiloader.h
41 create mode 100644 src/designer/src/uitools/quiloader_p.h
42 delete mode 100644 src/uiplugin/CMakeLists.txt
43 delete mode 100644 src/uiplugin/customwidget.h
44 delete mode 100644 src/uiplugin/customwidget.qdoc
45 delete mode 100644 src/uiplugin/qdesignerexportwidget.h
46 delete mode 100644 src/uitools/CMakeLists.txt
47 delete mode 100644 src/uitools/qtuitoolsglobal.h
48 delete mode 100644 src/uitools/quiloader.cpp
49 delete mode 100644 src/uitools/quiloader.h
50 delete mode 100644 src/uitools/quiloader_p.h
51
52 diff --git x/qttools/src/CMakeLists.txt y/qttools/src/CMakeLists.txt
53 index b42cd4946..cb0c21a70 100644
54 --- x/qttools/src/CMakeLists.txt
55 +++ y/qttools/src/CMakeLists.txt
56 @@ -21,11 +21,6 @@ qt_exclude_tool_directories_from_default_target(
57 qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake")
58 # special case end
59
60 -if(TARGET Qt::Widgets)
61 - add_subdirectory(uiplugin)
62 - add_subdirectory(uitools)
63 -endif()
64 -
65 add_subdirectory(global) # special case add as first directory
66 if(QT_FEATURE_linguist)
67 add_subdirectory(linguist)
68 diff --git x/qttools/src/designer/src/CMakeLists.txt y/qttools/src/designer/src/CMakeLists.txt
69 index 31fc1734e..32fb45160 100644
70 --- x/qttools/src/designer/src/CMakeLists.txt
71 +++ y/qttools/src/designer/src/CMakeLists.txt
72 @@ -8,6 +8,8 @@ qt_exclude_tool_directories_from_default_target(
73 plugins
74 )
75
76 +add_subdirectory(uiplugin)
77 +add_subdirectory(uitools)
78 if(QT_FEATURE_process)
79 add_subdirectory(lib)
80 add_subdirectory(components)
81 diff --git x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf
82 index 75c8c78dd..964fb47ed 100644
83 --- x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf
84 +++ y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf
85 @@ -28,11 +28,11 @@ qhp.QtDesigner.subprojects.classes.sortPages = true
86 language = Cpp
87
88 headerdirs += .. \
89 - ../../../../uiplugin \
90 + ../../uiplugin \
91 ../../lib
92
93 sourcedirs = .. \
94 - ../../../../uiplugin \
95 + ../../uiplugin \
96 ../../lib
97
98 exampledirs = ../../../../../examples/designer \
99 diff --git x/qttools/src/designer/src/uiplugin/CMakeLists.txt y/qttools/src/designer/src/uiplugin/CMakeLists.txt
100 new file mode 100644
101 index 000000000..4fedf8e33
102 --- /dev/null
103 +++ y/qttools/src/designer/src/uiplugin/CMakeLists.txt
104 @@ -0,0 +1,27 @@
105 +# Generated from uiplugin.pro.
106 +
107 +#####################################################################
108 +## UiPlugin Module:
109 +#####################################################################
110 +
111 +qt_internal_add_module(UiPlugin
112 + NO_PRIVATE_MODULE
113 + HEADER_MODULE
114 + QMAKE_MODULE_CONFIG designer_defines
115 + PUBLIC_LIBRARIES
116 + Qt::Core
117 + Qt::Gui
118 + Qt::Widgets
119 +)
120 +
121 +# special case begin
122 +set(is_plugin "$<TARGET_PROPERTY:QT_PLUGIN_CLASS_NAME>")
123 +target_compile_definitions(
124 + UiPlugin
125 + INTERFACE
126 + $<$<BOOL:${is_plugin}>:QDESIGNER_EXPORT_WIDGETS>
127 +)
128 +# special case end
129 +
130 +#### Keys ignored in scope 1:.:.:uiplugin.pro:<TRUE>:
131 +# MODULE_CONFIG = "designer_defines"
132 diff --git x/qttools/src/designer/src/uiplugin/customwidget.h y/qttools/src/designer/src/uiplugin/customwidget.h
133 new file mode 100644
134 index 000000000..2a47a32f8
135 --- /dev/null
136 +++ y/qttools/src/designer/src/uiplugin/customwidget.h
137 @@ -0,0 +1,62 @@
138 +// Copyright (C) 2016 The Qt Company Ltd.
139 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
140 +
141 +#ifndef CUSTOMWIDGET_H
142 +#define CUSTOMWIDGET_H
143 +
144 +#include <QtCore/qobject.h>
145 +#include <QtCore/qstring.h>
146 +#include <QtGui/qicon.h>
147 +
148 +QT_BEGIN_NAMESPACE
149 +
150 +class QWidget;
151 +class QDesignerFormEditorInterface;
152 +
153 +class QDesignerCustomWidgetInterface
154 +{
155 +public:
156 + virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable
157 +
158 + virtual QString name() const = 0;
159 + virtual QString group() const = 0;
160 + virtual QString toolTip() const = 0;
161 + virtual QString whatsThis() const = 0;
162 + virtual QString includeFile() const = 0;
163 + virtual QIcon icon() const = 0;
164 +
165 + virtual bool isContainer() const = 0;
166 +
167 + virtual QWidget *createWidget(QWidget *parent) = 0;
168 +
169 + virtual bool isInitialized() const { return false; }
170 + virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); }
171 +
172 + virtual QString domXml() const
173 + {
174 + return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
175 + .arg(name()).arg(name().toLower());
176 + }
177 +
178 + virtual QString codeTemplate() const { return QString(); }
179 +};
180 +
181 +#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface"
182 +
183 +Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid)
184 +
185 +class QDesignerCustomWidgetCollectionInterface
186 +{
187 +public:
188 + virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable
189 +
190 + virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const = 0;
191 +};
192 +
193 +#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface"
194 +
195 +Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid)
196 +
197 +QT_END_NAMESPACE
198 +
199 +#endif // CUSTOMWIDGET_H
200 diff --git x/qttools/src/designer/src/uiplugin/customwidget.qdoc y/qttools/src/designer/src/uiplugin/customwidget.qdoc
201 new file mode 100644
202 index 000000000..557e9a454
203 --- /dev/null
204 +++ y/qttools/src/designer/src/uiplugin/customwidget.qdoc
205 @@ -0,0 +1,269 @@
206 +// Copyright (C) 2016 The Qt Company Ltd.
207 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
208 +
209 +/*!
210 + \class QDesignerCustomWidgetInterface
211 +
212 + \brief The QDesignerCustomWidgetInterface class enables Qt Designer
213 + to access and construct custom widgets.
214 +
215 + \inmodule QtDesigner
216 +
217 + QDesignerCustomWidgetInterface provides a custom widget with an
218 + interface. The class contains a set of functions that must be subclassed
219 + to return basic information about the widget, such as its class name and
220 + the name of its header file. Other functions must be implemented to
221 + initialize the plugin when it is loaded, and to construct instances of
222 + the custom widget for \QD to use.
223 +
224 + When implementing a custom widget you must subclass
225 + QDesignerCustomWidgetInterface to expose your widget to \QD. For
226 + example, this is the declaration for the plugin used in the
227 + \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that
228 + enables an analog clock custom widget to be used by \QD:
229 +
230 + \snippet customwidgetplugin/customwidgetplugin.h 0
231 +
232 + Note that the only part of the class definition that is specific
233 + to this particular custom widget is the class name. In addition,
234 + since we are implementing an interface, we must ensure that it's
235 + made known to the meta object system using the Q_INTERFACES()
236 + macro. This enables \QD to use the qobject_cast() function to
237 + query for supported interfaces using nothing but a QObject
238 + pointer.
239 +
240 + After \QD loads a custom widget plugin, it calls the interface's
241 + initialize() function to enable it to set up any resources that it
242 + may need. This function is called with a QDesignerFormEditorInterface
243 + parameter that provides the plugin with a gateway to all of \QD's API.
244 +
245 + \QD constructs instances of the custom widget by calling the plugin's
246 + createWidget() function with a suitable parent widget. Plugins must
247 + construct and return an instance of a custom widget with the specified
248 + parent widget.
249 +
250 + Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA()
251 + macro. For example, if a library called \c libcustomwidgetplugin.so
252 + (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget
253 + class called \c MyCustomWidget, we can export it by adding the
254 + following line to the file containing the plugin header:
255 +
256 + \snippet plugins/doc_src_qtdesigner.cpp 14
257 +
258 + This macro ensures that \QD can access and construct the custom widget.
259 + Without this macro, there is no way for \QD to use it.
260 +
261 + When implementing a custom widget plugin, you build it as a
262 + separate library. If you want to include several custom widget
263 + plugins in the same library, you must in addition subclass
264 + QDesignerCustomWidgetCollectionInterface.
265 +
266 + \warning If your custom widget plugin contains QVariant
267 + properties, be aware that only the following \l
268 + {QVariant::Type}{types} are supported:
269 +
270 + \list
271 + \li QVariant::ByteArray
272 + \li QVariant::Bool
273 + \li QVariant::Color
274 + \li QVariant::Cursor
275 + \li QVariant::Date
276 + \li QVariant::DateTime
277 + \li QVariant::Double
278 + \li QVariant::Int
279 + \li QVariant::Point
280 + \li QVariant::Rect
281 + \li QVariant::Size
282 + \li QVariant::SizePolicy
283 + \li QVariant::String
284 + \li QVariant::Time
285 + \li QVariant::UInt
286 + \endlist
287 +
288 + For a complete example using the QDesignerCustomWidgetInterface
289 + class, see the \l {customwidgetplugin}{Custom Widget
290 + Example}. The example shows how to create a custom widget plugin
291 + for \QD.
292 +
293 + \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer}
294 +*/
295 +
296 +/*!
297 + \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface()
298 +
299 + Destroys the custom widget interface.
300 +*/
301 +
302 +/*!
303 + \fn QString QDesignerCustomWidgetInterface::name() const
304 +
305 + Returns the class name of the custom widget supplied by the interface.
306 +
307 + The name returned \e must be identical to the class name used for the
308 + custom widget.
309 +*/
310 +
311 +/*!
312 + \fn QString QDesignerCustomWidgetInterface::group() const
313 +
314 + Returns the name of the group to which the custom widget belongs.
315 +*/
316 +
317 +/*!
318 + \fn QString QDesignerCustomWidgetInterface::toolTip() const
319 +
320 + Returns a short description of the widget that can be used by \QD
321 + in a tool tip.
322 +*/
323 +
324 +/*!
325 + \fn QString QDesignerCustomWidgetInterface::whatsThis() const
326 +
327 + Returns a description of the widget that can be used by \QD in
328 + "What's This?" help for the widget.
329 +*/
330 +
331 +/*!
332 + \fn QString QDesignerCustomWidgetInterface::includeFile() const
333 +
334 + Returns the path to the include file that \l uic uses when
335 + creating code for the custom widget.
336 +*/
337 +
338 +/*!
339 + \fn QIcon QDesignerCustomWidgetInterface::icon() const
340 +
341 + Returns the icon used to represent the custom widget in \QD's
342 + widget box.
343 +*/
344 +
345 +/*!
346 + \fn bool QDesignerCustomWidgetInterface::isContainer() const
347 +
348 + Returns true if the custom widget is intended to be used as a
349 + container; otherwise returns false.
350 +
351 + Most custom widgets are not used to hold other widgets, so their
352 + implementations of this function will return false, but custom
353 + containers will return true to ensure that they behave correctly
354 + in \QD.
355 +*/
356 +
357 +/*!
358 + \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent)
359 +
360 + Returns a new instance of the custom widget, with the given \a
361 + parent.
362 +*/
363 +
364 +/*!
365 + \fn bool QDesignerCustomWidgetInterface::isInitialized() const
366 +
367 + Returns true if the widget has been initialized; otherwise returns
368 + false.
369 +
370 + \sa initialize()
371 +*/
372 +
373 +/*!
374 + \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor)
375 +
376 + Initializes the widget for use with the specified \a formEditor
377 + interface.
378 +
379 + \sa isInitialized()
380 +*/
381 +
382 +/*!
383 + \fn QString QDesignerCustomWidgetInterface::domXml() const
384 +
385 + Returns the XML that is used to describe the custom widget's
386 + properties to \QD.
387 +*/
388 +
389 +/*!
390 + \fn QString QDesignerCustomWidgetInterface::codeTemplate() const
391 +
392 + This function is reserved for future use by \QD.
393 +
394 + \omit
395 + Returns the code template that \QD includes in forms that contain
396 + the custom widget when they are saved.
397 + \endomit
398 +*/
399 +
400 +/*!
401 + \macro QDESIGNER_WIDGET_EXPORT
402 + \relates QDesignerCustomWidgetInterface
403 + \since 4.1
404 +
405 + This macro is used when defining custom widgets to ensure that they are
406 + correctly exported from plugins for use with \QD.
407 +
408 + On some platforms, the symbols required by \QD to create new widgets
409 + are removed from plugins by the build system, making them unusable.
410 + Using this macro ensures that the symbols are retained on those platforms,
411 + and has no side effects on other platforms.
412 +
413 + For example, the \l{worldtimeclockplugin}{World Time Clock Plugin}
414 + example exports a custom widget class with the following declaration:
415 +
416 + \snippet worldtimeclockplugin/worldtimeclock.h 0
417 + \dots
418 + \snippet worldtimeclockplugin/worldtimeclock.h 2
419 +
420 + \sa {Creating Custom Widgets for Qt Designer}
421 +*/
422 +
423 +
424 +
425 +
426 +
427 +/*!
428 + \class QDesignerCustomWidgetCollectionInterface
429 +
430 + \brief The QDesignerCustomWidgetCollectionInterface class allows
431 + you to include several custom widgets in one single library.
432 +
433 + \inmodule QtDesigner
434 +
435 + When implementing a custom widget plugin, you build it as a
436 + separate library. If you want to include several custom widget
437 + plugins in the same library, you must in addition subclass
438 + QDesignerCustomWidgetCollectionInterface.
439 +
440 + QDesignerCustomWidgetCollectionInterface contains one single
441 + function returning a list of the collection's
442 + QDesignerCustomWidgetInterface objects. For example, if you have
443 + several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and
444 + \c CustomWidgetThree, the class definition may look like this:
445 +
446 + \snippet plugins/doc_src_qtdesigner.cpp 12
447 +
448 + In the class constructor you add the interfaces to your custom
449 + widgets to the list which you return in the customWidgets()
450 + function:
451 +
452 + \snippet plugins/doc_src_qtdesigner.cpp 13
453 +
454 + Note that instead of exporting each custom widget plugin using the
455 + Q_PLUGIN_METADATA() macro, you export the entire collection. The
456 + Q_PLUGIN_METADATA() macro ensures that \QD can access and construct
457 + the custom widgets. Without this macro, there is no way for \QD to
458 + use them.
459 +
460 + \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for
461 + Qt Designer}
462 +*/
463 +
464 +/*!
465 + \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() {
466 +
467 + Destroys the custom widget collection interface.
468 +*/
469 +
470 +/*!
471 + \fn QList<QDesignerCustomWidgetInterface*> QDesignerCustomWidgetCollectionInterface::customWidgets() const
472 +
473 + Returns a list of interfaces to the collection's custom widgets.
474 +*/
475 diff --git x/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h
476 new file mode 100644
477 index 000000000..d90e9b217
478 --- /dev/null
479 +++ y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h
480 @@ -0,0 +1,24 @@
481 +// Copyright (C) 2016 The Qt Company Ltd.
482 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
483 +
484 +#ifndef QDESIGNEREXPORTWIDGET_H
485 +#define QDESIGNEREXPORTWIDGET_H
486 +
487 +#include <QtCore/qglobal.h>
488 +
489 +QT_BEGIN_NAMESPACE
490 +
491 +#if 0
492 +// pragma for syncqt, don't remove.
493 +#pragma qt_class(QDesignerExportWidget)
494 +#endif
495 +
496 +#if defined(QDESIGNER_EXPORT_WIDGETS)
497 +# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT
498 +#else
499 +# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT
500 +#endif
501 +
502 +QT_END_NAMESPACE
503 +
504 +#endif //QDESIGNEREXPORTWIDGET_H
505 diff --git x/qttools/src/designer/src/uitools/CMakeLists.txt y/qttools/src/designer/src/uitools/CMakeLists.txt
506 new file mode 100644
507 index 000000000..5306fcbd5
508 --- /dev/null
509 +++ y/qttools/src/designer/src/uitools/CMakeLists.txt
510 @@ -0,0 +1,47 @@
511 +# Generated from uitools.pro.
512 +
513 +#####################################################################
514 +## UiTools Module:
515 +#####################################################################
516 +
517 +qt_internal_add_module(UiTools
518 + SOURCES
519 + ../lib/uilib/abstractformbuilder.cpp ../lib/uilib/abstractformbuilder.h
520 + ../lib/uilib/formbuilder.cpp ../lib/uilib/formbuilder.h
521 + ../lib/uilib/formbuilderextra.cpp ../lib/uilib/formbuilderextra_p.h
522 + ../lib/uilib/properties.cpp ../lib/uilib/properties_p.h
523 + ../lib/uilib/resourcebuilder.cpp ../lib/uilib/resourcebuilder_p.h
524 + ../lib/uilib/textbuilder.cpp ../lib/uilib/textbuilder_p.h
525 + ../lib/uilib/ui4.cpp ../lib/uilib/ui4_p.h
526 + quiloader.cpp quiloader.h
527 + DEFINES
528 + QFORMINTERNAL_NAMESPACE
529 + QT_DESIGNER
530 + QT_DESIGNER_STATIC
531 + QT_USE_QSTRINGBUILDER
532 + INCLUDE_DIRECTORIES
533 + ../lib/uilib
534 + LIBRARIES
535 + Qt::UiPlugin
536 + PUBLIC_LIBRARIES
537 + Qt::Core
538 + Qt::Gui
539 + Qt::Widgets
540 +)
541 +
542 +## Scopes:
543 +#####################################################################
544 +
545 +qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets
546 + PUBLIC_LIBRARIES
547 + Qt::OpenGLWidgets
548 +)
549 +
550 +qt_internal_extend_target(UiTools CONDITION QT_FEATURE_opengl
551 + LIBRARIES
552 + Qt::OpenGL
553 +)
554 +qt_internal_add_docs(UiTools
555 + doc/qtuitools.qdocconf
556 +)
557 +
558 diff --git x/qttools/src/designer/src/uitools/qtuitoolsglobal.h y/qttools/src/designer/src/uitools/qtuitoolsglobal.h
559 new file mode 100644
560 index 000000000..a2f967dee
561 --- /dev/null
562 +++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h
563 @@ -0,0 +1,24 @@
564 +// Copyright (C) 2020 The Qt Company Ltd.
565 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
566 +
567 +#ifndef QTUITOOLSGLOBAL_H
568 +#define QTUITOOLSGLOBAL_H
569 +
570 +#include <QtCore/qglobal.h>
571 +
572 +QT_BEGIN_NAMESPACE
573 +
574 +#ifndef QT_STATIC
575 +# if defined(QT_BUILD_UITOOLS_LIB)
576 +# define Q_UITOOLS_EXPORT Q_DECL_EXPORT
577 +# else
578 +# define Q_UITOOLS_EXPORT Q_DECL_IMPORT
579 +# endif
580 +#else
581 +# define Q_UITOOLS_EXPORT
582 +#endif
583 +
584 +QT_END_NAMESPACE
585 +
586 +#endif // QTUITOOLSGLOBAL_H
587 +
588 diff --git x/qttools/src/designer/src/uitools/quiloader.cpp y/qttools/src/designer/src/uitools/quiloader.cpp
589 new file mode 100644
590 index 000000000..a06d4717b
591 --- /dev/null
592 +++ y/qttools/src/designer/src/uitools/quiloader.cpp
593 @@ -0,0 +1,914 @@
594 +// Copyright (C) 2020 The Qt Company Ltd.
595 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
596 +
597 +
598 +#include "quiloader.h"
599 +#include "quiloader_p.h"
600 +
601 +#include <QtUiPlugin/customwidget.h>
602 +
603 +#include <formbuilder.h>
604 +#include <formbuilderextra_p.h>
605 +#include <textbuilder_p.h>
606 +#include <ui4_p.h>
607 +
608 +#include <QtWidgets/qapplication.h>
609 +#include <QtWidgets/qlayout.h>
610 +#include <QtWidgets/qwidget.h>
611 +#include <QtWidgets/qtabwidget.h>
612 +#include <QtWidgets/qtreewidget.h>
613 +#include <QtWidgets/qlistwidget.h>
614 +#include <QtWidgets/qtablewidget.h>
615 +#include <QtWidgets/qtoolbox.h>
616 +#include <QtWidgets/qcombobox.h>
617 +#include <QtWidgets/qfontcombobox.h>
618 +
619 +#include <QtGui/qaction.h>
620 +#include <QtGui/qactiongroup.h>
621 +
622 +#include <QtCore/qdebug.h>
623 +#include <QtCore/qdatastream.h>
624 +#include <QtCore/qmap.h>
625 +#include <QtCore/qdir.h>
626 +#include <QtCore/qlibraryinfo.h>
627 +
628 +QT_BEGIN_NAMESPACE
629 +
630 +typedef QMap<QString, bool> widget_map;
631 +Q_GLOBAL_STATIC(widget_map, g_widgets)
632 +
633 +class QUiLoader;
634 +class QUiLoaderPrivate;
635 +
636 +#ifndef QT_NO_DATASTREAM
637 +// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based
638 +// mime data when dragging items in views with QAbstractItemView::InternalMove.
639 +QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s)
640 +{
641 + out << s.qualifier() << s.value();
642 + return out;
643 +}
644 +
645 +QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s)
646 +{
647 + QByteArray qualifier, value;
648 + in >> qualifier >> value;
649 + s.setQualifier(qualifier);
650 + s.setValue(value);
651 + return in;
652 +}
653 +#endif // QT_NO_DATASTREAM
654 +
655 +QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const
656 +{
657 + return idBased
658 + ? qtTrId(m_qualifier.constData())
659 + : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData());
660 +}
661 +
662 +#ifdef QFORMINTERNAL_NAMESPACE
663 +namespace QFormInternal
664 +{
665 +#endif
666 +
667 +class TranslatingTextBuilder : public QTextBuilder
668 +{
669 +public:
670 + explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) :
671 + m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {}
672 +
673 + QVariant loadText(const DomProperty *icon) const override;
674 +
675 + QVariant toNativeValue(const QVariant &value) const override;
676 +
677 + bool idBased() const { return m_idBased; }
678 +
679 +private:
680 + bool m_idBased;
681 + bool m_trEnabled;
682 + QByteArray m_className;
683 +};
684 +
685 +QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const
686 +{
687 + const DomString *str = text->elementString();
688 + if (!str)
689 + return QVariant();
690 + if (str->hasAttributeNotr()) {
691 + const QString notr = str->attributeNotr();
692 + if (notr == QStringLiteral("true") || notr == QStringLiteral("yes"))
693 + return QVariant::fromValue(str->text());
694 + }
695 + QUiTranslatableStringValue strVal;
696 + strVal.setValue(str->text().toUtf8());
697 + if (m_idBased)
698 + strVal.setQualifier(str->attributeId().toUtf8());
699 + else if (str->hasAttributeComment())
700 + strVal.setQualifier(str->attributeComment().toUtf8());
701 + return QVariant::fromValue(strVal);
702 +}
703 +
704 +QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const
705 +{
706 + if (value.canConvert<QUiTranslatableStringValue>()) {
707 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(value);
708 + if (!m_trEnabled)
709 + return QString::fromUtf8(tsv.value().constData());
710 + return QVariant::fromValue(tsv.translate(m_className, m_idBased));
711 + }
712 + if (value.canConvert<QString>())
713 + return QVariant::fromValue(qvariant_cast<QString>(value));
714 + return value;
715 +}
716 +
717 +// This is "exported" to linguist
718 +const QUiItemRolePair qUiItemRoles[] = {
719 + { Qt::DisplayRole, Qt::DisplayPropertyRole },
720 +#if QT_CONFIG(tooltip)
721 + { Qt::ToolTipRole, Qt::ToolTipPropertyRole },
722 +#endif
723 +#if QT_CONFIG(statustip)
724 + { Qt::StatusTipRole, Qt::StatusTipPropertyRole },
725 +#endif
726 +#if QT_CONFIG(whatsthis)
727 + { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole },
728 +#endif
729 + { -1 , -1 }
730 +};
731 +
732 +static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased)
733 +{
734 + const QUiItemRolePair *irs = qUiItemRoles;
735 +
736 + int cnt = item->columnCount();
737 + for (int i = 0; i < cnt; ++i) {
738 + for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
739 + QVariant v = item->data(i, irs[j].shadowRole);
740 + if (v.isValid()) {
741 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
742 + item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased));
743 + }
744 + }
745 + }
746 +
747 + cnt = item->childCount();
748 + for (int i = 0; i < cnt; ++i)
749 + recursiveReTranslate(item->child(i), class_name, idBased);
750 +}
751 +
752 +template<typename T>
753 +static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
754 +{
755 + const QUiItemRolePair *irs = qUiItemRoles;
756 +
757 + for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
758 + QVariant v = item->data(irs[j].shadowRole);
759 + if (v.isValid()) {
760 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
761 + item->setData(irs[j].realRole, tsv.translate(class_name, idBased));
762 + }
763 + }
764 +}
765 +
766 +static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased)
767 +{
768 + if (item)
769 + reTranslateWidgetItem(item, class_name, idBased);
770 +}
771 +
772 +#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \
773 + do { \
774 + QVariant v = mainWidget->widget(i)->property(propName); \
775 + if (v.isValid()) { \
776 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v); \
777 + mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \
778 + } \
779 + } while (0)
780 +
781 +class TranslationWatcher: public QObject
782 +{
783 + Q_OBJECT
784 +
785 +public:
786 + explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased):
787 + QObject(parent),
788 + m_className(className),
789 + m_idBased(idBased)
790 + {
791 + }
792 +
793 + bool eventFilter(QObject *o, QEvent *event) override
794 + {
795 + if (event->type() == QEvent::LanguageChange) {
796 + const auto &dynamicPropertyNames = o->dynamicPropertyNames();
797 + for (const QByteArray &prop : dynamicPropertyNames) {
798 + if (prop.startsWith(PROP_GENERIC_PREFIX)) {
799 + const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
800 + const QUiTranslatableStringValue tsv =
801 + qvariant_cast<QUiTranslatableStringValue>(o->property(prop));
802 + o->setProperty(propName, tsv.translate(m_className, m_idBased));
803 + }
804 + }
805 + if (0) {
806 +#if QT_CONFIG(tabwidget)
807 + } else if (QTabWidget *tabw = qobject_cast<QTabWidget*>(o)) {
808 + const int cnt = tabw->count();
809 + for (int i = 0; i < cnt; ++i) {
810 + RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT);
811 +#if QT_CONFIG(tooltip)
812 + RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP);
813 +# endif
814 +#if QT_CONFIG(whatsthis)
815 + RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
816 +# endif
817 + }
818 +#endif
819 +#if QT_CONFIG(listwidget)
820 + } else if (QListWidget *listw = qobject_cast<QListWidget*>(o)) {
821 + const int cnt = listw->count();
822 + for (int i = 0; i < cnt; ++i)
823 + reTranslateWidgetItem(listw->item(i), m_className, m_idBased);
824 +#endif
825 +#if QT_CONFIG(treewidget)
826 + } else if (QTreeWidget *treew = qobject_cast<QTreeWidget*>(o)) {
827 + if (QTreeWidgetItem *item = treew->headerItem())
828 + recursiveReTranslate(item, m_className, m_idBased);
829 + const int cnt = treew->topLevelItemCount();
830 + for (int i = 0; i < cnt; ++i) {
831 + QTreeWidgetItem *item = treew->topLevelItem(i);
832 + recursiveReTranslate(item, m_className, m_idBased);
833 + }
834 +#endif
835 +#if QT_CONFIG(tablewidget)
836 + } else if (QTableWidget *tablew = qobject_cast<QTableWidget*>(o)) {
837 + const int row_cnt = tablew->rowCount();
838 + const int col_cnt = tablew->columnCount();
839 + for (int j = 0; j < col_cnt; ++j)
840 + reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased);
841 + for (int i = 0; i < row_cnt; ++i) {
842 + reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased);
843 + for (int j = 0; j < col_cnt; ++j)
844 + reTranslateTableItem(tablew->item(i, j), m_className, m_idBased);
845 + }
846 +#endif
847 +#if QT_CONFIG(combobox)
848 + } else if (QComboBox *combow = qobject_cast<QComboBox*>(o)) {
849 + if (!qobject_cast<QFontComboBox*>(o)) {
850 + const int cnt = combow->count();
851 + for (int i = 0; i < cnt; ++i) {
852 + const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole);
853 + if (v.isValid()) {
854 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
855 + combow->setItemText(i, tsv.translate(m_className, m_idBased));
856 + }
857 + }
858 + }
859 +#endif
860 +#if QT_CONFIG(toolbox)
861 + } else if (QToolBox *toolw = qobject_cast<QToolBox*>(o)) {
862 + const int cnt = toolw->count();
863 + for (int i = 0; i < cnt; ++i) {
864 + RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT);
865 +#if QT_CONFIG(tooltip)
866 + RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP);
867 +# endif
868 + }
869 +#endif
870 + }
871 + }
872 + return false;
873 + }
874 +
875 +private:
876 + QByteArray m_className;
877 + bool m_idBased;
878 +};
879 +
880 +class FormBuilderPrivate: public QFormBuilder
881 +{
882 + friend class QT_PREPEND_NAMESPACE(QUiLoader);
883 + friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate);
884 + using ParentClass = QFormBuilder;
885 +
886 +public:
887 + QUiLoader *loader = nullptr;
888 +
889 + bool dynamicTr = false;
890 + bool trEnabled = true;
891 +
892 + FormBuilderPrivate() = default;
893 +
894 + QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
895 + {
896 + return ParentClass::createWidget(className, parent, name);
897 + }
898 +
899 + QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
900 + {
901 + return ParentClass::createLayout(className, parent, name);
902 + }
903 +
904 + QAction *defaultCreateAction(QObject *parent, const QString &name)
905 + {
906 + return ParentClass::createAction(parent, name);
907 + }
908 +
909 + QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name)
910 + {
911 + return ParentClass::createActionGroup(parent, name);
912 + }
913 +
914 + QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override
915 + {
916 + if (QWidget *widget = loader->createWidget(className, parent, name)) {
917 + widget->setObjectName(name);
918 + return widget;
919 + }
920 +
921 + return nullptr;
922 + }
923 +
924 + QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override
925 + {
926 + if (QLayout *layout = loader->createLayout(className, parent, name)) {
927 + layout->setObjectName(name);
928 + return layout;
929 + }
930 +
931 + return nullptr;
932 + }
933 +
934 + QActionGroup *createActionGroup(QObject *parent, const QString &name) override
935 + {
936 + if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) {
937 + actionGroup->setObjectName(name);
938 + return actionGroup;
939 + }
940 +
941 + return nullptr;
942 + }
943 +
944 + QAction *createAction(QObject *parent, const QString &name) override
945 + {
946 + if (QAction *action = loader->createAction(parent, name)) {
947 + action->setObjectName(name);
948 + return action;
949 + }
950 +
951 + return nullptr;
952 + }
953 +
954 + void applyProperties(QObject *o, const QList<DomProperty*> &properties) override;
955 + QWidget *create(DomUI *ui, QWidget *parentWidget) override;
956 + QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override;
957 + bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override;
958 +
959 +private:
960 + QByteArray m_class;
961 + TranslationWatcher *m_trwatch = nullptr;
962 + bool m_idBased = false;
963 +};
964 +
965 +static QString convertTranslatable(const DomProperty *p, const QByteArray &className,
966 + bool idBased, QUiTranslatableStringValue *strVal)
967 +{
968 + if (p->kind() != DomProperty::String)
969 + return QString();
970 + const DomString *dom_str = p->elementString();
971 + if (!dom_str)
972 + return QString();
973 + if (dom_str->hasAttributeNotr()) {
974 + const QString notr = dom_str->attributeNotr();
975 + if (notr == QStringLiteral("yes") || notr == QStringLiteral("true"))
976 + return QString();
977 + }
978 + strVal->setValue(dom_str->text().toUtf8());
979 + strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8());
980 + if (strVal->value().isEmpty() && strVal->qualifier().isEmpty())
981 + return QString();
982 + return strVal->translate(className, idBased);
983 +}
984 +
985 +void FormBuilderPrivate::applyProperties(QObject *o, const QList<DomProperty*> &properties)
986 +{
987 + QFormBuilder::applyProperties(o, properties);
988 +
989 + if (!m_trwatch)
990 + m_trwatch = new TranslationWatcher(o, m_class, m_idBased);
991 +
992 + if (properties.isEmpty())
993 + return;
994 +
995 + // Unlike string item roles, string properties are not loaded via the textBuilder
996 + // (as they are "shadowed" by the property sheets in designer). So do the initial
997 + // translation here.
998 + bool anyTrs = false;
999 + for (const DomProperty *p : properties) {
1000 + QUiTranslatableStringValue strVal;
1001 + const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
1002 + if (text.isEmpty())
1003 + continue;
1004 + const QByteArray name = p->attributeName().toUtf8();
1005 + if (dynamicTr) {
1006 + const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
1007 + o->setProperty(dynname, QVariant::fromValue(strVal));
1008 + anyTrs = trEnabled;
1009 + }
1010 + if (p->elementString()->text() != text)
1011 + o->setProperty(name, text);
1012 + }
1013 + if (anyTrs)
1014 + o->installEventFilter(m_trwatch);
1015 +}
1016 +
1017 +QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget)
1018 +{
1019 + m_class = ui->elementClass().toUtf8();
1020 + m_trwatch = nullptr;
1021 + m_idBased = ui->attributeIdbasedtr();
1022 + setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class));
1023 + return QFormBuilder::create(ui, parentWidget);
1024 +}
1025 +
1026 +QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget)
1027 +{
1028 + QWidget *w = QFormBuilder::create(ui_widget, parentWidget);
1029 + if (w == nullptr)
1030 + return nullptr;
1031 +
1032 + if (0) {
1033 +#if QT_CONFIG(tabwidget)
1034 + } else if (qobject_cast<QTabWidget*>(w)) {
1035 +#endif
1036 +#if QT_CONFIG(listwidget)
1037 + } else if (qobject_cast<QListWidget*>(w)) {
1038 +#endif
1039 +#if QT_CONFIG(treewidget)
1040 + } else if (qobject_cast<QTreeWidget*>(w)) {
1041 +#endif
1042 +#if QT_CONFIG(tablewidget)
1043 + } else if (qobject_cast<QTableWidget*>(w)) {
1044 +#endif
1045 +#if QT_CONFIG(combobox)
1046 + } else if (qobject_cast<QComboBox*>(w)) {
1047 + if (qobject_cast<QFontComboBox*>(w))
1048 + return w;
1049 +#endif
1050 +#if QT_CONFIG(toolbox)
1051 + } else if (qobject_cast<QToolBox*>(w)) {
1052 +#endif
1053 + } else {
1054 + return w;
1055 + }
1056 + if (dynamicTr && trEnabled)
1057 + w->installEventFilter(m_trwatch);
1058 + return w;
1059 +}
1060 +
1061 +#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \
1062 + do { \
1063 + if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \
1064 + QUiTranslatableStringValue strVal; \
1065 + const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \
1066 + if (!text.isEmpty()) { \
1067 + if (dynamicTr) \
1068 + mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \
1069 + mainWidget->setter(i, text); \
1070 + } \
1071 + } \
1072 + } while (0)
1073 +
1074 +bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
1075 +{
1076 + if (parentWidget == nullptr)
1077 + return true;
1078 +
1079 + if (!ParentClass::addItem(ui_widget, widget, parentWidget))
1080 + return false;
1081 +
1082 + // Check special cases. First: Custom container
1083 + const QString className = QLatin1String(parentWidget->metaObject()->className());
1084 + if (!d->customWidgetAddPageMethod(className).isEmpty())
1085 + return true;
1086 +
1087 + const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1088 +
1089 + if (0) {
1090 +#if QT_CONFIG(tabwidget)
1091 + } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
1092 + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
1093 + const int i = tabWidget->count() - 1;
1094 + TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT);
1095 +#if QT_CONFIG(tooltip)
1096 + TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP);
1097 +# endif
1098 +#if QT_CONFIG(whatsthis)
1099 + TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
1100 +# endif
1101 +#endif
1102 +#if QT_CONFIG(toolbox)
1103 + } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
1104 + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
1105 + const int i = toolBox->count() - 1;
1106 + TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT);
1107 +#if QT_CONFIG(tooltip)
1108 + TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP);
1109 +# endif
1110 +#endif
1111 + }
1112 +
1113 + return true;
1114 +}
1115 +
1116 +#ifdef QFORMINTERNAL_NAMESPACE
1117 +}
1118 +#endif
1119 +
1120 +class QUiLoaderPrivate
1121 +{
1122 +public:
1123 +#ifdef QFORMINTERNAL_NAMESPACE
1124 + QFormInternal::FormBuilderPrivate builder;
1125 +#else
1126 + FormBuilderPrivate builder;
1127 +#endif
1128 +
1129 + void setupWidgetMap() const;
1130 +};
1131 +
1132 +void QUiLoaderPrivate::setupWidgetMap() const
1133 +{
1134 + if (!g_widgets()->isEmpty())
1135 + return;
1136 +
1137 +#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true);
1138 +#define DECLARE_LAYOUT(a, b)
1139 +
1140 +#include "widgets.table"
1141 +
1142 +#undef DECLARE_WIDGET
1143 +#undef DECLARE_WIDGET_1
1144 +#undef DECLARE_LAYOUT
1145 +}
1146 +
1147 +/*!
1148 + \class QUiLoader
1149 + \inmodule QtUiTools
1150 +
1151 + \brief The QUiLoader class enables standalone applications to
1152 + dynamically create user interfaces at run-time using the
1153 + information stored in UI files or specified in plugin paths.
1154 +
1155 + In addition, you can customize or create your own user interface by
1156 + deriving your own loader class.
1157 +
1158 + If you have a custom component or an application that embeds \QD, you can
1159 + also use the QFormBuilder class provided by the QtDesigner module to create
1160 + user interfaces from UI files.
1161 +
1162 + The QUiLoader class provides a collection of functions allowing you to
1163 + create widgets based on the information stored in UI files (created
1164 + with \QD) or available in the specified plugin paths. The specified plugin
1165 + paths can be retrieved using the pluginPaths() function. Similarly, the
1166 + contents of a UI file can be retrieved using the load() function. For
1167 + example:
1168 +
1169 + \snippet quiloader/mywidget.cpp 0
1170 +
1171 + \if !defined(qtforpython)
1172 + By including the user interface in the form's resources (\c myform.qrc), we
1173 + ensure that it will be present at run-time:
1174 +
1175 + \quotefile quiloader/mywidget.qrc
1176 + \endif
1177 +
1178 + The availableWidgets() function returns a QStringList with the class names
1179 + of the widgets available in the specified plugin paths. To create these
1180 + widgets, simply use the createWidget() function. For example:
1181 +
1182 + \snippet quiloader/main.cpp 0
1183 +
1184 + To make a custom widget available to the loader, you can use the
1185 + addPluginPath() function; to remove all available widgets, you can call
1186 + the clearPluginPaths() function.
1187 +
1188 + The createAction(), createActionGroup(), createLayout(), and createWidget()
1189 + functions are used internally by the QUiLoader class whenever it has to
1190 + create an action, action group, layout, or widget respectively. For that
1191 + reason, you can subclass the QUiLoader class and reimplement these
1192 + functions to intervene the process of constructing a user interface. For
1193 + example, you might want to have a list of the actions created when loading
1194 + a form or creating a custom widget.
1195 +
1196 + For a complete example using the QUiLoader class, see the
1197 + \l{Calculator Builder Example}.
1198 +
1199 + \sa {Qt UI Tools}, QFormBuilder
1200 +*/
1201 +
1202 +/*!
1203 + Creates a form loader with the given \a parent.
1204 +*/
1205 +QUiLoader::QUiLoader(QObject *parent)
1206 + : QObject(parent), d_ptr(new QUiLoaderPrivate)
1207 +{
1208 + Q_D(QUiLoader);
1209 +
1210 +#ifndef QT_NO_DATASTREAM
1211 + static int metaTypeId = 0;
1212 + if (!metaTypeId) {
1213 + metaTypeId = qRegisterMetaType<QUiTranslatableStringValue>("QUiTranslatableStringValue");
1214 + }
1215 +#endif // QT_NO_DATASTREAM
1216 + d->builder.loader = this;
1217 +
1218 +#if QT_CONFIG(library)
1219 + QStringList paths;
1220 + const QStringList &libraryPaths = QApplication::libraryPaths();
1221 + for (const QString &path : libraryPaths) {
1222 + QString libPath = path;
1223 + libPath += QDir::separator();
1224 + libPath += QStringLiteral("designer");
1225 + paths.append(libPath);
1226 + }
1227 +
1228 + d->builder.setPluginPath(paths);
1229 +#endif // QT_CONFIG(library)
1230 +}
1231 +
1232 +/*!
1233 + Destroys the loader.
1234 +*/
1235 +QUiLoader::~QUiLoader() = default;
1236 +
1237 +/*!
1238 + Loads a form from the given \a device and creates a new widget with the
1239 + given \a parentWidget to hold its contents.
1240 +
1241 + \sa createWidget(), errorString()
1242 +*/
1243 +QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
1244 +{
1245 + Q_D(QUiLoader);
1246 + // QXmlStreamReader will report errors on open failure.
1247 + if (!device->isOpen())
1248 + device->open(QIODevice::ReadOnly|QIODevice::Text);
1249 + return d->builder.load(device, parentWidget);
1250 +}
1251 +
1252 +/*!
1253 + Returns a list naming the paths in which the loader will search when
1254 + locating custom widget plugins.
1255 +
1256 + \sa addPluginPath(), clearPluginPaths()
1257 +*/
1258 +QStringList QUiLoader::pluginPaths() const
1259 +{
1260 + Q_D(const QUiLoader);
1261 + return d->builder.pluginPaths();
1262 +}
1263 +
1264 +/*!
1265 + Clears the list of paths in which the loader will search when locating
1266 + plugins.
1267 +
1268 + \sa addPluginPath(), pluginPaths()
1269 +*/
1270 +void QUiLoader::clearPluginPaths()
1271 +{
1272 + Q_D(QUiLoader);
1273 + d->builder.clearPluginPaths();
1274 +}
1275 +
1276 +/*!
1277 + Adds the given \a path to the list of paths in which the loader will search
1278 + when locating plugins.
1279 +
1280 + \sa pluginPaths(), clearPluginPaths()
1281 +*/
1282 +void QUiLoader::addPluginPath(const QString &path)
1283 +{
1284 + Q_D(QUiLoader);
1285 + d->builder.addPluginPath(path);
1286 +}
1287 +
1288 +/*!
1289 + Creates a new widget with the given \a parent and \a name using the class
1290 + specified by \a className. You can use this function to create any of the
1291 + widgets returned by the availableWidgets() function.
1292 +
1293 + The function is also used internally by the QUiLoader class whenever it
1294 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1295 + function to intervene process of constructing a user interface or widget.
1296 + However, in your implementation, ensure that you call QUiLoader's version
1297 + first.
1298 +
1299 + \sa availableWidgets(), load()
1300 +*/
1301 +QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
1302 +{
1303 + Q_D(QUiLoader);
1304 + return d->builder.defaultCreateWidget(className, parent, name);
1305 +}
1306 +
1307 +/*!
1308 + Creates a new layout with the given \a parent and \a name using the class
1309 + specified by \a className.
1310 +
1311 + The function is also used internally by the QUiLoader class whenever it
1312 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1313 + function to intervene process of constructing a user interface or widget.
1314 + However, in your implementation, ensure that you call QUiLoader's version
1315 + first.
1316 +
1317 + \sa createWidget(), load()
1318 +*/
1319 +QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
1320 +{
1321 + Q_D(QUiLoader);
1322 + return d->builder.defaultCreateLayout(className, parent, name);
1323 +}
1324 +
1325 +/*!
1326 + Creates a new action group with the given \a parent and \a name.
1327 +
1328 + The function is also used internally by the QUiLoader class whenever it
1329 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1330 + function to intervene process of constructing a user interface or widget.
1331 + However, in your implementation, ensure that you call QUiLoader's version
1332 + first.
1333 +
1334 + \sa createAction(), createWidget(), load()
1335 + */
1336 +QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
1337 +{
1338 + Q_D(QUiLoader);
1339 + return d->builder.defaultCreateActionGroup(parent, name);
1340 +}
1341 +
1342 +/*!
1343 + Creates a new action with the given \a parent and \a name.
1344 +
1345 + The function is also used internally by the QUiLoader class whenever it
1346 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1347 + function to intervene process of constructing a user interface or widget.
1348 + However, in your implementation, ensure that you call QUiLoader's version
1349 + first.
1350 +
1351 + \sa createActionGroup(), createWidget(), load()
1352 +*/
1353 +QAction *QUiLoader::createAction(QObject *parent, const QString &name)
1354 +{
1355 + Q_D(QUiLoader);
1356 + return d->builder.defaultCreateAction(parent, name);
1357 +}
1358 +
1359 +/*!
1360 + Returns a list naming all available widgets that can be built using the
1361 + createWidget() function, i.e all the widgets specified within the given
1362 + plugin paths.
1363 +
1364 + \sa pluginPaths(), createWidget()
1365 +
1366 +*/
1367 +QStringList QUiLoader::availableWidgets() const
1368 +{
1369 + Q_D(const QUiLoader);
1370 +
1371 + d->setupWidgetMap();
1372 + widget_map available = *g_widgets();
1373 +
1374 + const auto &customWidgets = d->builder.customWidgets();
1375 + for (QDesignerCustomWidgetInterface *plugin : customWidgets)
1376 + available.insert(plugin->name(), true);
1377 +
1378 + return available.keys();
1379 +}
1380 +
1381 +
1382 +/*!
1383 + \since 4.5
1384 + Returns a list naming all available layouts that can be built using the
1385 + createLayout() function
1386 +
1387 + \sa createLayout()
1388 +*/
1389 +
1390 +QStringList QUiLoader::availableLayouts() const
1391 +{
1392 + QStringList rc;
1393 +#define DECLARE_WIDGET(a, b)
1394 +#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a));
1395 +
1396 +#include "widgets.table"
1397 +
1398 +#undef DECLARE_WIDGET
1399 +#undef DECLARE_LAYOUT
1400 + return rc;
1401 +}
1402 +
1403 +/*!
1404 + Sets the working directory of the loader to \a dir. The loader will look
1405 + for other resources, such as icons and resource files, in paths relative to
1406 + this directory.
1407 +
1408 + \sa workingDirectory()
1409 +*/
1410 +
1411 +void QUiLoader::setWorkingDirectory(const QDir &dir)
1412 +{
1413 + Q_D(QUiLoader);
1414 + d->builder.setWorkingDirectory(dir);
1415 +}
1416 +
1417 +/*!
1418 + Returns the working directory of the loader.
1419 +
1420 + \sa setWorkingDirectory()
1421 +*/
1422 +
1423 +QDir QUiLoader::workingDirectory() const
1424 +{
1425 + Q_D(const QUiLoader);
1426 + return d->builder.workingDirectory();
1427 +}
1428 +/*!
1429 + \since 4.5
1430 +
1431 + If \a enabled is true, user interfaces loaded by this loader will
1432 + automatically retranslate themselves upon receiving a language change
1433 + event. Otherwise, the user interfaces will not be retranslated.
1434 +
1435 + \sa isLanguageChangeEnabled()
1436 +*/
1437 +
1438 +void QUiLoader::setLanguageChangeEnabled(bool enabled)
1439 +{
1440 + Q_D(QUiLoader);
1441 + d->builder.dynamicTr = enabled;
1442 +}
1443 +
1444 +/*!
1445 + \since 4.5
1446 +
1447 + Returns true if dynamic retranslation on language change is enabled;
1448 + returns false otherwise.
1449 +
1450 + \sa setLanguageChangeEnabled()
1451 +*/
1452 +
1453 +bool QUiLoader::isLanguageChangeEnabled() const
1454 +{
1455 + Q_D(const QUiLoader);
1456 + return d->builder.dynamicTr;
1457 +}
1458 +
1459 +/*!
1460 + \internal
1461 + \since 4.5
1462 +
1463 + If \a enabled is true, user interfaces loaded by this loader will be
1464 + translated. Otherwise, the user interfaces will not be translated.
1465 +
1466 + \note This is orthogonal to languageChangeEnabled.
1467 +
1468 + \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
1469 +*/
1470 +
1471 +void QUiLoader::setTranslationEnabled(bool enabled)
1472 +{
1473 + Q_D(QUiLoader);
1474 + d->builder.trEnabled = enabled;
1475 +}
1476 +
1477 +/*!
1478 + \internal
1479 + \since 4.5
1480 +
1481 + Returns true if translation is enabled; returns false otherwise.
1482 +
1483 + \sa setTranslationEnabled()
1484 +*/
1485 +
1486 +bool QUiLoader::isTranslationEnabled() const
1487 +{
1488 + Q_D(const QUiLoader);
1489 + return d->builder.trEnabled;
1490 +}
1491 +
1492 +/*!
1493 + Returns a human-readable description of the last error occurred in load().
1494 +
1495 + \since 5.0
1496 + \sa load()
1497 +*/
1498 +
1499 +QString QUiLoader::errorString() const
1500 +{
1501 + Q_D(const QUiLoader);
1502 + return d->builder.errorString();
1503 +}
1504 +
1505 +QT_END_NAMESPACE
1506 +
1507 +#include "quiloader.moc"
1508 diff --git x/qttools/src/designer/src/uitools/quiloader.h y/qttools/src/designer/src/uitools/quiloader.h
1509 new file mode 100644
1510 index 000000000..742b5606f
1511 --- /dev/null
1512 +++ y/qttools/src/designer/src/uitools/quiloader.h
1513 @@ -0,0 +1,61 @@
1514 +// Copyright (C) 2020 The Qt Company Ltd.
1515 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
1516 +
1517 +#ifndef QUILOADER_H
1518 +#define QUILOADER_H
1519 +
1520 +#include <QtUiTools/qtuitoolsglobal.h>
1521 +#include <QtCore/qobject.h>
1522 +#include <QtCore/qscopedpointer.h>
1523 +
1524 +QT_BEGIN_NAMESPACE
1525 +
1526 +class QWidget;
1527 +class QLayout;
1528 +class QAction;
1529 +class QActionGroup;
1530 +class QString;
1531 +class QIODevice;
1532 +class QDir;
1533 +
1534 +class QUiLoaderPrivate;
1535 +class Q_UITOOLS_EXPORT QUiLoader : public QObject
1536 +{
1537 + Q_OBJECT
1538 +public:
1539 + explicit QUiLoader(QObject *parent = nullptr);
1540 + ~QUiLoader() override;
1541 +
1542 + QStringList pluginPaths() const;
1543 + void clearPluginPaths();
1544 + void addPluginPath(const QString &path);
1545 +
1546 + QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr);
1547 + QStringList availableWidgets() const;
1548 + QStringList availableLayouts() const;
1549 +
1550 + virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString());
1551 + virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString());
1552 + virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString());
1553 + virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString());
1554 +
1555 + void setWorkingDirectory(const QDir &dir);
1556 + QDir workingDirectory() const;
1557 +
1558 + void setLanguageChangeEnabled(bool enabled);
1559 + bool isLanguageChangeEnabled() const;
1560 +
1561 + void setTranslationEnabled(bool enabled);
1562 + bool isTranslationEnabled() const;
1563 +
1564 + QString errorString() const;
1565 +
1566 +private:
1567 + QScopedPointer<QUiLoaderPrivate> d_ptr;
1568 + Q_DECLARE_PRIVATE(QUiLoader)
1569 + Q_DISABLE_COPY_MOVE(QUiLoader)
1570 +};
1571 +
1572 +QT_END_NAMESPACE
1573 +
1574 +#endif // QUILOADER_H
1575 diff --git x/qttools/src/designer/src/uitools/quiloader_p.h y/qttools/src/designer/src/uitools/quiloader_p.h
1576 new file mode 100644
1577 index 000000000..efd943217
1578 --- /dev/null
1579 +++ y/qttools/src/designer/src/uitools/quiloader_p.h
1580 @@ -0,0 +1,77 @@
1581 +// Copyright (C) 2020 The Qt Company Ltd.
1582 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
1583 +
1584 +#ifndef QUILOADER_P_H
1585 +#define QUILOADER_P_H
1586 +
1587 +//
1588 +// W A R N I N G
1589 +// -------------
1590 +//
1591 +// This file is not part of the Qt API. It exists purely as an
1592 +// implementation detail. This header file may change from version to
1593 +// version without notice, or even be removed.
1594 +//
1595 +// We mean it.
1596 +//
1597 +
1598 +#include <QtUiTools/qtuitoolsglobal.h>
1599 +#include <QtCore/qbytearray.h>
1600 +#include <QtCore/qmetatype.h>
1601 +
1602 +QT_FORWARD_DECLARE_CLASS(QDataStream)
1603 +
1604 +// This file is here for use by the form preview in Linguist. If you change anything
1605 +// here or in the code which uses it, remember to adapt Linguist accordingly.
1606 +
1607 +#define PROP_GENERIC_PREFIX "_q_notr_"
1608 +#define PROP_TOOLITEMTEXT "_q_toolItemText_notr"
1609 +#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr"
1610 +#define PROP_TABPAGETEXT "_q_tabPageText_notr"
1611 +#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr"
1612 +#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr"
1613 +
1614 +QT_BEGIN_NAMESPACE
1615 +
1616 +class Q_UITOOLS_EXPORT QUiTranslatableStringValue
1617 +{
1618 +public:
1619 + QByteArray value() const { return m_value; }
1620 + void setValue(const QByteArray &value) { m_value = value; }
1621 + QByteArray qualifier() const { return m_qualifier; }
1622 + void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; }
1623 +
1624 + QString translate(const QByteArray &className, bool idBased) const;
1625 +
1626 +private:
1627 + QByteArray m_value;
1628 + QByteArray m_qualifier; // Comment or ID for id-based tr().
1629 +};
1630 +
1631 +#ifndef QT_NO_DATASTREAM
1632 +Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s);
1633 +Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s);
1634 +#endif // QT_NO_DATASTREAM
1635 +
1636 +struct QUiItemRolePair {
1637 + int realRole;
1638 + int shadowRole;
1639 +};
1640 +
1641 +#ifdef QFORMINTERNAL_NAMESPACE
1642 +namespace QFormInternal
1643 +{
1644 +#endif
1645 +
1646 +extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[];
1647 +
1648 +#ifdef QFORMINTERNAL_NAMESPACE
1649 +}
1650 +#endif
1651 +
1652 +QT_END_NAMESPACE
1653 +
1654 +Q_DECLARE_METATYPE(QUiTranslatableStringValue)
1655 +
1656 +
1657 +#endif // QUILOADER_P_H
1658 diff --git x/qttools/src/uiplugin/CMakeLists.txt y/qttools/src/uiplugin/CMakeLists.txt
1659 deleted file mode 100644
1660 index 4fedf8e33..000000000
1661 --- x/qttools/src/uiplugin/CMakeLists.txt
1662 +++ /dev/null
1663 @@ -1,27 +0,0 @@
1664 -# Generated from uiplugin.pro.
1665 -
1666 -#####################################################################
1667 -## UiPlugin Module:
1668 -#####################################################################
1669 -
1670 -qt_internal_add_module(UiPlugin
1671 - NO_PRIVATE_MODULE
1672 - HEADER_MODULE
1673 - QMAKE_MODULE_CONFIG designer_defines
1674 - PUBLIC_LIBRARIES
1675 - Qt::Core
1676 - Qt::Gui
1677 - Qt::Widgets
1678 -)
1679 -
1680 -# special case begin
1681 -set(is_plugin "$<TARGET_PROPERTY:QT_PLUGIN_CLASS_NAME>")
1682 -target_compile_definitions(
1683 - UiPlugin
1684 - INTERFACE
1685 - $<$<BOOL:${is_plugin}>:QDESIGNER_EXPORT_WIDGETS>
1686 -)
1687 -# special case end
1688 -
1689 -#### Keys ignored in scope 1:.:.:uiplugin.pro:<TRUE>:
1690 -# MODULE_CONFIG = "designer_defines"
1691 diff --git x/qttools/src/uiplugin/customwidget.h y/qttools/src/uiplugin/customwidget.h
1692 deleted file mode 100644
1693 index 2a47a32f8..000000000
1694 --- x/qttools/src/uiplugin/customwidget.h
1695 +++ /dev/null
1696 @@ -1,62 +0,0 @@
1697 -// Copyright (C) 2016 The Qt Company Ltd.
1698 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
1699 -
1700 -#ifndef CUSTOMWIDGET_H
1701 -#define CUSTOMWIDGET_H
1702 -
1703 -#include <QtCore/qobject.h>
1704 -#include <QtCore/qstring.h>
1705 -#include <QtGui/qicon.h>
1706 -
1707 -QT_BEGIN_NAMESPACE
1708 -
1709 -class QWidget;
1710 -class QDesignerFormEditorInterface;
1711 -
1712 -class QDesignerCustomWidgetInterface
1713 -{
1714 -public:
1715 - virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable
1716 -
1717 - virtual QString name() const = 0;
1718 - virtual QString group() const = 0;
1719 - virtual QString toolTip() const = 0;
1720 - virtual QString whatsThis() const = 0;
1721 - virtual QString includeFile() const = 0;
1722 - virtual QIcon icon() const = 0;
1723 -
1724 - virtual bool isContainer() const = 0;
1725 -
1726 - virtual QWidget *createWidget(QWidget *parent) = 0;
1727 -
1728 - virtual bool isInitialized() const { return false; }
1729 - virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); }
1730 -
1731 - virtual QString domXml() const
1732 - {
1733 - return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
1734 - .arg(name()).arg(name().toLower());
1735 - }
1736 -
1737 - virtual QString codeTemplate() const { return QString(); }
1738 -};
1739 -
1740 -#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface"
1741 -
1742 -Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid)
1743 -
1744 -class QDesignerCustomWidgetCollectionInterface
1745 -{
1746 -public:
1747 - virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable
1748 -
1749 - virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const = 0;
1750 -};
1751 -
1752 -#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface"
1753 -
1754 -Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid)
1755 -
1756 -QT_END_NAMESPACE
1757 -
1758 -#endif // CUSTOMWIDGET_H
1759 diff --git x/qttools/src/uiplugin/customwidget.qdoc y/qttools/src/uiplugin/customwidget.qdoc
1760 deleted file mode 100644
1761 index 557e9a454..000000000
1762 --- x/qttools/src/uiplugin/customwidget.qdoc
1763 +++ /dev/null
1764 @@ -1,269 +0,0 @@
1765 -// Copyright (C) 2016 The Qt Company Ltd.
1766 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
1767 -
1768 -/*!
1769 - \class QDesignerCustomWidgetInterface
1770 -
1771 - \brief The QDesignerCustomWidgetInterface class enables Qt Designer
1772 - to access and construct custom widgets.
1773 -
1774 - \inmodule QtDesigner
1775 -
1776 - QDesignerCustomWidgetInterface provides a custom widget with an
1777 - interface. The class contains a set of functions that must be subclassed
1778 - to return basic information about the widget, such as its class name and
1779 - the name of its header file. Other functions must be implemented to
1780 - initialize the plugin when it is loaded, and to construct instances of
1781 - the custom widget for \QD to use.
1782 -
1783 - When implementing a custom widget you must subclass
1784 - QDesignerCustomWidgetInterface to expose your widget to \QD. For
1785 - example, this is the declaration for the plugin used in the
1786 - \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that
1787 - enables an analog clock custom widget to be used by \QD:
1788 -
1789 - \snippet customwidgetplugin/customwidgetplugin.h 0
1790 -
1791 - Note that the only part of the class definition that is specific
1792 - to this particular custom widget is the class name. In addition,
1793 - since we are implementing an interface, we must ensure that it's
1794 - made known to the meta object system using the Q_INTERFACES()
1795 - macro. This enables \QD to use the qobject_cast() function to
1796 - query for supported interfaces using nothing but a QObject
1797 - pointer.
1798 -
1799 - After \QD loads a custom widget plugin, it calls the interface's
1800 - initialize() function to enable it to set up any resources that it
1801 - may need. This function is called with a QDesignerFormEditorInterface
1802 - parameter that provides the plugin with a gateway to all of \QD's API.
1803 -
1804 - \QD constructs instances of the custom widget by calling the plugin's
1805 - createWidget() function with a suitable parent widget. Plugins must
1806 - construct and return an instance of a custom widget with the specified
1807 - parent widget.
1808 -
1809 - Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA()
1810 - macro. For example, if a library called \c libcustomwidgetplugin.so
1811 - (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget
1812 - class called \c MyCustomWidget, we can export it by adding the
1813 - following line to the file containing the plugin header:
1814 -
1815 - \snippet plugins/doc_src_qtdesigner.cpp 14
1816 -
1817 - This macro ensures that \QD can access and construct the custom widget.
1818 - Without this macro, there is no way for \QD to use it.
1819 -
1820 - When implementing a custom widget plugin, you build it as a
1821 - separate library. If you want to include several custom widget
1822 - plugins in the same library, you must in addition subclass
1823 - QDesignerCustomWidgetCollectionInterface.
1824 -
1825 - \warning If your custom widget plugin contains QVariant
1826 - properties, be aware that only the following \l
1827 - {QVariant::Type}{types} are supported:
1828 -
1829 - \list
1830 - \li QVariant::ByteArray
1831 - \li QVariant::Bool
1832 - \li QVariant::Color
1833 - \li QVariant::Cursor
1834 - \li QVariant::Date
1835 - \li QVariant::DateTime
1836 - \li QVariant::Double
1837 - \li QVariant::Int
1838 - \li QVariant::Point
1839 - \li QVariant::Rect
1840 - \li QVariant::Size
1841 - \li QVariant::SizePolicy
1842 - \li QVariant::String
1843 - \li QVariant::Time
1844 - \li QVariant::UInt
1845 - \endlist
1846 -
1847 - For a complete example using the QDesignerCustomWidgetInterface
1848 - class, see the \l {customwidgetplugin}{Custom Widget
1849 - Example}. The example shows how to create a custom widget plugin
1850 - for \QD.
1851 -
1852 - \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer}
1853 -*/
1854 -
1855 -/*!
1856 - \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface()
1857 -
1858 - Destroys the custom widget interface.
1859 -*/
1860 -
1861 -/*!
1862 - \fn QString QDesignerCustomWidgetInterface::name() const
1863 -
1864 - Returns the class name of the custom widget supplied by the interface.
1865 -
1866 - The name returned \e must be identical to the class name used for the
1867 - custom widget.
1868 -*/
1869 -
1870 -/*!
1871 - \fn QString QDesignerCustomWidgetInterface::group() const
1872 -
1873 - Returns the name of the group to which the custom widget belongs.
1874 -*/
1875 -
1876 -/*!
1877 - \fn QString QDesignerCustomWidgetInterface::toolTip() const
1878 -
1879 - Returns a short description of the widget that can be used by \QD
1880 - in a tool tip.
1881 -*/
1882 -
1883 -/*!
1884 - \fn QString QDesignerCustomWidgetInterface::whatsThis() const
1885 -
1886 - Returns a description of the widget that can be used by \QD in
1887 - "What's This?" help for the widget.
1888 -*/
1889 -
1890 -/*!
1891 - \fn QString QDesignerCustomWidgetInterface::includeFile() const
1892 -
1893 - Returns the path to the include file that \l uic uses when
1894 - creating code for the custom widget.
1895 -*/
1896 -
1897 -/*!
1898 - \fn QIcon QDesignerCustomWidgetInterface::icon() const
1899 -
1900 - Returns the icon used to represent the custom widget in \QD's
1901 - widget box.
1902 -*/
1903 -
1904 -/*!
1905 - \fn bool QDesignerCustomWidgetInterface::isContainer() const
1906 -
1907 - Returns true if the custom widget is intended to be used as a
1908 - container; otherwise returns false.
1909 -
1910 - Most custom widgets are not used to hold other widgets, so their
1911 - implementations of this function will return false, but custom
1912 - containers will return true to ensure that they behave correctly
1913 - in \QD.
1914 -*/
1915 -
1916 -/*!
1917 - \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent)
1918 -
1919 - Returns a new instance of the custom widget, with the given \a
1920 - parent.
1921 -*/
1922 -
1923 -/*!
1924 - \fn bool QDesignerCustomWidgetInterface::isInitialized() const
1925 -
1926 - Returns true if the widget has been initialized; otherwise returns
1927 - false.
1928 -
1929 - \sa initialize()
1930 -*/
1931 -
1932 -/*!
1933 - \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor)
1934 -
1935 - Initializes the widget for use with the specified \a formEditor
1936 - interface.
1937 -
1938 - \sa isInitialized()
1939 -*/
1940 -
1941 -/*!
1942 - \fn QString QDesignerCustomWidgetInterface::domXml() const
1943 -
1944 - Returns the XML that is used to describe the custom widget's
1945 - properties to \QD.
1946 -*/
1947 -
1948 -/*!
1949 - \fn QString QDesignerCustomWidgetInterface::codeTemplate() const
1950 -
1951 - This function is reserved for future use by \QD.
1952 -
1953 - \omit
1954 - Returns the code template that \QD includes in forms that contain
1955 - the custom widget when they are saved.
1956 - \endomit
1957 -*/
1958 -
1959 -/*!
1960 - \macro QDESIGNER_WIDGET_EXPORT
1961 - \relates QDesignerCustomWidgetInterface
1962 - \since 4.1
1963 -
1964 - This macro is used when defining custom widgets to ensure that they are
1965 - correctly exported from plugins for use with \QD.
1966 -
1967 - On some platforms, the symbols required by \QD to create new widgets
1968 - are removed from plugins by the build system, making them unusable.
1969 - Using this macro ensures that the symbols are retained on those platforms,
1970 - and has no side effects on other platforms.
1971 -
1972 - For example, the \l{worldtimeclockplugin}{World Time Clock Plugin}
1973 - example exports a custom widget class with the following declaration:
1974 -
1975 - \snippet worldtimeclockplugin/worldtimeclock.h 0
1976 - \dots
1977 - \snippet worldtimeclockplugin/worldtimeclock.h 2
1978 -
1979 - \sa {Creating Custom Widgets for Qt Designer}
1980 -*/
1981 -
1982 -
1983 -
1984 -
1985 -
1986 -/*!
1987 - \class QDesignerCustomWidgetCollectionInterface
1988 -
1989 - \brief The QDesignerCustomWidgetCollectionInterface class allows
1990 - you to include several custom widgets in one single library.
1991 -
1992 - \inmodule QtDesigner
1993 -
1994 - When implementing a custom widget plugin, you build it as a
1995 - separate library. If you want to include several custom widget
1996 - plugins in the same library, you must in addition subclass
1997 - QDesignerCustomWidgetCollectionInterface.
1998 -
1999 - QDesignerCustomWidgetCollectionInterface contains one single
2000 - function returning a list of the collection's
2001 - QDesignerCustomWidgetInterface objects. For example, if you have
2002 - several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and
2003 - \c CustomWidgetThree, the class definition may look like this:
2004 -
2005 - \snippet plugins/doc_src_qtdesigner.cpp 12
2006 -
2007 - In the class constructor you add the interfaces to your custom
2008 - widgets to the list which you return in the customWidgets()
2009 - function:
2010 -
2011 - \snippet plugins/doc_src_qtdesigner.cpp 13
2012 -
2013 - Note that instead of exporting each custom widget plugin using the
2014 - Q_PLUGIN_METADATA() macro, you export the entire collection. The
2015 - Q_PLUGIN_METADATA() macro ensures that \QD can access and construct
2016 - the custom widgets. Without this macro, there is no way for \QD to
2017 - use them.
2018 -
2019 - \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for
2020 - Qt Designer}
2021 -*/
2022 -
2023 -/*!
2024 - \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() {
2025 -
2026 - Destroys the custom widget collection interface.
2027 -*/
2028 -
2029 -/*!
2030 - \fn QList<QDesignerCustomWidgetInterface*> QDesignerCustomWidgetCollectionInterface::customWidgets() const
2031 -
2032 - Returns a list of interfaces to the collection's custom widgets.
2033 -*/
2034 diff --git x/qttools/src/uiplugin/qdesignerexportwidget.h y/qttools/src/uiplugin/qdesignerexportwidget.h
2035 deleted file mode 100644
2036 index d90e9b217..000000000
2037 --- x/qttools/src/uiplugin/qdesignerexportwidget.h
2038 +++ /dev/null
2039 @@ -1,24 +0,0 @@
2040 -// Copyright (C) 2016 The Qt Company Ltd.
2041 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
2042 -
2043 -#ifndef QDESIGNEREXPORTWIDGET_H
2044 -#define QDESIGNEREXPORTWIDGET_H
2045 -
2046 -#include <QtCore/qglobal.h>
2047 -
2048 -QT_BEGIN_NAMESPACE
2049 -
2050 -#if 0
2051 -// pragma for syncqt, don't remove.
2052 -#pragma qt_class(QDesignerExportWidget)
2053 -#endif
2054 -
2055 -#if defined(QDESIGNER_EXPORT_WIDGETS)
2056 -# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT
2057 -#else
2058 -# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT
2059 -#endif
2060 -
2061 -QT_END_NAMESPACE
2062 -
2063 -#endif //QDESIGNEREXPORTWIDGET_H
2064 diff --git x/qttools/src/uitools/CMakeLists.txt y/qttools/src/uitools/CMakeLists.txt
2065 deleted file mode 100644
2066 index 448bd1840..000000000
2067 --- x/qttools/src/uitools/CMakeLists.txt
2068 +++ /dev/null
2069 @@ -1,47 +0,0 @@
2070 -# Generated from uitools.pro.
2071 -
2072 -#####################################################################
2073 -## UiTools Module:
2074 -#####################################################################
2075 -
2076 -qt_internal_add_module(UiTools
2077 - SOURCES
2078 - ../designer/src/lib/uilib/abstractformbuilder.cpp ../designer/src/lib/uilib/abstractformbuilder.h
2079 - ../designer/src/lib/uilib/formbuilder.cpp ../designer/src/lib/uilib/formbuilder.h
2080 - ../designer/src/lib/uilib/formbuilderextra.cpp ../designer/src/lib/uilib/formbuilderextra_p.h
2081 - ../designer/src/lib/uilib/properties.cpp ../designer/src/lib/uilib/properties_p.h
2082 - ../designer/src/lib/uilib/resourcebuilder.cpp ../designer/src/lib/uilib/resourcebuilder_p.h
2083 - ../designer/src/lib/uilib/textbuilder.cpp ../designer/src/lib/uilib/textbuilder_p.h
2084 - ../designer/src/lib/uilib/ui4.cpp ../designer/src/lib/uilib/ui4_p.h
2085 - quiloader.cpp quiloader.h
2086 - DEFINES
2087 - QFORMINTERNAL_NAMESPACE
2088 - QT_DESIGNER
2089 - QT_DESIGNER_STATIC
2090 - QT_USE_QSTRINGBUILDER
2091 - INCLUDE_DIRECTORIES
2092 - ../designer/src/lib/uilib
2093 - LIBRARIES
2094 - Qt::UiPlugin
2095 - PUBLIC_LIBRARIES
2096 - Qt::Core
2097 - Qt::Gui
2098 - Qt::Widgets
2099 -)
2100 -
2101 -## Scopes:
2102 -#####################################################################
2103 -
2104 -qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets
2105 - PUBLIC_LIBRARIES
2106 - Qt::OpenGLWidgets
2107 -)
2108 -
2109 -qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGL
2110 - LIBRARIES
2111 - Qt::OpenGL
2112 -)
2113 -qt_internal_add_docs(UiTools
2114 - doc/qtuitools.qdocconf
2115 -)
2116 -
2117 diff --git x/qttools/src/uitools/qtuitoolsglobal.h y/qttools/src/uitools/qtuitoolsglobal.h
2118 deleted file mode 100644
2119 index a2f967dee..000000000
2120 --- x/qttools/src/uitools/qtuitoolsglobal.h
2121 +++ /dev/null
2122 @@ -1,24 +0,0 @@
2123 -// Copyright (C) 2020 The Qt Company Ltd.
2124 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
2125 -
2126 -#ifndef QTUITOOLSGLOBAL_H
2127 -#define QTUITOOLSGLOBAL_H
2128 -
2129 -#include <QtCore/qglobal.h>
2130 -
2131 -QT_BEGIN_NAMESPACE
2132 -
2133 -#ifndef QT_STATIC
2134 -# if defined(QT_BUILD_UITOOLS_LIB)
2135 -# define Q_UITOOLS_EXPORT Q_DECL_EXPORT
2136 -# else
2137 -# define Q_UITOOLS_EXPORT Q_DECL_IMPORT
2138 -# endif
2139 -#else
2140 -# define Q_UITOOLS_EXPORT
2141 -#endif
2142 -
2143 -QT_END_NAMESPACE
2144 -
2145 -#endif // QTUITOOLSGLOBAL_H
2146 -
2147 diff --git x/qttools/src/uitools/quiloader.cpp y/qttools/src/uitools/quiloader.cpp
2148 deleted file mode 100644
2149 index a06d4717b..000000000
2150 --- x/qttools/src/uitools/quiloader.cpp
2151 +++ /dev/null
2152 @@ -1,914 +0,0 @@
2153 -// Copyright (C) 2020 The Qt Company Ltd.
2154 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
2155 -
2156 -
2157 -#include "quiloader.h"
2158 -#include "quiloader_p.h"
2159 -
2160 -#include <QtUiPlugin/customwidget.h>
2161 -
2162 -#include <formbuilder.h>
2163 -#include <formbuilderextra_p.h>
2164 -#include <textbuilder_p.h>
2165 -#include <ui4_p.h>
2166 -
2167 -#include <QtWidgets/qapplication.h>
2168 -#include <QtWidgets/qlayout.h>
2169 -#include <QtWidgets/qwidget.h>
2170 -#include <QtWidgets/qtabwidget.h>
2171 -#include <QtWidgets/qtreewidget.h>
2172 -#include <QtWidgets/qlistwidget.h>
2173 -#include <QtWidgets/qtablewidget.h>
2174 -#include <QtWidgets/qtoolbox.h>
2175 -#include <QtWidgets/qcombobox.h>
2176 -#include <QtWidgets/qfontcombobox.h>
2177 -
2178 -#include <QtGui/qaction.h>
2179 -#include <QtGui/qactiongroup.h>
2180 -
2181 -#include <QtCore/qdebug.h>
2182 -#include <QtCore/qdatastream.h>
2183 -#include <QtCore/qmap.h>
2184 -#include <QtCore/qdir.h>
2185 -#include <QtCore/qlibraryinfo.h>
2186 -
2187 -QT_BEGIN_NAMESPACE
2188 -
2189 -typedef QMap<QString, bool> widget_map;
2190 -Q_GLOBAL_STATIC(widget_map, g_widgets)
2191 -
2192 -class QUiLoader;
2193 -class QUiLoaderPrivate;
2194 -
2195 -#ifndef QT_NO_DATASTREAM
2196 -// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based
2197 -// mime data when dragging items in views with QAbstractItemView::InternalMove.
2198 -QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s)
2199 -{
2200 - out << s.qualifier() << s.value();
2201 - return out;
2202 -}
2203 -
2204 -QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s)
2205 -{
2206 - QByteArray qualifier, value;
2207 - in >> qualifier >> value;
2208 - s.setQualifier(qualifier);
2209 - s.setValue(value);
2210 - return in;
2211 -}
2212 -#endif // QT_NO_DATASTREAM
2213 -
2214 -QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const
2215 -{
2216 - return idBased
2217 - ? qtTrId(m_qualifier.constData())
2218 - : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData());
2219 -}
2220 -
2221 -#ifdef QFORMINTERNAL_NAMESPACE
2222 -namespace QFormInternal
2223 -{
2224 -#endif
2225 -
2226 -class TranslatingTextBuilder : public QTextBuilder
2227 -{
2228 -public:
2229 - explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) :
2230 - m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {}
2231 -
2232 - QVariant loadText(const DomProperty *icon) const override;
2233 -
2234 - QVariant toNativeValue(const QVariant &value) const override;
2235 -
2236 - bool idBased() const { return m_idBased; }
2237 -
2238 -private:
2239 - bool m_idBased;
2240 - bool m_trEnabled;
2241 - QByteArray m_className;
2242 -};
2243 -
2244 -QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const
2245 -{
2246 - const DomString *str = text->elementString();
2247 - if (!str)
2248 - return QVariant();
2249 - if (str->hasAttributeNotr()) {
2250 - const QString notr = str->attributeNotr();
2251 - if (notr == QStringLiteral("true") || notr == QStringLiteral("yes"))
2252 - return QVariant::fromValue(str->text());
2253 - }
2254 - QUiTranslatableStringValue strVal;
2255 - strVal.setValue(str->text().toUtf8());
2256 - if (m_idBased)
2257 - strVal.setQualifier(str->attributeId().toUtf8());
2258 - else if (str->hasAttributeComment())
2259 - strVal.setQualifier(str->attributeComment().toUtf8());
2260 - return QVariant::fromValue(strVal);
2261 -}
2262 -
2263 -QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const
2264 -{
2265 - if (value.canConvert<QUiTranslatableStringValue>()) {
2266 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(value);
2267 - if (!m_trEnabled)
2268 - return QString::fromUtf8(tsv.value().constData());
2269 - return QVariant::fromValue(tsv.translate(m_className, m_idBased));
2270 - }
2271 - if (value.canConvert<QString>())
2272 - return QVariant::fromValue(qvariant_cast<QString>(value));
2273 - return value;
2274 -}
2275 -
2276 -// This is "exported" to linguist
2277 -const QUiItemRolePair qUiItemRoles[] = {
2278 - { Qt::DisplayRole, Qt::DisplayPropertyRole },
2279 -#if QT_CONFIG(tooltip)
2280 - { Qt::ToolTipRole, Qt::ToolTipPropertyRole },
2281 -#endif
2282 -#if QT_CONFIG(statustip)
2283 - { Qt::StatusTipRole, Qt::StatusTipPropertyRole },
2284 -#endif
2285 -#if QT_CONFIG(whatsthis)
2286 - { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole },
2287 -#endif
2288 - { -1 , -1 }
2289 -};
2290 -
2291 -static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased)
2292 -{
2293 - const QUiItemRolePair *irs = qUiItemRoles;
2294 -
2295 - int cnt = item->columnCount();
2296 - for (int i = 0; i < cnt; ++i) {
2297 - for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
2298 - QVariant v = item->data(i, irs[j].shadowRole);
2299 - if (v.isValid()) {
2300 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
2301 - item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased));
2302 - }
2303 - }
2304 - }
2305 -
2306 - cnt = item->childCount();
2307 - for (int i = 0; i < cnt; ++i)
2308 - recursiveReTranslate(item->child(i), class_name, idBased);
2309 -}
2310 -
2311 -template<typename T>
2312 -static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
2313 -{
2314 - const QUiItemRolePair *irs = qUiItemRoles;
2315 -
2316 - for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
2317 - QVariant v = item->data(irs[j].shadowRole);
2318 - if (v.isValid()) {
2319 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
2320 - item->setData(irs[j].realRole, tsv.translate(class_name, idBased));
2321 - }
2322 - }
2323 -}
2324 -
2325 -static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased)
2326 -{
2327 - if (item)
2328 - reTranslateWidgetItem(item, class_name, idBased);
2329 -}
2330 -
2331 -#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \
2332 - do { \
2333 - QVariant v = mainWidget->widget(i)->property(propName); \
2334 - if (v.isValid()) { \
2335 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v); \
2336 - mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \
2337 - } \
2338 - } while (0)
2339 -
2340 -class TranslationWatcher: public QObject
2341 -{
2342 - Q_OBJECT
2343 -
2344 -public:
2345 - explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased):
2346 - QObject(parent),
2347 - m_className(className),
2348 - m_idBased(idBased)
2349 - {
2350 - }
2351 -
2352 - bool eventFilter(QObject *o, QEvent *event) override
2353 - {
2354 - if (event->type() == QEvent::LanguageChange) {
2355 - const auto &dynamicPropertyNames = o->dynamicPropertyNames();
2356 - for (const QByteArray &prop : dynamicPropertyNames) {
2357 - if (prop.startsWith(PROP_GENERIC_PREFIX)) {
2358 - const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
2359 - const QUiTranslatableStringValue tsv =
2360 - qvariant_cast<QUiTranslatableStringValue>(o->property(prop));
2361 - o->setProperty(propName, tsv.translate(m_className, m_idBased));
2362 - }
2363 - }
2364 - if (0) {
2365 -#if QT_CONFIG(tabwidget)
2366 - } else if (QTabWidget *tabw = qobject_cast<QTabWidget*>(o)) {
2367 - const int cnt = tabw->count();
2368 - for (int i = 0; i < cnt; ++i) {
2369 - RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT);
2370 -#if QT_CONFIG(tooltip)
2371 - RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP);
2372 -# endif
2373 -#if QT_CONFIG(whatsthis)
2374 - RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
2375 -# endif
2376 - }
2377 -#endif
2378 -#if QT_CONFIG(listwidget)
2379 - } else if (QListWidget *listw = qobject_cast<QListWidget*>(o)) {
2380 - const int cnt = listw->count();
2381 - for (int i = 0; i < cnt; ++i)
2382 - reTranslateWidgetItem(listw->item(i), m_className, m_idBased);
2383 -#endif
2384 -#if QT_CONFIG(treewidget)
2385 - } else if (QTreeWidget *treew = qobject_cast<QTreeWidget*>(o)) {
2386 - if (QTreeWidgetItem *item = treew->headerItem())
2387 - recursiveReTranslate(item, m_className, m_idBased);
2388 - const int cnt = treew->topLevelItemCount();
2389 - for (int i = 0; i < cnt; ++i) {
2390 - QTreeWidgetItem *item = treew->topLevelItem(i);
2391 - recursiveReTranslate(item, m_className, m_idBased);
2392 - }
2393 -#endif
2394 -#if QT_CONFIG(tablewidget)
2395 - } else if (QTableWidget *tablew = qobject_cast<QTableWidget*>(o)) {
2396 - const int row_cnt = tablew->rowCount();
2397 - const int col_cnt = tablew->columnCount();
2398 - for (int j = 0; j < col_cnt; ++j)
2399 - reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased);
2400 - for (int i = 0; i < row_cnt; ++i) {
2401 - reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased);
2402 - for (int j = 0; j < col_cnt; ++j)
2403 - reTranslateTableItem(tablew->item(i, j), m_className, m_idBased);
2404 - }
2405 -#endif
2406 -#if QT_CONFIG(combobox)
2407 - } else if (QComboBox *combow = qobject_cast<QComboBox*>(o)) {
2408 - if (!qobject_cast<QFontComboBox*>(o)) {
2409 - const int cnt = combow->count();
2410 - for (int i = 0; i < cnt; ++i) {
2411 - const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole);
2412 - if (v.isValid()) {
2413 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
2414 - combow->setItemText(i, tsv.translate(m_className, m_idBased));
2415 - }
2416 - }
2417 - }
2418 -#endif
2419 -#if QT_CONFIG(toolbox)
2420 - } else if (QToolBox *toolw = qobject_cast<QToolBox*>(o)) {
2421 - const int cnt = toolw->count();
2422 - for (int i = 0; i < cnt; ++i) {
2423 - RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT);
2424 -#if QT_CONFIG(tooltip)
2425 - RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP);
2426 -# endif
2427 - }
2428 -#endif
2429 - }
2430 - }
2431 - return false;
2432 - }
2433 -
2434 -private:
2435 - QByteArray m_className;
2436 - bool m_idBased;
2437 -};
2438 -
2439 -class FormBuilderPrivate: public QFormBuilder
2440 -{
2441 - friend class QT_PREPEND_NAMESPACE(QUiLoader);
2442 - friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate);
2443 - using ParentClass = QFormBuilder;
2444 -
2445 -public:
2446 - QUiLoader *loader = nullptr;
2447 -
2448 - bool dynamicTr = false;
2449 - bool trEnabled = true;
2450 -
2451 - FormBuilderPrivate() = default;
2452 -
2453 - QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
2454 - {
2455 - return ParentClass::createWidget(className, parent, name);
2456 - }
2457 -
2458 - QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
2459 - {
2460 - return ParentClass::createLayout(className, parent, name);
2461 - }
2462 -
2463 - QAction *defaultCreateAction(QObject *parent, const QString &name)
2464 - {
2465 - return ParentClass::createAction(parent, name);
2466 - }
2467 -
2468 - QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name)
2469 - {
2470 - return ParentClass::createActionGroup(parent, name);
2471 - }
2472 -
2473 - QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override
2474 - {
2475 - if (QWidget *widget = loader->createWidget(className, parent, name)) {
2476 - widget->setObjectName(name);
2477 - return widget;
2478 - }
2479 -
2480 - return nullptr;
2481 - }
2482 -
2483 - QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override
2484 - {
2485 - if (QLayout *layout = loader->createLayout(className, parent, name)) {
2486 - layout->setObjectName(name);
2487 - return layout;
2488 - }
2489 -
2490 - return nullptr;
2491 - }
2492 -
2493 - QActionGroup *createActionGroup(QObject *parent, const QString &name) override
2494 - {
2495 - if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) {
2496 - actionGroup->setObjectName(name);
2497 - return actionGroup;
2498 - }
2499 -
2500 - return nullptr;
2501 - }
2502 -
2503 - QAction *createAction(QObject *parent, const QString &name) override
2504 - {
2505 - if (QAction *action = loader->createAction(parent, name)) {
2506 - action->setObjectName(name);
2507 - return action;
2508 - }
2509 -
2510 - return nullptr;
2511 - }
2512 -
2513 - void applyProperties(QObject *o, const QList<DomProperty*> &properties) override;
2514 - QWidget *create(DomUI *ui, QWidget *parentWidget) override;
2515 - QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override;
2516 - bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override;
2517 -
2518 -private:
2519 - QByteArray m_class;
2520 - TranslationWatcher *m_trwatch = nullptr;
2521 - bool m_idBased = false;
2522 -};
2523 -
2524 -static QString convertTranslatable(const DomProperty *p, const QByteArray &className,
2525 - bool idBased, QUiTranslatableStringValue *strVal)
2526 -{
2527 - if (p->kind() != DomProperty::String)
2528 - return QString();
2529 - const DomString *dom_str = p->elementString();
2530 - if (!dom_str)
2531 - return QString();
2532 - if (dom_str->hasAttributeNotr()) {
2533 - const QString notr = dom_str->attributeNotr();
2534 - if (notr == QStringLiteral("yes") || notr == QStringLiteral("true"))
2535 - return QString();
2536 - }
2537 - strVal->setValue(dom_str->text().toUtf8());
2538 - strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8());
2539 - if (strVal->value().isEmpty() && strVal->qualifier().isEmpty())
2540 - return QString();
2541 - return strVal->translate(className, idBased);
2542 -}
2543 -
2544 -void FormBuilderPrivate::applyProperties(QObject *o, const QList<DomProperty*> &properties)
2545 -{
2546 - QFormBuilder::applyProperties(o, properties);
2547 -
2548 - if (!m_trwatch)
2549 - m_trwatch = new TranslationWatcher(o, m_class, m_idBased);
2550 -
2551 - if (properties.isEmpty())
2552 - return;
2553 -
2554 - // Unlike string item roles, string properties are not loaded via the textBuilder
2555 - // (as they are "shadowed" by the property sheets in designer). So do the initial
2556 - // translation here.
2557 - bool anyTrs = false;
2558 - for (const DomProperty *p : properties) {
2559 - QUiTranslatableStringValue strVal;
2560 - const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
2561 - if (text.isEmpty())
2562 - continue;
2563 - const QByteArray name = p->attributeName().toUtf8();
2564 - if (dynamicTr) {
2565 - const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
2566 - o->setProperty(dynname, QVariant::fromValue(strVal));
2567 - anyTrs = trEnabled;
2568 - }
2569 - if (p->elementString()->text() != text)
2570 - o->setProperty(name, text);
2571 - }
2572 - if (anyTrs)
2573 - o->installEventFilter(m_trwatch);
2574 -}
2575 -
2576 -QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget)
2577 -{
2578 - m_class = ui->elementClass().toUtf8();
2579 - m_trwatch = nullptr;
2580 - m_idBased = ui->attributeIdbasedtr();
2581 - setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class));
2582 - return QFormBuilder::create(ui, parentWidget);
2583 -}
2584 -
2585 -QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget)
2586 -{
2587 - QWidget *w = QFormBuilder::create(ui_widget, parentWidget);
2588 - if (w == nullptr)
2589 - return nullptr;
2590 -
2591 - if (0) {
2592 -#if QT_CONFIG(tabwidget)
2593 - } else if (qobject_cast<QTabWidget*>(w)) {
2594 -#endif
2595 -#if QT_CONFIG(listwidget)
2596 - } else if (qobject_cast<QListWidget*>(w)) {
2597 -#endif
2598 -#if QT_CONFIG(treewidget)
2599 - } else if (qobject_cast<QTreeWidget*>(w)) {
2600 -#endif
2601 -#if QT_CONFIG(tablewidget)
2602 - } else if (qobject_cast<QTableWidget*>(w)) {
2603 -#endif
2604 -#if QT_CONFIG(combobox)
2605 - } else if (qobject_cast<QComboBox*>(w)) {
2606 - if (qobject_cast<QFontComboBox*>(w))
2607 - return w;
2608 -#endif
2609 -#if QT_CONFIG(toolbox)
2610 - } else if (qobject_cast<QToolBox*>(w)) {
2611 -#endif
2612 - } else {
2613 - return w;
2614 - }
2615 - if (dynamicTr && trEnabled)
2616 - w->installEventFilter(m_trwatch);
2617 - return w;
2618 -}
2619 -
2620 -#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \
2621 - do { \
2622 - if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \
2623 - QUiTranslatableStringValue strVal; \
2624 - const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \
2625 - if (!text.isEmpty()) { \
2626 - if (dynamicTr) \
2627 - mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \
2628 - mainWidget->setter(i, text); \
2629 - } \
2630 - } \
2631 - } while (0)
2632 -
2633 -bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
2634 -{
2635 - if (parentWidget == nullptr)
2636 - return true;
2637 -
2638 - if (!ParentClass::addItem(ui_widget, widget, parentWidget))
2639 - return false;
2640 -
2641 - // Check special cases. First: Custom container
2642 - const QString className = QLatin1String(parentWidget->metaObject()->className());
2643 - if (!d->customWidgetAddPageMethod(className).isEmpty())
2644 - return true;
2645 -
2646 - const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2647 -
2648 - if (0) {
2649 -#if QT_CONFIG(tabwidget)
2650 - } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
2651 - const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
2652 - const int i = tabWidget->count() - 1;
2653 - TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT);
2654 -#if QT_CONFIG(tooltip)
2655 - TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP);
2656 -# endif
2657 -#if QT_CONFIG(whatsthis)
2658 - TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
2659 -# endif
2660 -#endif
2661 -#if QT_CONFIG(toolbox)
2662 - } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
2663 - const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
2664 - const int i = toolBox->count() - 1;
2665 - TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT);
2666 -#if QT_CONFIG(tooltip)
2667 - TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP);
2668 -# endif
2669 -#endif
2670 - }
2671 -
2672 - return true;
2673 -}
2674 -
2675 -#ifdef QFORMINTERNAL_NAMESPACE
2676 -}
2677 -#endif
2678 -
2679 -class QUiLoaderPrivate
2680 -{
2681 -public:
2682 -#ifdef QFORMINTERNAL_NAMESPACE
2683 - QFormInternal::FormBuilderPrivate builder;
2684 -#else
2685 - FormBuilderPrivate builder;
2686 -#endif
2687 -
2688 - void setupWidgetMap() const;
2689 -};
2690 -
2691 -void QUiLoaderPrivate::setupWidgetMap() const
2692 -{
2693 - if (!g_widgets()->isEmpty())
2694 - return;
2695 -
2696 -#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true);
2697 -#define DECLARE_LAYOUT(a, b)
2698 -
2699 -#include "widgets.table"
2700 -
2701 -#undef DECLARE_WIDGET
2702 -#undef DECLARE_WIDGET_1
2703 -#undef DECLARE_LAYOUT
2704 -}
2705 -
2706 -/*!
2707 - \class QUiLoader
2708 - \inmodule QtUiTools
2709 -
2710 - \brief The QUiLoader class enables standalone applications to
2711 - dynamically create user interfaces at run-time using the
2712 - information stored in UI files or specified in plugin paths.
2713 -
2714 - In addition, you can customize or create your own user interface by
2715 - deriving your own loader class.
2716 -
2717 - If you have a custom component or an application that embeds \QD, you can
2718 - also use the QFormBuilder class provided by the QtDesigner module to create
2719 - user interfaces from UI files.
2720 -
2721 - The QUiLoader class provides a collection of functions allowing you to
2722 - create widgets based on the information stored in UI files (created
2723 - with \QD) or available in the specified plugin paths. The specified plugin
2724 - paths can be retrieved using the pluginPaths() function. Similarly, the
2725 - contents of a UI file can be retrieved using the load() function. For
2726 - example:
2727 -
2728 - \snippet quiloader/mywidget.cpp 0
2729 -
2730 - \if !defined(qtforpython)
2731 - By including the user interface in the form's resources (\c myform.qrc), we
2732 - ensure that it will be present at run-time:
2733 -
2734 - \quotefile quiloader/mywidget.qrc
2735 - \endif
2736 -
2737 - The availableWidgets() function returns a QStringList with the class names
2738 - of the widgets available in the specified plugin paths. To create these
2739 - widgets, simply use the createWidget() function. For example:
2740 -
2741 - \snippet quiloader/main.cpp 0
2742 -
2743 - To make a custom widget available to the loader, you can use the
2744 - addPluginPath() function; to remove all available widgets, you can call
2745 - the clearPluginPaths() function.
2746 -
2747 - The createAction(), createActionGroup(), createLayout(), and createWidget()
2748 - functions are used internally by the QUiLoader class whenever it has to
2749 - create an action, action group, layout, or widget respectively. For that
2750 - reason, you can subclass the QUiLoader class and reimplement these
2751 - functions to intervene the process of constructing a user interface. For
2752 - example, you might want to have a list of the actions created when loading
2753 - a form or creating a custom widget.
2754 -
2755 - For a complete example using the QUiLoader class, see the
2756 - \l{Calculator Builder Example}.
2757 -
2758 - \sa {Qt UI Tools}, QFormBuilder
2759 -*/
2760 -
2761 -/*!
2762 - Creates a form loader with the given \a parent.
2763 -*/
2764 -QUiLoader::QUiLoader(QObject *parent)
2765 - : QObject(parent), d_ptr(new QUiLoaderPrivate)
2766 -{
2767 - Q_D(QUiLoader);
2768 -
2769 -#ifndef QT_NO_DATASTREAM
2770 - static int metaTypeId = 0;
2771 - if (!metaTypeId) {
2772 - metaTypeId = qRegisterMetaType<QUiTranslatableStringValue>("QUiTranslatableStringValue");
2773 - }
2774 -#endif // QT_NO_DATASTREAM
2775 - d->builder.loader = this;
2776 -
2777 -#if QT_CONFIG(library)
2778 - QStringList paths;
2779 - const QStringList &libraryPaths = QApplication::libraryPaths();
2780 - for (const QString &path : libraryPaths) {
2781 - QString libPath = path;
2782 - libPath += QDir::separator();
2783 - libPath += QStringLiteral("designer");
2784 - paths.append(libPath);
2785 - }
2786 -
2787 - d->builder.setPluginPath(paths);
2788 -#endif // QT_CONFIG(library)
2789 -}
2790 -
2791 -/*!
2792 - Destroys the loader.
2793 -*/
2794 -QUiLoader::~QUiLoader() = default;
2795 -
2796 -/*!
2797 - Loads a form from the given \a device and creates a new widget with the
2798 - given \a parentWidget to hold its contents.
2799 -
2800 - \sa createWidget(), errorString()
2801 -*/
2802 -QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
2803 -{
2804 - Q_D(QUiLoader);
2805 - // QXmlStreamReader will report errors on open failure.
2806 - if (!device->isOpen())
2807 - device->open(QIODevice::ReadOnly|QIODevice::Text);
2808 - return d->builder.load(device, parentWidget);
2809 -}
2810 -
2811 -/*!
2812 - Returns a list naming the paths in which the loader will search when
2813 - locating custom widget plugins.
2814 -
2815 - \sa addPluginPath(), clearPluginPaths()
2816 -*/
2817 -QStringList QUiLoader::pluginPaths() const
2818 -{
2819 - Q_D(const QUiLoader);
2820 - return d->builder.pluginPaths();
2821 -}
2822 -
2823 -/*!
2824 - Clears the list of paths in which the loader will search when locating
2825 - plugins.
2826 -
2827 - \sa addPluginPath(), pluginPaths()
2828 -*/
2829 -void QUiLoader::clearPluginPaths()
2830 -{
2831 - Q_D(QUiLoader);
2832 - d->builder.clearPluginPaths();
2833 -}
2834 -
2835 -/*!
2836 - Adds the given \a path to the list of paths in which the loader will search
2837 - when locating plugins.
2838 -
2839 - \sa pluginPaths(), clearPluginPaths()
2840 -*/
2841 -void QUiLoader::addPluginPath(const QString &path)
2842 -{
2843 - Q_D(QUiLoader);
2844 - d->builder.addPluginPath(path);
2845 -}
2846 -
2847 -/*!
2848 - Creates a new widget with the given \a parent and \a name using the class
2849 - specified by \a className. You can use this function to create any of the
2850 - widgets returned by the availableWidgets() function.
2851 -
2852 - The function is also used internally by the QUiLoader class whenever it
2853 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2854 - function to intervene process of constructing a user interface or widget.
2855 - However, in your implementation, ensure that you call QUiLoader's version
2856 - first.
2857 -
2858 - \sa availableWidgets(), load()
2859 -*/
2860 -QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
2861 -{
2862 - Q_D(QUiLoader);
2863 - return d->builder.defaultCreateWidget(className, parent, name);
2864 -}
2865 -
2866 -/*!
2867 - Creates a new layout with the given \a parent and \a name using the class
2868 - specified by \a className.
2869 -
2870 - The function is also used internally by the QUiLoader class whenever it
2871 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2872 - function to intervene process of constructing a user interface or widget.
2873 - However, in your implementation, ensure that you call QUiLoader's version
2874 - first.
2875 -
2876 - \sa createWidget(), load()
2877 -*/
2878 -QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
2879 -{
2880 - Q_D(QUiLoader);
2881 - return d->builder.defaultCreateLayout(className, parent, name);
2882 -}
2883 -
2884 -/*!
2885 - Creates a new action group with the given \a parent and \a name.
2886 -
2887 - The function is also used internally by the QUiLoader class whenever it
2888 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2889 - function to intervene process of constructing a user interface or widget.
2890 - However, in your implementation, ensure that you call QUiLoader's version
2891 - first.
2892 -
2893 - \sa createAction(), createWidget(), load()
2894 - */
2895 -QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
2896 -{
2897 - Q_D(QUiLoader);
2898 - return d->builder.defaultCreateActionGroup(parent, name);
2899 -}
2900 -
2901 -/*!
2902 - Creates a new action with the given \a parent and \a name.
2903 -
2904 - The function is also used internally by the QUiLoader class whenever it
2905 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2906 - function to intervene process of constructing a user interface or widget.
2907 - However, in your implementation, ensure that you call QUiLoader's version
2908 - first.
2909 -
2910 - \sa createActionGroup(), createWidget(), load()
2911 -*/
2912 -QAction *QUiLoader::createAction(QObject *parent, const QString &name)
2913 -{
2914 - Q_D(QUiLoader);
2915 - return d->builder.defaultCreateAction(parent, name);
2916 -}
2917 -
2918 -/*!
2919 - Returns a list naming all available widgets that can be built using the
2920 - createWidget() function, i.e all the widgets specified within the given
2921 - plugin paths.
2922 -
2923 - \sa pluginPaths(), createWidget()
2924 -
2925 -*/
2926 -QStringList QUiLoader::availableWidgets() const
2927 -{
2928 - Q_D(const QUiLoader);
2929 -
2930 - d->setupWidgetMap();
2931 - widget_map available = *g_widgets();
2932 -
2933 - const auto &customWidgets = d->builder.customWidgets();
2934 - for (QDesignerCustomWidgetInterface *plugin : customWidgets)
2935 - available.insert(plugin->name(), true);
2936 -
2937 - return available.keys();
2938 -}
2939 -
2940 -
2941 -/*!
2942 - \since 4.5
2943 - Returns a list naming all available layouts that can be built using the
2944 - createLayout() function
2945 -
2946 - \sa createLayout()
2947 -*/
2948 -
2949 -QStringList QUiLoader::availableLayouts() const
2950 -{
2951 - QStringList rc;
2952 -#define DECLARE_WIDGET(a, b)
2953 -#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a));
2954 -
2955 -#include "widgets.table"
2956 -
2957 -#undef DECLARE_WIDGET
2958 -#undef DECLARE_LAYOUT
2959 - return rc;
2960 -}
2961 -
2962 -/*!
2963 - Sets the working directory of the loader to \a dir. The loader will look
2964 - for other resources, such as icons and resource files, in paths relative to
2965 - this directory.
2966 -
2967 - \sa workingDirectory()
2968 -*/
2969 -
2970 -void QUiLoader::setWorkingDirectory(const QDir &dir)
2971 -{
2972 - Q_D(QUiLoader);
2973 - d->builder.setWorkingDirectory(dir);
2974 -}
2975 -
2976 -/*!
2977 - Returns the working directory of the loader.
2978 -
2979 - \sa setWorkingDirectory()
2980 -*/
2981 -
2982 -QDir QUiLoader::workingDirectory() const
2983 -{
2984 - Q_D(const QUiLoader);
2985 - return d->builder.workingDirectory();
2986 -}
2987 -/*!
2988 - \since 4.5
2989 -
2990 - If \a enabled is true, user interfaces loaded by this loader will
2991 - automatically retranslate themselves upon receiving a language change
2992 - event. Otherwise, the user interfaces will not be retranslated.
2993 -
2994 - \sa isLanguageChangeEnabled()
2995 -*/
2996 -
2997 -void QUiLoader::setLanguageChangeEnabled(bool enabled)
2998 -{
2999 - Q_D(QUiLoader);
3000 - d->builder.dynamicTr = enabled;
3001 -}
3002 -
3003 -/*!
3004 - \since 4.5
3005 -
3006 - Returns true if dynamic retranslation on language change is enabled;
3007 - returns false otherwise.
3008 -
3009 - \sa setLanguageChangeEnabled()
3010 -*/
3011 -
3012 -bool QUiLoader::isLanguageChangeEnabled() const
3013 -{
3014 - Q_D(const QUiLoader);
3015 - return d->builder.dynamicTr;
3016 -}
3017 -
3018 -/*!
3019 - \internal
3020 - \since 4.5
3021 -
3022 - If \a enabled is true, user interfaces loaded by this loader will be
3023 - translated. Otherwise, the user interfaces will not be translated.
3024 -
3025 - \note This is orthogonal to languageChangeEnabled.
3026 -
3027 - \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
3028 -*/
3029 -
3030 -void QUiLoader::setTranslationEnabled(bool enabled)
3031 -{
3032 - Q_D(QUiLoader);
3033 - d->builder.trEnabled = enabled;
3034 -}
3035 -
3036 -/*!
3037 - \internal
3038 - \since 4.5
3039 -
3040 - Returns true if translation is enabled; returns false otherwise.
3041 -
3042 - \sa setTranslationEnabled()
3043 -*/
3044 -
3045 -bool QUiLoader::isTranslationEnabled() const
3046 -{
3047 - Q_D(const QUiLoader);
3048 - return d->builder.trEnabled;
3049 -}
3050 -
3051 -/*!
3052 - Returns a human-readable description of the last error occurred in load().
3053 -
3054 - \since 5.0
3055 - \sa load()
3056 -*/
3057 -
3058 -QString QUiLoader::errorString() const
3059 -{
3060 - Q_D(const QUiLoader);
3061 - return d->builder.errorString();
3062 -}
3063 -
3064 -QT_END_NAMESPACE
3065 -
3066 -#include "quiloader.moc"
3067 diff --git x/qttools/src/uitools/quiloader.h y/qttools/src/uitools/quiloader.h
3068 deleted file mode 100644
3069 index 742b5606f..000000000
3070 --- x/qttools/src/uitools/quiloader.h
3071 +++ /dev/null
3072 @@ -1,61 +0,0 @@
3073 -// Copyright (C) 2020 The Qt Company Ltd.
3074 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3075 -
3076 -#ifndef QUILOADER_H
3077 -#define QUILOADER_H
3078 -
3079 -#include <QtUiTools/qtuitoolsglobal.h>
3080 -#include <QtCore/qobject.h>
3081 -#include <QtCore/qscopedpointer.h>
3082 -
3083 -QT_BEGIN_NAMESPACE
3084 -
3085 -class QWidget;
3086 -class QLayout;
3087 -class QAction;
3088 -class QActionGroup;
3089 -class QString;
3090 -class QIODevice;
3091 -class QDir;
3092 -
3093 -class QUiLoaderPrivate;
3094 -class Q_UITOOLS_EXPORT QUiLoader : public QObject
3095 -{
3096 - Q_OBJECT
3097 -public:
3098 - explicit QUiLoader(QObject *parent = nullptr);
3099 - ~QUiLoader() override;
3100 -
3101 - QStringList pluginPaths() const;
3102 - void clearPluginPaths();
3103 - void addPluginPath(const QString &path);
3104 -
3105 - QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr);
3106 - QStringList availableWidgets() const;
3107 - QStringList availableLayouts() const;
3108 -
3109 - virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString());
3110 - virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString());
3111 - virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString());
3112 - virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString());
3113 -
3114 - void setWorkingDirectory(const QDir &dir);
3115 - QDir workingDirectory() const;
3116 -
3117 - void setLanguageChangeEnabled(bool enabled);
3118 - bool isLanguageChangeEnabled() const;
3119 -
3120 - void setTranslationEnabled(bool enabled);
3121 - bool isTranslationEnabled() const;
3122 -
3123 - QString errorString() const;
3124 -
3125 -private:
3126 - QScopedPointer<QUiLoaderPrivate> d_ptr;
3127 - Q_DECLARE_PRIVATE(QUiLoader)
3128 - Q_DISABLE_COPY_MOVE(QUiLoader)
3129 -};
3130 -
3131 -QT_END_NAMESPACE
3132 -
3133 -#endif // QUILOADER_H
3134 diff --git x/qttools/src/uitools/quiloader_p.h y/qttools/src/uitools/quiloader_p.h
3135 deleted file mode 100644
3136 index efd943217..000000000
3137 --- x/qttools/src/uitools/quiloader_p.h
3138 +++ /dev/null
3139 @@ -1,77 +0,0 @@
3140 -// Copyright (C) 2020 The Qt Company Ltd.
3141 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3142 -
3143 -#ifndef QUILOADER_P_H
3144 -#define QUILOADER_P_H
3145 -
3146 -//
3147 -// W A R N I N G
3148 -// -------------
3149 -//
3150 -// This file is not part of the Qt API. It exists purely as an
3151 -// implementation detail. This header file may change from version to
3152 -// version without notice, or even be removed.
3153 -//
3154 -// We mean it.
3155 -//
3156 -
3157 -#include <QtUiTools/qtuitoolsglobal.h>
3158 -#include <QtCore/qbytearray.h>
3159 -#include <QtCore/qmetatype.h>
3160 -
3161 -QT_FORWARD_DECLARE_CLASS(QDataStream)
3162 -
3163 -// This file is here for use by the form preview in Linguist. If you change anything
3164 -// here or in the code which uses it, remember to adapt Linguist accordingly.
3165 -
3166 -#define PROP_GENERIC_PREFIX "_q_notr_"
3167 -#define PROP_TOOLITEMTEXT "_q_toolItemText_notr"
3168 -#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr"
3169 -#define PROP_TABPAGETEXT "_q_tabPageText_notr"
3170 -#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr"
3171 -#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr"
3172 -
3173 -QT_BEGIN_NAMESPACE
3174 -
3175 -class Q_UITOOLS_EXPORT QUiTranslatableStringValue
3176 -{
3177 -public:
3178 - QByteArray value() const { return m_value; }
3179 - void setValue(const QByteArray &value) { m_value = value; }
3180 - QByteArray qualifier() const { return m_qualifier; }
3181 - void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; }
3182 -
3183 - QString translate(const QByteArray &className, bool idBased) const;
3184 -
3185 -private:
3186 - QByteArray m_value;
3187 - QByteArray m_qualifier; // Comment or ID for id-based tr().
3188 -};
3189 -
3190 -#ifndef QT_NO_DATASTREAM
3191 -Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s);
3192 -Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s);
3193 -#endif // QT_NO_DATASTREAM
3194 -
3195 -struct QUiItemRolePair {
3196 - int realRole;
3197 - int shadowRole;
3198 -};
3199 -
3200 -#ifdef QFORMINTERNAL_NAMESPACE
3201 -namespace QFormInternal
3202 -{
3203 -#endif
3204 -
3205 -extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[];
3206 -
3207 -#ifdef QFORMINTERNAL_NAMESPACE
3208 -}
3209 -#endif
3210 -
3211 -QT_END_NAMESPACE
3212 -
3213 -Q_DECLARE_METATYPE(QUiTranslatableStringValue)
3214 -
3215 -
3216 -#endif // QUILOADER_P_H
3217 diff --git x/qttools/sync.profile y/qttools/sync.profile
3218 index caa7ed5ad..de4261afc 100644
3219 --- x/qttools/sync.profile
3220 +++ y/qttools/sync.profile
3221 @@ -1,8 +1,8 @@
3222 %modules = ( # path to module name map
3223 "QtTools" => "$basedir/src/global",
3224 "QtHelp" => "$basedir/src/assistant/help",
3225 - "QtUiTools" => "$basedir/src/uitools",
3226 - "QtUiPlugin" => "$basedir/src/uiplugin",
3227 + "QtUiTools" => "$basedir/src/designer/src/uitools",
3228 + "QtUiPlugin" => "$basedir/src/designer/src/uiplugin",
3229 "QtDesigner" => "$basedir/src/designer/src/lib",
3230 "QtDesignerComponents" => "$basedir/src/designer/src/components/lib",
3231 );
3232 --
3233 2.38.1
3234
+0
-39
libs/patches/qt-webengine-0001-Fix-Linux-build-with-CMake-versions-3.25.patch less more
0 From dfc2918f8d635edf9300512fc5c1a067a89707d1 Mon Sep 17 00:00:00 2001
1 From: Alexey Edelev <alexey.edelev@qt.io>
2 Date: Wed, 23 Nov 2022 12:40:45 +0100
3 Subject: Fix Linux build with CMake versions >= 3.25
4 MIME-Version: 1.0
5 Content-Type: text/plain; charset=UTF-8
6 Content-Transfer-Encoding: 8bit
7
8 The 'LINUX' variable exists in CMake since the version 3.25. This
9 variable previously was undefined while preparsing the configure.cmake
10 files. Since the CMake script that defines the 'check_for_ulimit'
11 function is not included while evaluating configure.cmake first time
12 we need to add a stub.
13
14 Change-Id: I25bdec4f4a1b6af23174507a8f0f9cbf01f0c398
15 Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
16 (cherry picked from commit 240e71877865ed07e4c8d5bd4553aa0772c2adf4)
17 Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
18 (cherry picked from commit 517d0890f9e95c841bea3421f2455651ca0d8070)
19 ---
20 configure.cmake | 2 ++
21 1 file changed, 2 insertions(+)
22
23 diff --git x/qtwebengine/configure.cmake y/qtwebengine/configure.cmake
24 index f485c1b4b..fff76d54a 100644
25 --- x/qtwebengine/configure.cmake
26 +++ y/qtwebengine/configure.cmake
27 @@ -3,6 +3,8 @@ if(QT_CONFIGURE_RUNNING)
28 endfunction()
29 function(add_check_for_support)
30 endfunction()
31 + function(check_for_ulimit)
32 + endfunction()
33 else()
34 find_package(Ninja 1.7.2)
35 find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT)
36 --
37 2.38.1
38
0 From 68bc2e3fae6480d6315f524c2ee9acf3a33a435a Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= <aklitzing@gmail.com>
2 Date: Mon, 25 Jul 2022 17:08:54 +0200
3 Subject: Revert "Fix usage of logging category on Android"
4
5 This reverts commit 87d8ee755bfdef8e72a122789c2e3ed382881a12.
6
7 Change-Id: If19a9d615e01d61c79955cda4789ba1646520ee1
8 ---
9 src/corelib/global/qlogging.cpp | 9 +--------
10 1 file changed, 1 insertion(+), 8 deletions(-)
11
12 diff --git x/qtbase/src/corelib/global/qlogging.cpp y/qtbase/src/corelib/global/qlogging.cpp
13 index 9ac70b3340..737a91dc6e 100644
14 --- x/qtbase/src/corelib/global/qlogging.cpp
15 +++ y/qtbase/src/corelib/global/qlogging.cpp
16 @@ -1450,10 +1450,7 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
17 } else if (token == messageTokenC) {
18 message.append(str);
19 } else if (token == categoryTokenC) {
20 -#ifndef Q_OS_ANDROID
21 - // Don't add the category to the message on Android
22 message.append(QLatin1StringView(context.category));
23 -#endif
24 } else if (token == typeTokenC) {
25 switch (type) {
26 case QtDebugMsg: message.append("debug"_L1); break;
27 @@ -1701,11 +1698,7 @@ static bool android_default_message_handler(QtMsgType type,
28 break;
29 };
30
31 - // If application name is a tag ensure it has no spaces
32 - // If a category is defined, use it as an Android logging tag
33 - __android_log_print(priority, isDefaultCategory(context.category) ?
34 - qPrintable(QCoreApplication::applicationName().replace(u' ', u'_')) : context.category,
35 - "%s\n", qPrintable(formattedMessage));
36 + __android_log_print(priority, qPrintable(QCoreApplication::applicationName()), "%s\n", qPrintable(formattedMessage));
37
38 return true; // Prevent further output to stderr
39 }
0 From bdd9f0e3a243977858df6691b734b7f596a9729b Mon Sep 17 00:00:00 2001
1 From: Bartlomiej Moskal <bartlomiej.moskal@qt.io>
2 Date: Tue, 30 May 2023 14:17:19 +0200
3 Subject: Android: Restore the default QSettings path to the .config directory
4
5 After 140ca89a3c2b8d78889d27217f977cd4de10041b commit, the path of the
6 QSettings default file location changed. That caused the problem with
7 updating the app (old settings file is not used anymore). That is why we
8 should still use old (.config) directory for QSettings file if the file
9 exists.
10
11 Pick-to: 6.2 6.5 6.6
12 Fixes: QTBUG-109405
13 Fixes: QTBUG-109369
14 Change-Id: I8ce53e0a80e4c2d16802b27b000ab3fbed198628
15 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
16 (cherry picked from commit beaaa0bf02fee696b03f2839bea8e0e6bc685a62)
17 ---
18 src/corelib/io/qsettings.cpp | 40 +++++++++++++++++++++++++-----------
19 1 file changed, 28 insertions(+), 12 deletions(-)
20
21 diff --git x/qtbase/src/corelib/io/qsettings.cpp y/qtbase/src/corelib/io/qsettings.cpp
22 index 60622e3aaa..9fb2e0b522 100644
23 --- x/qtbase/src/corelib/io/qsettings.cpp
24 +++ y/qtbase/src/corelib/io/qsettings.cpp
25 @@ -954,26 +954,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
26 }
27
28 #ifndef Q_OS_WIN
29 -static QString make_user_path()
30 +static constexpr QChar sep = u'/';
31 +
32 +#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID)
33 +static QString make_user_path_without_qstandard_paths()
34 {
35 - static constexpr QChar sep = u'/';
36 -#ifndef QSETTINGS_USE_QSTANDARDPATHS
37 - // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
38 - // for some time now. Moving away from that would require migrating existing settings.
39 QByteArray env = qgetenv("XDG_CONFIG_HOME");
40 if (env.isEmpty()) {
41 return QDir::homePath() + "/.config/"_L1;
42 } else if (env.startsWith('/')) {
43 return QFile::decodeName(env) + sep;
44 - } else {
45 - return QDir::homePath() + sep + QFile::decodeName(env) + sep;
46 }
47 +
48 + return QDir::homePath() + sep + QFile::decodeName(env) + sep;
49 +}
50 +#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID
51 +
52 +static QString make_user_path()
53 +{
54 +#ifndef QSETTINGS_USE_QSTANDARDPATHS
55 + // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
56 + // for some time now. Moving away from that would require migrating existing settings.
57 + // The migration has already been done for Android.
58 + return make_user_path_without_qstandard_paths();
59 #else
60 - // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
61 - // it makes the use of test mode from unit tests possible.
62 +
63 +#ifdef Q_OS_ANDROID
64 + // If an old settings path exists, use it instead of creating a new one
65 + QString ret = make_user_path_without_qstandard_paths();
66 + if (QFile(ret).exists())
67 + return ret;
68 +#endif // Q_OS_ANDROID
69 +
70 + // When using a proper XDG platform or Android platform, use QStandardPaths rather than the
71 + // above hand-written code. It makes the use of test mode from unit tests possible.
72 // Ideally all platforms should use this, but see above for the migration issue.
73 return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep;
74 -#endif
75 +#endif // !QSETTINGS_USE_QSTANDARDPATHS
76 }
77 #endif // !Q_OS_WIN
78
79 @@ -1338,8 +1355,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
80 // On android and if it is a content URL put the lock file in a
81 // writable location to prevent permissions issues and invalid paths.
82 if (confFile->name.startsWith("content:"_L1))
83 - lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
84 - + QFileInfo(lockFileName).fileName();
85 + lockFileName = make_user_path() + QFileInfo(lockFileName).fileName();
86 # endif
87 /*
88 Use a lockfile in order to protect us against other QSettings instances
0 From a7490023e8f11906b30013c93ff991d941efc622 Mon Sep 17 00:00:00 2001
1 From: Julian Greilich <j.greilich@gmx.de>
2 Date: Wed, 4 Jan 2023 16:32:28 +0100
3 Subject: Android A11Y: Only access the main thread when it is not blocked
4
5 When the qtMainLoopThread calls QSGThreadedRenderLoop::polishAndSync(),
6 it waits for the QSGRenderThread.
7
8 In the QSGRenderThread, QAndroidPlatformOpenGLWindow::eglSurface()
9 calls QtAndroid::createSurface() and waits for the "android main
10 thread" to return a valid surface.
11 When the "android main thread" now calls "runInObjectContext" (e.g. by
12 calling QtAndroidAccessibility::childIdListForAccessibleObject()) it
13 waits for the qtMainLoopThread and the program is stuck in a deadlock.
14
15 To prevent this, we protect all BlockedQueuedConnection from the
16 "android main thread" to the qtMainLoopThread by acquiring the
17 AndroidDeadlockProtector.
18 When QAndroidPlatformOpenGLWindow::eglSurface() already acquired the
19 AndroidDeadlockProtector we abort the current A11y call with an emtpy
20 or default value.
21
22 Note: b8a95275440b8a143ee648466fd8b5401ee1e839 already tried to fix
23 this by checking "getSurfaceCount() != 0", but there are situations,
24 where a new surface is being created while an old surface is still
25 present.
26
27 Task-number: QTBUG-105958
28 Pick-to: 6.5 6.4 6.3 6.2 5.15
29 Change-Id: Ie40e8654c99aace9e69b0b8412952fa22c89f071
30 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
31 (cherry picked from commit b832a5ac72c6015b6509d60b75b2ce5d5e570800)
32 ---
33 .../platforms/android/androidjniaccessibility.cpp | 9 +++++++++
34 1 file changed, 9 insertions(+)
35
36 diff --git x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp
37 index 3067cb178a..8990289dc4 100644
38 --- x/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp
39 +++ y/qtbase/src/plugins/platforms/android/androidjniaccessibility.cpp
40 @@ -1,6 +1,7 @@
41 // Copyright (C) 2021 The Qt Company Ltd.
42 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
43
44 +#include "androiddeadlockprotector.h"
45 #include "androidjniaccessibility.h"
46 #include "androidjnimain.h"
47 #include "qandroidplatformintegration.h"
48 @@ -61,6 +62,14 @@ namespace QtAndroidAccessibility
49 template <typename Func, typename Ret>
50 void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
51 {
52 + AndroidDeadlockProtector protector;
53 + if (!protector.acquire()) {
54 + __android_log_print(ANDROID_LOG_WARN, m_qtTag,
55 + "Could not run accessibility call in object context, accessing "
56 + "main thread could lead to deadlock");
57 + return;
58 + }
59 +
60 if (!QtAndroid::blockEventLoopsWhenSuspended()
61 || QGuiApplication::applicationState() != Qt::ApplicationSuspended) {
62 QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal);
0 From 03485e0ca36c615b87b82c6711fbacf0493d02bc Mon Sep 17 00:00:00 2001
1 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
2 Date: Mon, 9 Jan 2023 06:54:53 +0100
3 Subject: Fix warning in q20algorithm.h when xcodebuild is used
4
5 q20algorithm.h:150:20: error: unused function template 'operator()'
6 q20algorithm.h:163:20: error: unused function template 'operator()'
7 q20algorithm.h:176:20: error: unused function template 'operator()'
8
9 Fixes: QTBUG-109874
10 Change-Id: If5ccbfffd0b6a53f73f221b45033dab7e4775d89
11 ---
12 src/corelib/global/q20algorithm.h | 6 +++---
13 1 file changed, 3 insertions(+), 3 deletions(-)
14
15 diff --git x/qtbase/src/corelib/global/q20algorithm.h y/qtbase/src/corelib/global/q20algorithm.h
16 index 69dc2d2446..88e8ab08d2 100644
17 --- x/qtbase/src/corelib/global/q20algorithm.h
18 +++ y/qtbase/src/corelib/global/q20algorithm.h
19 @@ -147,7 +147,7 @@ using std::ranges::none_of;
20 [[maybe_unused]] inline constexpr struct { // Niebloid
21 template <typename InputIterator, typename Sentinel,
22 typename Predicate, typename Projection = q20::identity>
23 - constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
24 + [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
25 {
26 while (first != last) {
27 if (std::invoke(pred, std::invoke(proj, *first)))
28 @@ -160,7 +160,7 @@ using std::ranges::none_of;
29 [[maybe_unused]] inline constexpr struct { // Niebloid
30 template <typename InputIterator, typename Sentinel,
31 typename Predicate, typename Projection = q20::identity>
32 - constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
33 + [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
34 {
35 while (first != last) {
36 if (!std::invoke(pred, std::invoke(proj, *first)))
37 @@ -173,7 +173,7 @@ using std::ranges::none_of;
38 [[maybe_unused]] inline constexpr struct { // Niebloid
39 template <typename InputIterator, typename Sentinel,
40 typename Predicate, typename Projection = q20::identity>
41 - constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
42 + [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
43 {
44 while (first != last) {
45 if (std::invoke(pred, std::invoke(proj, *first)))
0 From e2402debef95b7ccc2050f331ee9f5076332ae91 Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@qt.io>
2 Date: Mon, 12 Dec 2022 14:33:41 +0100
3 Subject: macOS: Use NSStatusItem.menu to manage system tray menu
4
5 Using [NSStatusItem popUpStatusItemMenu:] to manually show the menu is
6 deprecated, and was causing various issues when right clicking the menu,
7 such as not unhighlighting the menu item when dismissing the menu, or
8 worse, not quitting the application if a 'Quit' item was triggered from
9 a right click.
10
11 The reason we were using popUpStatusItemMenu instead of the menu
12 property of NSStatusItem was that the latter prevented us from seeing
13 the action message of the NSStatusItem button, which we used to emit
14 the system tray's activated signal, but this can be solved by listing
15 for the menu's tracking state starting.
16
17 Fixes: QTBUG-103515
18 Pick-to: 6.4
19 Change-Id: I686550ebac7d94d8d11b2e3c49ed16a8240cb214
20 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
21 (cherry picked from commit da754d5b6589c9877f0325edb3da5cbc64d966c7)
22 ---
23 .../platforms/cocoa/qcocoasystemtrayicon.h | 3 +-
24 .../platforms/cocoa/qcocoasystemtrayicon.mm | 36 ++++++++++++-------
25 2 files changed, 24 insertions(+), 15 deletions(-)
26
27 diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
28 index 414560e119..75c33cc5a3 100644
29 --- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
30 +++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
31 @@ -45,12 +45,11 @@ public:
32 bool isSystemTrayAvailable() const override;
33 bool supportsMessages() const override;
34
35 - void statusItemClicked();
36 + void emitActivated();
37
38 private:
39 NSStatusItem *m_statusItem = nullptr;
40 QStatusItemDelegate *m_delegate = nullptr;
41 - QCocoaMenu *m_menu = nullptr;
42 };
43
44 QT_END_NAMESPACE
45 diff --git x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
46 index c004cd69b5..2f7f73b481 100644
47 --- x/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
48 +++ y/qtbase/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
49 @@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init()
50
51 m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this];
52
53 + // In case the status item does not have a menu assigned to it
54 + // we fall back to the item's button to detect activation.
55 m_statusItem.button.target = m_delegate;
56 m_statusItem.button.action = @selector(statusItemClicked);
57 [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown];
58 @@ -81,8 +83,6 @@ void QCocoaSystemTrayIcon::cleanup()
59
60 [m_delegate release];
61 m_delegate = nil;
62 -
63 - m_menu = nullptr;
64 }
65
66 QRect QCocoaSystemTrayIcon::geometry() const
67 @@ -178,12 +178,20 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
68
69 void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
70 {
71 - // We don't set the menu property of the NSStatusItem here,
72 - // as that would prevent us from receiving the action for the
73 - // click, and we wouldn't be able to emit the activated signal.
74 - // Instead we show the menu manually when the status item is
75 - // clicked.
76 - m_menu = static_cast<QCocoaMenu *>(menu);
77 + m_statusItem.menu = menu ? static_cast<QCocoaMenu *>(menu)->nsMenu() : nil;
78 +
79 + if (m_statusItem.menu) {
80 + // When a menu is assigned, NSStatusBarButtonCell will intercept the mouse
81 + // down to pop up the menu, and we never see the NSStatusBarButton action.
82 + // To ensure we emit the 'activated' signal in both cases we detect when
83 + // menu starts tracking, which happens before the menu delegate is sent
84 + // the menuWillOpen callback we use to emit aboutToShow for the menu.
85 + [NSNotificationCenter.defaultCenter addObserver:m_delegate
86 + selector:@selector(statusItemMenuBeganTracking:)
87 + name:NSMenuDidBeginTrackingNotification
88 + object:m_statusItem.menu
89 + ];
90 + }
91 }
92
93 void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip)
94 @@ -226,7 +234,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
95 }
96 }
97
98 -void QCocoaSystemTrayIcon::statusItemClicked()
99 +void QCocoaSystemTrayIcon::emitActivated()
100 {
101 auto *mouseEvent = NSApp.currentEvent;
102
103 @@ -245,9 +253,6 @@ void QCocoaSystemTrayIcon::statusItemClicked()
104 }
105
106 emit activated(activationReason);
107 -
108 - if (NSMenu *menu = m_menu ? m_menu->nsMenu() : nil)
109 - QT_IGNORE_DEPRECATIONS([m_statusItem popUpStatusItemMenu:menu]);
110 }
111
112 QT_END_NAMESPACE
113 @@ -270,7 +275,12 @@ QT_END_NAMESPACE
114
115 - (void)statusItemClicked
116 {
117 - self.platformSystemTray->statusItemClicked();
118 + self.platformSystemTray->emitActivated();
119 +}
120 +
121 +- (void)statusItemMenuBeganTracking:(NSNotification*)notification
122 +{
123 + self.platformSystemTray->emitActivated();
124 }
125
126 - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
0 From d967022bcd7061771f10e4d36d38ab8ffe5aef98 Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@qt.io>
2 Date: Thu, 15 Dec 2022 16:40:34 +0100
3 Subject: iOS: Don't assume screens will not be connected before
4 QIOSIntegration
5
6 When an external screen is connected to an iPad, and the application is
7 starting up on that screen, we will get a connection notification about
8 that screen as part of the initial bootstrap of UIApplicationMain,
9 before we call the user's main().
10
11 Since we initialize and add all available screen on QIOSIntegration
12 creation, we can just ignore the early connection notification.
13
14 This avoids a crash, but the window will not show anything on the
15 external screen, which is a separate issue.
16
17 Pick-to: 6.5 6.4 6.2
18 Fixes: QTBUG-106701
19 Change-Id: I9e0a9736bf602277316bd004e0d01c640feaf319
20 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
21 (cherry picked from commit dd49793bc3b4dd3808f0f24b717c442a5095db14)
22 ---
23 src/plugins/platforms/ios/qiosscreen.mm | 4 ++--
24 1 file changed, 2 insertions(+), 2 deletions(-)
25
26 diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
27 index f144c00fb0..3d660189af 100644
28 --- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm
29 +++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
30 @@ -72,8 +72,8 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
31
32 + (void)screenConnected:(NSNotification*)notification
33 {
34 - Q_ASSERT_X(QIOSIntegration::instance(), Q_FUNC_INFO,
35 - "Screen connected before QIOSIntegration creation");
36 + if (!QIOSIntegration::instance())
37 + return; // Will be added when QIOSIntegration is created
38
39 QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object]));
40 }
0 From 6d6832fc530c9296d92dd924f6f6bca0effa6412 Mon Sep 17 00:00:00 2001
1 From: Jan Moeller <jan.moeller@governikus.de>
2 Date: Thu, 6 Apr 2023 09:27:16 +0200
3 Subject: Ignore removed/changed screens if no QIOSIntegration instance exists
4
5 QIOSTracker registers itself as handlers for system notifications about
6 changes of the screen environment. If no QIOSIntegration instance
7 exists, newly detected screens are not added to the list of known
8 screens (see screenConnected()). This, in turn, will result in a crash
9 if a screen is disconnected and removed in screenDisconnected() as it
10 is not known to qtPlatformScreenFor() and the function returns a
11 nullptr.
12
13 Consider the QIOSIntegration also whenever a screen is "changed". This
14 is more of a safety measure do avoid crashes for unknown screens.
15
16 This situation occurs if an iOS device is used to mirror the display
17 via AirPlay and no actual QGuiApplication exists, e.g. Qt is only
18 embedded in a Framework.
19
20 Pick-to: 6.5 6.2
21 Fixes: QTBUG-106701
22 Change-Id: Id778fc5afa7c284b0536ee02b1ba2c10321cc5b1
23 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
24 Reviewed-by: Lars Schmertmann <lars.schmertmann@governikus.de>
25 (cherry picked from commit ffdfafc4b47b8267395370199073c292da33dd42)
26 ---
27 src/plugins/platforms/ios/qiosscreen.mm | 6 ++++++
28 1 file changed, 6 insertions(+)
29
30 diff --git x/qtbase/src/plugins/platforms/ios/qiosscreen.mm y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
31 index 3d660189af..e0216ce652 100644
32 --- x/qtbase/src/plugins/platforms/ios/qiosscreen.mm
33 +++ y/qtbase/src/plugins/platforms/ios/qiosscreen.mm
34 @@ -80,6 +80,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
35
36 + (void)screenDisconnected:(NSNotification*)notification
37 {
38 + if (!QIOSIntegration::instance())
39 + return;
40 +
41 QIOSScreen *screen = qtPlatformScreenFor([notification object]);
42 Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about");
43
44 @@ -88,6 +91,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
45
46 + (void)screenModeChanged:(NSNotification*)notification
47 {
48 + if (!QIOSIntegration::instance())
49 + return;
50 +
51 QIOSScreen *screen = qtPlatformScreenFor([notification object]);
52 Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about");
53
0 From 25b9264bd6e5a547db3692032dd5c49cb2db0bfd Mon Sep 17 00:00:00 2001
1 From: Allan Sandfeld Jensen <allan.jensen@qt.io>
2 Date: Fri, 5 May 2023 09:51:32 +0200
3 Subject: Fix specific overflow in qtextlayout
4
5 Adds qAddOverflow and qMulOverflow definitions to QFixed
6
7 Fixes: QTBUG-113337
8 Pick-to: 6.5 6.5.1 6.2 5.15
9 Change-Id: I13579306defceaccdc0fbb1ec0e9b77c6f8d1af9
10 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
11 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
12 (cherry picked from commit 7b7a01c266b507636eab51a36328c7c72d82d93c)
13 ---
14 src/gui/painting/qfixed_p.h | 17 +++++++++++++++++
15 src/gui/text/qtextlayout.cpp | 9 ++++++---
16 2 files changed, 23 insertions(+), 3 deletions(-)
17
18 diff --git x/qtbase/src/gui/painting/qfixed_p.h y/qtbase/src/gui/painting/qfixed_p.h
19 index f3718a097e..c0a13d057f 100644
20 --- x/qtbase/src/gui/painting/qfixed_p.h
21 +++ y/qtbase/src/gui/painting/qfixed_p.h
22 @@ -18,6 +18,7 @@
23 #include <QtGui/private/qtguiglobal_p.h>
24 #include "QtCore/qdebug.h"
25 #include "QtCore/qpoint.h"
26 +#include "QtCore/qnumeric.h"
27 #include "QtCore/qsize.h"
28
29 QT_BEGIN_NAMESPACE
30 @@ -136,6 +137,22 @@ constexpr inline QFixed operator+(uint i, QFixed d) { return d+i; }
31 constexpr inline QFixed operator-(uint i, QFixed d) { return -(d-i); }
32 // constexpr inline QFixed operator*(qreal d, QFixed d2) { return d2*d; }
33
34 +inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r)
35 +{
36 + int val;
37 + bool result = qAddOverflow(v1.value(), v2.value(), &val);
38 + r->setValue(val);
39 + return result;
40 +}
41 +
42 +inline bool qMulOverflow(QFixed v1, QFixed v2, QFixed *r)
43 +{
44 + int val;
45 + bool result = qMulOverflow(v1.value(), v2.value(), &val);
46 + r->setValue(val);
47 + return result;
48 +}
49 +
50 #ifndef QT_NO_DEBUG_STREAM
51 inline QDebug &operator<<(QDebug &dbg, QFixed f)
52 { return dbg << f.toReal(); }
53 diff --git x/qtbase/src/gui/text/qtextlayout.cpp y/qtbase/src/gui/text/qtextlayout.cpp
54 index 365131f508..6a36b2458a 100644
55 --- x/qtbase/src/gui/text/qtextlayout.cpp
56 +++ y/qtbase/src/gui/text/qtextlayout.cpp
57 @@ -2105,11 +2105,14 @@ found:
58 eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
59 } else {
60 eng->minWidth = qMax(eng->minWidth, lbh.minw);
61 - eng->maxWidth += line.textWidth;
62 + if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth))
63 + eng->maxWidth = QFIXED_MAX;
64 }
65
66 - if (line.textWidth > 0 && item < eng->layoutData->items.size())
67 - eng->maxWidth += lbh.spaceData.textWidth;
68 + if (line.textWidth > 0 && item < eng->layoutData->items.size()) {
69 + if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth))
70 + eng->maxWidth = QFIXED_MAX;
71 + }
72
73 line.textWidth += trailingSpace;
74 if (lbh.spaceData.length) {
0 From 550172c8a2f5e7195e2255bc50cffb2a64b8701c Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= <marten.nordheim@qt.io>
2 Date: Wed, 10 May 2023 16:43:41 +0200
3 Subject: Schannel: Reject certificate not signed by a configured CA
4 certificate
5
6 Not entirely clear why, but when building the certificate chain for a
7 peer the system certificate store is searched for root certificates.
8 General expectation is that after calling
9 `sslConfiguration.setCaCertificates()` the system certificates will
10 not be taken into consideration.
11
12 To work around this behavior, we do a manual check that the root of the
13 chain is part of the configured CA certificates.
14
15 Pick-to: 6.5 6.2 5.15
16 Change-Id: I03666a4d9b0eac39ae97e150b4743120611a11b3
17 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
18 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
19 (cherry picked from commit ada2c573c1a25f8d96577734968fe317ddfa292a)
20 ---
21 src/plugins/tls/schannel/qtls_schannel.cpp | 21 ++++
22 .../network/ssl/client-auth/CMakeLists.txt | 24 ++++
23 .../network/ssl/client-auth/certs/.gitignore | 4 +
24 .../client-auth/certs/accepted-client.conf | 14 +++
25 .../network/ssl/client-auth/certs/generate.sh | 33 +++++
26 .../tst_manual_ssl_client_auth.cpp | 118 ++++++++++++++++++
27 6 files changed, 214 insertions(+)
28 create mode 100644 tests/manual/network/ssl/client-auth/CMakeLists.txt
29 create mode 100644 tests/manual/network/ssl/client-auth/certs/.gitignore
30 create mode 100644 tests/manual/network/ssl/client-auth/certs/accepted-client.conf
31 create mode 100755 tests/manual/network/ssl/client-auth/certs/generate.sh
32 create mode 100644 tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp
33
34 diff --git x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp
35 index 58e74357d8..c15eab8796 100644
36 --- x/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp
37 +++ y/qtbase/src/plugins/tls/schannel/qtls_schannel.cpp
38 @@ -2106,6 +2106,27 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
39 verifyDepth = DWORD(q->peerVerifyDepth());
40
41 const auto &caCertificates = q->sslConfiguration().caCertificates();
42 +
43 + if (!rootCertOnDemandLoadingAllowed()
44 + && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
45 + && (q->peerVerifyMode() == QSslSocket::VerifyPeer
46 + || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
47 + // When verifying a peer Windows "helpfully" builds a chain that
48 + // may include roots from the system store. But we don't want that if
49 + // the user has set their own CA certificates.
50 + // Since Windows claims this is not a partial chain the root is included
51 + // and we have to check that it is one of our configured CAs.
52 + CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
53 + QSslCertificate certificate = getCertificateFromChainElement(element);
54 + if (!caCertificates.contains(certificate)) {
55 + auto error = QSslError(QSslError::CertificateUntrusted, certificate);
56 + sslErrors += error;
57 + emit q->peerVerifyError(error);
58 + if (q->state() != QAbstractSocket::ConnectedState)
59 + return false;
60 + }
61 + }
62 +
63 QList<QSslCertificate> peerCertificateChain;
64 for (DWORD i = 0; i < verifyDepth; i++) {
65 CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
66 diff --git x/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt
67 new file mode 100644
68 index 0000000000..67ecc20bf4
69 --- /dev/null
70 +++ y/qtbase/tests/manual/network/ssl/client-auth/CMakeLists.txt
71 @@ -0,0 +1,24 @@
72 +# Copyright (C) 2023 The Qt Company Ltd.
73 +# SPDX-License-Identifier: BSD-3-Clause
74 +
75 +qt_internal_add_manual_test(tst_manual_ssl_client_auth
76 + SOURCES
77 + tst_manual_ssl_client_auth.cpp
78 + LIBRARIES
79 + Qt::Network
80 +)
81 +
82 +qt_internal_add_resource(tst_manual_ssl_client_auth "tst_manual_ssl_client_auth"
83 + PREFIX
84 + "/"
85 + FILES
86 + "certs/127.0.0.1.pem"
87 + "certs/127.0.0.1-key.pem"
88 + "certs/127.0.0.1-client.pem"
89 + "certs/127.0.0.1-client-key.pem"
90 + "certs/accepted-client.pem"
91 + "certs/accepted-client-key.pem"
92 + "certs/rootCA.pem"
93 + BASE
94 + "certs"
95 +)
96 diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore
97 new file mode 100644
98 index 0000000000..5866f7b609
99 --- /dev/null
100 +++ y/qtbase/tests/manual/network/ssl/client-auth/certs/.gitignore
101 @@ -0,0 +1,4 @@
102 +*
103 +!/.gitignore
104 +!/generate.sh
105 +!/accepted-client.conf
106 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
107 new file mode 100644
108 index 0000000000..a88b276efe
109 --- /dev/null
110 +++ y/qtbase/tests/manual/network/ssl/client-auth/certs/accepted-client.conf
111 @@ -0,0 +1,14 @@
112 +[req]
113 +default_md = sha512
114 +basicConstraints = CA:FALSE
115 +extendedKeyUsage = clientAuth
116 +[req]
117 +distinguished_name = client_distinguished_name
118 +prompt = no
119 +[client_distinguished_name]
120 +C = NO
121 +ST = Oslo
122 +L = Oslo
123 +O = The Qt Project
124 +OU = The Qt Project
125 +CN = Fake Qt Project Client Certificate
126 diff --git x/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh
127 new file mode 100755
128 index 0000000000..5dbe3b3712
129 --- /dev/null
130 +++ y/qtbase/tests/manual/network/ssl/client-auth/certs/generate.sh
131 @@ -0,0 +1,33 @@
132 +#!/bin/bash
133 +# Copyright (C) 2023 The Qt Company Ltd.
134 +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
135 +
136 +# Requires mkcert and openssl
137 +
138 +warn () { echo "$@" >&2; }
139 +die () { warn "$@"; exit 1; }
140 +
141 +
142 +command -v mkcert 1>/dev/null 2>&1 || die "Failed to find mkcert"
143 +command -v openssl 1>/dev/null 2>&1 || die "Failed to find openssl"
144 +
145 +SCRIPT=$(realpath "$0")
146 +SCRIPTPATH=$(dirname "$SCRIPT")
147 +
148 +pushd "$SCRIPTPATH" || die "Unable to pushd to $SCRIPTPATH"
149 +mkcert 127.0.0.1
150 +mkcert -client 127.0.0.1
151 +warn "Remember to run mkcert -install if you haven't already"
152 +
153 +# Generate CA
154 +openssl genrsa -out ca-key.pem 2048
155 +openssl req -new -x509 -noenc -days 365 -key ca-key.pem -out rootCA.pem
156 +
157 +# Generate accepted client certificate
158 +openssl genrsa -out accepted-client-key.pem 2048
159 +openssl req -new -sha512 -nodes -key accepted-client-key.pem -out accepted-client.csr -config accepted-client.conf
160 +openssl x509 -req -sha512 -days 45 -in accepted-client.csr -CA rootCA.pem -CAkey ca-key.pem -CAcreateserial -out accepted-client.pem
161 +rm accepted-client.csr
162 +rm rootCA.srl
163 +
164 +popd || die "Unable to popd"
165 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
166 new file mode 100644
167 index 0000000000..2307cbb191
168 --- /dev/null
169 +++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp
170 @@ -0,0 +1,118 @@
171 +// Copyright (C) 2023 The Qt Company Ltd.
172 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
173 +
174 +#include <QtCore/qcoreapplication.h>
175 +
176 +#include <QtCore/qthread.h>
177 +#include <QtCore/qfile.h>
178 +#include <QtCore/qdir.h>
179 +
180 +#include <QtNetwork/qsslsocket.h>
181 +#include <QtNetwork/qsslserver.h>
182 +#include <QtNetwork/qsslconfiguration.h>
183 +#include <QtNetwork/qsslkey.h>
184 +
185 +// Client and/or server presents a certificate signed by a system-trusted CA
186 +// but the other side presents a certificate signed by a different CA.
187 +constexpr bool TestServerPresentsIncorrectCa = false;
188 +constexpr bool TestClientPresentsIncorrectCa = true;
189 +
190 +class ServerThread : public QThread
191 +{
192 + Q_OBJECT
193 +public:
194 + void run() override
195 + {
196 + QSslServer server;
197 +
198 + QSslConfiguration config = server.sslConfiguration();
199 + QList<QSslCertificate> certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem"));
200 + config.setCaCertificates(certs);
201 + config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem"))
202 + .first());
203 + QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem"));
204 + if (!keyFile.open(QIODevice::ReadOnly))
205 + qFatal("Failed to open key file");
206 + config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa));
207 + config.setPeerVerifyMode(QSslSocket::VerifyPeer);
208 + server.setSslConfiguration(config);
209 +
210 + connect(&server, &QSslServer::pendingConnectionAvailable, [&server]() {
211 + QSslSocket *socket = static_cast<QSslSocket *>(server.nextPendingConnection());
212 + qDebug() << "[s] newConnection" << socket->peerAddress() << socket->peerPort();
213 + socket->disconnectFromHost();
214 + qApp->quit();
215 + });
216 + connect(&server, &QSslServer::startedEncryptionHandshake, [](QSslSocket *socket) {
217 + qDebug() << "[s] new handshake" << socket->peerAddress() << socket->peerPort();
218 + });
219 + connect(&server, &QSslServer::errorOccurred,
220 + [](QSslSocket *socket, QAbstractSocket::SocketError error) {
221 + qDebug() << "[s] errorOccurred" << socket->peerAddress() << socket->peerPort()
222 + << error << socket->errorString();
223 + });
224 + connect(&server, &QSslServer::peerVerifyError,
225 + [](QSslSocket *socket, const QSslError &error) {
226 + qDebug() << "[s] peerVerifyError" << socket->peerAddress() << socket->peerPort()
227 + << error;
228 + });
229 + server.listen(QHostAddress::LocalHost, 24242);
230 +
231 + exec();
232 +
233 + server.close();
234 + }
235 +};
236 +
237 +int main(int argc, char **argv)
238 +{
239 + QCoreApplication app(argc, argv);
240 +
241 + using namespace Qt::StringLiterals;
242 +
243 + if (!QFileInfo(u":/rootCA.pem"_s).exists())
244 + qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?");
245 +
246 + ServerThread serverThread;
247 + serverThread.start();
248 +
249 + QSslSocket socket;
250 + QSslConfiguration config = socket.sslConfiguration();
251 + QString certificatePath;
252 + QString keyFileName;
253 + if constexpr (TestClientPresentsIncorrectCa) { // true: Present cert signed with incorrect CA: should fail
254 + certificatePath = u":/127.0.0.1-client.pem"_s;
255 + keyFileName = u":/127.0.0.1-client-key.pem"_s;
256 + } else { // false: Use correct CA: should succeed
257 + certificatePath = u":/accepted-client.pem"_s;
258 + keyFileName = u":/accepted-client-key.pem"_s;
259 + }
260 + config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first());
261 + if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail
262 + config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s));
263 + QFile keyFile(keyFileName);
264 + if (!keyFile.open(QIODevice::ReadOnly))
265 + qFatal("Failed to open key file");
266 + config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa));
267 + socket.setSslConfiguration(config);
268 +
269 + QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; });
270 + QObject::connect(&socket, &QSslSocket::errorOccurred,
271 + [&socket](QAbstractSocket::SocketError error) {
272 + qDebug() << "[c] errorOccurred" << error << socket.errorString();
273 + qApp->quit();
274 + });
275 + QObject::connect(&socket, &QSslSocket::sslErrors, [](const QList<QSslError> &errors) {
276 + qDebug() << "[c] sslErrors" << errors;
277 + });
278 + QObject::connect(&socket, &QSslSocket::connected, []() { qDebug() << "[c] connected"; });
279 +
280 + socket.connectToHostEncrypted(QStringLiteral("127.0.0.1"), 24242);
281 +
282 + const int res = app.exec();
283 + serverThread.quit();
284 + serverThread.wait();
285 + return res;
286 +}
287 +
288 +#include "tst_manual_ssl_client_auth.moc"
0 From d13e70c1d56a94d64eb68d2f3cba670e58a1a73f Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= <marten.nordheim@qt.io>
2 Date: Thu, 25 May 2023 14:40:29 +0200
3 Subject: Ssl: Copy the on-demand cert loading bool from default config
4
5 Otherwise individual sockets will still load system certificates when
6 a chain doesn't match against the configured CA certificates.
7 That's not intended behavior, since specifically setting the CA
8 certificates means you don't want the system certificates to be used.
9
10 Follow-up to/amends ada2c573c1a25f8d96577734968fe317ddfa292a
11
12 This is potentially a breaking change because now, if you ever add a
13 CA to the default config, it will disable loading system certificates
14 on demand for all sockets. And the only way to re-enable it is to
15 create a null-QSslConfiguration and set it as the new default.
16
17 Pick-to: 6.5 6.2 5.15
18 Change-Id: Ic3b2ab125c0cdd58ad654af1cb36173960ce2d1e
19 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
20 (cherry picked from commit 57ba6260c0801055b7188fdaa1818b940590f5f1)
21 ---
22 src/network/ssl/qsslsocket.cpp | 5 ++++
23 .../tst_manual_ssl_client_auth.cpp | 24 ++++++++++++++++---
24 2 files changed, 26 insertions(+), 3 deletions(-)
25
26 diff --git x/qtbase/src/network/ssl/qsslsocket.cpp y/qtbase/src/network/ssl/qsslsocket.cpp
27 index cd76517c25..a94f2b79c3 100644
28 --- x/qtbase/src/network/ssl/qsslsocket.cpp
29 +++ y/qtbase/src/network/ssl/qsslsocket.cpp
30 @@ -1973,6 +1973,10 @@ QSslSocketPrivate::QSslSocketPrivate()
31 , flushTriggered(false)
32 {
33 QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
34 + // If the global configuration doesn't allow root certificates to be loaded
35 + // on demand then we have to disable it for this socket as well.
36 + if (!configuration.allowRootCertOnDemandLoading)
37 + allowRootCertOnDemandLoading = false;
38
39 const auto *tlsBackend = tlsBackendInUse();
40 if (!tlsBackend) {
41 @@ -2281,6 +2285,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
42 ptr->sessionProtocol = global->sessionProtocol;
43 ptr->ciphers = global->ciphers;
44 ptr->caCertificates = global->caCertificates;
45 + ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
46 ptr->protocol = global->protocol;
47 ptr->peerVerifyMode = global->peerVerifyMode;
48 ptr->peerVerifyDepth = global->peerVerifyDepth;
49 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
50 index 2307cbb191..4d4aaca7e3 100644
51 --- x/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp
52 +++ y/qtbase/tests/manual/network/ssl/client-auth/tst_manual_ssl_client_auth.cpp
53 @@ -16,6 +16,9 @@
54 // but the other side presents a certificate signed by a different CA.
55 constexpr bool TestServerPresentsIncorrectCa = false;
56 constexpr bool TestClientPresentsIncorrectCa = true;
57 +// Decides whether or not to put the root CA into the global ssl configuration
58 +// or into the socket's specific ssl configuration.
59 +constexpr bool UseGlobalConfiguration = true;
60
61 class ServerThread : public QThread
62 {
63 @@ -26,8 +29,10 @@ public:
64 QSslServer server;
65
66 QSslConfiguration config = server.sslConfiguration();
67 - QList<QSslCertificate> certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem"));
68 - config.setCaCertificates(certs);
69 + if (!UseGlobalConfiguration) {
70 + QList<QSslCertificate> certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem"));
71 + config.setCaCertificates(certs);
72 + }
73 config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem"))
74 .first());
75 QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem"));
76 @@ -73,6 +78,12 @@ int main(int argc, char **argv)
77 if (!QFileInfo(u":/rootCA.pem"_s).exists())
78 qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?");
79
80 + if (UseGlobalConfiguration) {
81 + QSslConfiguration config = QSslConfiguration::defaultConfiguration();
82 + config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s));
83 + QSslConfiguration::setDefaultConfiguration(config);
84 + }
85 +
86 ServerThread serverThread;
87 serverThread.start();
88
89 @@ -88,12 +99,19 @@ int main(int argc, char **argv)
90 keyFileName = u":/accepted-client-key.pem"_s;
91 }
92 config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first());
93 - if (TestServerPresentsIncorrectCa) // true: Verify server using incorrect CA: should fail
94 + if (!UseGlobalConfiguration && TestServerPresentsIncorrectCa) {
95 + // Verify server using incorrect CA: should fail
96 config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s));
97 + } else if (UseGlobalConfiguration && !TestServerPresentsIncorrectCa) {
98 + // Verify server using correct CA, we need to explicitly set the
99 + // system CAs when the global config is overridden.
100 + config.setCaCertificates(QSslConfiguration::systemCaCertificates());
101 + }
102 QFile keyFile(keyFileName);
103 if (!keyFile.open(QIODevice::ReadOnly))
104 qFatal("Failed to open key file");
105 config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa));
106 +
107 socket.setSslConfiguration(config);
108
109 QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; });
0 From bdc4845cd844e674f17161435a11e60dde2769cc Mon Sep 17 00:00:00 2001
1 From: Jens Trillmann <jens.trillmann@governikus.de>
2 Date: Wed, 5 Jul 2023 09:33:03 +0200
3 Subject: Improve Intent source app detection
4
5 Activity.getReferrer does not only return app IDs but also URLs if
6 Intent.EXTRA_REFERRER is set on the Intent. In the case of Chrome the referrer
7 is set to the website triggering the Intent. To improve the detection of the
8 calling app we check first if the browser specific
9 Browser.EXTRAS_APPLICATION_ID is set. If it is not set we fall back to
10 Intent.getReferrer.
11
12 Pick-to: 6.6
13 Change-Id: I33d1edd52de98486d9616713e531ea20ada87bcb
14 ---
15 .../qtproject/qt/android/bindings/QtActivity.java | 15 ++++++++++++---
16 1 file changed, 12 insertions(+), 3 deletions(-)
17
18 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
19 index 9cef8146fd..f862f6aaee 100644
20 --- x/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
21 +++ y/qtbase/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
22 @@ -16,6 +16,7 @@ import android.graphics.Canvas;
23 import android.net.Uri;
24 import android.os.Build;
25 import android.os.Bundle;
26 +import android.provider.Browser;
27 import android.util.AttributeSet;
28 import android.view.ActionMode;
29 import android.view.ActionMode.Callback;
30 @@ -237,9 +238,17 @@ public class QtActivity extends Activity
31 return;
32
33 String sourceInformation = "";
34 - Uri referrer = getReferrer();
35 - if (referrer != null)
36 - sourceInformation = referrer.toString().replaceFirst("android-app://", "");
37 + String browserApplicationId = intent.getExtras() == null ? "" : intent.getExtras().getString(Browser.EXTRA_APPLICATION_ID);
38 + if (!browserApplicationId.isEmpty())
39 + {
40 + sourceInformation = browserApplicationId;
41 + }
42 + else
43 + {
44 + Uri referrer = getReferrer();
45 + if (referrer != null)
46 + sourceInformation = referrer.toString().replaceFirst("android-app://", "");
47 + }
48
49 intent.putExtra(EXTRA_SOURCE_INFO, sourceInformation);
50 }
0 From f9a1c8668e5f4787e9b0b3136076138f4fda5563 Mon Sep 17 00:00:00 2001
1 From: Ahmad Samir <a.samirh78@gmail.com>
2 Date: Wed, 12 Apr 2023 13:10:26 +0200
3 Subject: QXmlStreamReader: change fastScanName() to take a Value*
4
5 For easier debugging, e.g. to print out value.len and value.prefix.
6
7 Pick-to: 6.6 6.5 6.5.2 6.2 5.15
8 Change-Id: Ib0eed38772f899502962f578775d34ea2744fdde
9 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
10 (cherry picked from commit 1a423ce4372d18a779f3c0d746d5283d9a425839)
11 ---
12 src/corelib/serialization/qxmlstream.cpp | 16 ++++++++--------
13 src/corelib/serialization/qxmlstream.g | 3 ++-
14 src/corelib/serialization/qxmlstream_p.h | 2 +-
15 src/corelib/serialization/qxmlstreamparser_p.h | 3 ++-
16 4 files changed, 13 insertions(+), 11 deletions(-)
17
18 diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp
19 index a6a2bc41af..f64db47867 100644
20 --- x/qtbase/src/corelib/serialization/qxmlstream.cpp
21 +++ y/qtbase/src/corelib/serialization/qxmlstream.cpp
22 @@ -1243,7 +1243,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
23 return n;
24 }
25
26 -inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
27 +inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val)
28 {
29 qsizetype n = 0;
30 uint c;
31 @@ -1280,16 +1280,16 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
32 case '+':
33 case '*':
34 putChar(c);
35 - if (prefix && *prefix == n+1) {
36 - *prefix = 0;
37 + if (val && val->prefix == n + 1) {
38 + val->prefix = 0;
39 putChar(':');
40 --n;
41 }
42 return n;
43 case ':':
44 - if (prefix) {
45 - if (*prefix == 0) {
46 - *prefix = qint16(n + 2);
47 + if (val) {
48 + if (val->prefix == 0) {
49 + val->prefix = qint16(n + 2);
50 } else { // only one colon allowed according to the namespace spec.
51 putChar(c);
52 return n;
53 @@ -1305,8 +1305,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
54 }
55 }
56
57 - if (prefix)
58 - *prefix = 0;
59 + if (val)
60 + val->prefix = 0;
61 qsizetype pos = textBuffer.size() - n;
62 putString(textBuffer, pos);
63 textBuffer.resize(pos);
64 diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g
65 index d06c371eb8..f3152bff37 100644
66 --- x/qtbase/src/corelib/serialization/qxmlstream.g
67 +++ y/qtbase/src/corelib/serialization/qxmlstream.g
68 @@ -1419,7 +1419,8 @@ space_opt ::= space;
69 qname ::= LETTER;
70 /.
71 case $rule_number: {
72 - sym(1).len += fastScanName(&sym(1).prefix);
73 + Value &val = sym(1);
74 + val.len += fastScanName(&val);
75 if (atEnd) {
76 resume($rule_number);
77 return false;
78 diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h
79 index 8e523f9c67..5da1f4aa5a 100644
80 --- x/qtbase/src/corelib/serialization/qxmlstream_p.h
81 +++ y/qtbase/src/corelib/serialization/qxmlstream_p.h
82 @@ -471,7 +471,7 @@ public:
83 qsizetype fastScanLiteralContent();
84 qsizetype fastScanSpace();
85 qsizetype fastScanContentCharList();
86 - qsizetype fastScanName(qint16 *prefix = nullptr);
87 + qsizetype fastScanName(Value *val = nullptr);
88 inline qsizetype fastScanNMTOKEN();
89
90
91 diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h
92 index e3ae6faa44..59370a9310 100644
93 --- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h
94 +++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h
95 @@ -947,7 +947,8 @@ bool QXmlStreamReaderPrivate::parse()
96 break;
97
98 case 262: {
99 - sym(1).len += fastScanName(&sym(1).prefix);
100 + Value &val = sym(1);
101 + val.len += fastScanName(&val);
102 if (atEnd) {
103 resume(262);
104 return false;
0 From 836d7df23ec9b6cb3dea1bb68b7c8bc75090702e Mon Sep 17 00:00:00 2001
1 From: Ahmad Samir <a.samirh78@gmail.com>
2 Date: Thu, 22 Jun 2023 15:56:07 +0300
3 Subject: QXmlStreamReader: make fastScanName() indicate parsing status to
4 callers
5
6 This fixes a crash while parsing an XML file with garbage data, the file
7 starts with '<' then garbage data:
8 - The loop in the parse() keeps iterating until it hits "case 262:",
9 which calls fastScanName()
10 - fastScanName() iterates over the text buffer scanning for the
11 attribute name (e.g. "xml:lang"), until it finds ':'
12 - Consider a Value val, fastScanName() is called on it, it would set
13 val.prefix to a number > val.len, then it would hit the 4096 condition
14 and return (returned 0, now it returns the equivalent of
15 std::null_opt), which means that val.len doesn't get modified, making
16 it smaller than val.prefix
17 - The code would try constructing an XmlStringRef with negative length,
18 which would hit an assert in one of QStringView's constructors
19
20 Add an assert to the XmlStringRef constructor.
21
22 Add unittest based on the file from the bug report.
23
24 Later on I will replace FastScanNameResult with std::optional<qsizetype>
25 (std::optional is C++17, which isn't required by Qt 5.15, and we want to
26 backport this fix).
27
28 Credit to OSS-Fuzz.
29
30 Fixes: QTBUG-109781
31 Fixes: QTBUG-114829
32 Pick-to: 6.6 6.5 6.2 5.15
33 Change-Id: I455a5eeb47870c2ac9ffd0cbcdcd99c1ae2dd374
34 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
35 (cherry picked from commit 6326bec46a618c72feba4a2bb994c4d475050aed)
36 ---
37 src/corelib/serialization/qxmlstream.cpp | 23 ++++++++---
38 src/corelib/serialization/qxmlstream.g | 12 +++++-
39 src/corelib/serialization/qxmlstream_p.h | 14 ++++++-
40 .../serialization/qxmlstreamparser_p.h | 12 +++++-
41 .../qxmlstream/tst_qxmlstream.cpp | 39 +++++++++++++++++++
42 5 files changed, 88 insertions(+), 12 deletions(-)
43
44 diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp
45 index f64db47867..34568b7351 100644
46 --- x/qtbase/src/corelib/serialization/qxmlstream.cpp
47 +++ y/qtbase/src/corelib/serialization/qxmlstream.cpp
48 @@ -1243,7 +1243,9 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
49 return n;
50 }
51
52 -inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val)
53 +// Fast scan an XML attribute name (e.g. "xml:lang").
54 +inline QXmlStreamReaderPrivate::FastScanNameResult
55 +QXmlStreamReaderPrivate::fastScanName(Value *val)
56 {
57 qsizetype n = 0;
58 uint c;
59 @@ -1251,7 +1253,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val)
60 if (n >= 4096) {
61 // This is too long to be a sensible name, and
62 // can exhaust memory, or the range of decltype(*prefix)
63 - return 0;
64 + raiseNamePrefixTooLongError();
65 + return {};
66 }
67 switch (c) {
68 case '\n':
69 @@ -1285,18 +1288,18 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val)
70 putChar(':');
71 --n;
72 }
73 - return n;
74 + return FastScanNameResult(n);
75 case ':':
76 if (val) {
77 if (val->prefix == 0) {
78 val->prefix = qint16(n + 2);
79 } else { // only one colon allowed according to the namespace spec.
80 putChar(c);
81 - return n;
82 + return FastScanNameResult(n);
83 }
84 } else {
85 putChar(c);
86 - return n;
87 + return FastScanNameResult(n);
88 }
89 Q_FALLTHROUGH();
90 default:
91 @@ -1310,7 +1313,7 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(Value *val)
92 qsizetype pos = textBuffer.size() - n;
93 putString(textBuffer, pos);
94 textBuffer.resize(pos);
95 - return 0;
96 + return FastScanNameResult(0);
97 }
98
99 enum NameChar { NameBeginning, NameNotBeginning, NotName };
100 @@ -1791,6 +1794,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message)
101 raiseError(QXmlStreamReader::NotWellFormedError, message);
102 }
103
104 +void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
105 +{
106 + // TODO: add a ImplementationLimitsExceededError and use it instead
107 + raiseError(QXmlStreamReader::NotWellFormedError,
108 + QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB "
109 + "characters)."));
110 +}
111 +
112 void QXmlStreamReaderPrivate::parseError()
113 {
114
115 diff --git x/qtbase/src/corelib/serialization/qxmlstream.g y/qtbase/src/corelib/serialization/qxmlstream.g
116 index f3152bff37..fc122e6681 100644
117 --- x/qtbase/src/corelib/serialization/qxmlstream.g
118 +++ y/qtbase/src/corelib/serialization/qxmlstream.g
119 @@ -1420,7 +1420,11 @@ qname ::= LETTER;
120 /.
121 case $rule_number: {
122 Value &val = sym(1);
123 - val.len += fastScanName(&val);
124 + if (auto res = fastScanName(&val))
125 + val.len += *res;
126 + else
127 + return false;
128 +
129 if (atEnd) {
130 resume($rule_number);
131 return false;
132 @@ -1431,7 +1435,11 @@ qname ::= LETTER;
133 name ::= LETTER;
134 /.
135 case $rule_number:
136 - sym(1).len += fastScanName();
137 + if (auto res = fastScanName())
138 + sym(1).len += *res;
139 + else
140 + return false;
141 +
142 if (atEnd) {
143 resume($rule_number);
144 return false;
145 diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h
146 index 5da1f4aa5a..7925e59014 100644
147 --- x/qtbase/src/corelib/serialization/qxmlstream_p.h
148 +++ y/qtbase/src/corelib/serialization/qxmlstream_p.h
149 @@ -38,7 +38,7 @@ public:
150
151 constexpr XmlStringRef() = default;
152 constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length)
153 - : m_string(string), m_pos(pos), m_size(length)
154 + : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length))
155 {
156 }
157 XmlStringRef(const QString *string)
158 @@ -471,7 +471,16 @@ public:
159 qsizetype fastScanLiteralContent();
160 qsizetype fastScanSpace();
161 qsizetype fastScanContentCharList();
162 - qsizetype fastScanName(Value *val = nullptr);
163 +
164 + struct FastScanNameResult {
165 + FastScanNameResult() : ok(false) {}
166 + explicit FastScanNameResult(qsizetype len) : addToLen(len), ok(true) { }
167 + operator bool() { return ok; }
168 + qsizetype operator*() { Q_ASSERT(ok); return addToLen; }
169 + qsizetype addToLen;
170 + bool ok;
171 + };
172 + FastScanNameResult fastScanName(Value *val = nullptr);
173 inline qsizetype fastScanNMTOKEN();
174
175
176 @@ -480,6 +489,7 @@ public:
177
178 void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
179 void raiseWellFormedError(const QString &message);
180 + void raiseNamePrefixTooLongError();
181
182 QXmlStreamEntityResolver *entityResolver;
183
184 diff --git x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h
185 index 59370a9310..afd83381b3 100644
186 --- x/qtbase/src/corelib/serialization/qxmlstreamparser_p.h
187 +++ y/qtbase/src/corelib/serialization/qxmlstreamparser_p.h
188 @@ -948,7 +948,11 @@ bool QXmlStreamReaderPrivate::parse()
189
190 case 262: {
191 Value &val = sym(1);
192 - val.len += fastScanName(&val);
193 + if (auto res = fastScanName(&val))
194 + val.len += *res;
195 + else
196 + return false;
197 +
198 if (atEnd) {
199 resume(262);
200 return false;
201 @@ -956,7 +960,11 @@ bool QXmlStreamReaderPrivate::parse()
202 } break;
203
204 case 263:
205 - sym(1).len += fastScanName();
206 + if (auto res = fastScanName())
207 + sym(1).len += *res;
208 + else
209 + return false;
210 +
211 if (atEnd) {
212 resume(263);
213 return false;
214 diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
215 index 2799e7a999..7eb0aac5cc 100644
216 --- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
217 +++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
218 @@ -581,6 +581,8 @@ private slots:
219 void readBack() const;
220 void roundTrip() const;
221 void roundTrip_data() const;
222 + void test_fastScanName_data() const;
223 + void test_fastScanName() const;
224
225 void entityExpansionLimit() const;
226
227 @@ -1753,5 +1755,42 @@ void tst_QXmlStream::roundTrip() const
228 QCOMPARE(out, in);
229 }
230
231 +void tst_QXmlStream::test_fastScanName_data() const
232 +{
233 + QTest::addColumn<QByteArray>("data");
234 + QTest::addColumn<QXmlStreamReader::Error>("errorType");
235 +
236 + // 4096 is the limit in QXmlStreamReaderPrivate::fastScanName()
237 +
238 + QByteArray arr = "<a"_ba + ":" + QByteArray("b").repeated(4096 - 1);
239 + QTest::newRow("data1") << arr << QXmlStreamReader::PrematureEndOfDocumentError;
240 +
241 + arr = "<a"_ba + ":" + QByteArray("b").repeated(4096);
242 + QTest::newRow("data2") << arr << QXmlStreamReader::NotWellFormedError;
243 +
244 + arr = "<"_ba + QByteArray("a").repeated(4000) + ":" + QByteArray("b").repeated(96);
245 + QTest::newRow("data3") << arr << QXmlStreamReader::PrematureEndOfDocumentError;
246 +
247 + arr = "<"_ba + QByteArray("a").repeated(4000) + ":" + QByteArray("b").repeated(96 + 1);
248 + QTest::newRow("data4") << arr << QXmlStreamReader::NotWellFormedError;
249 +
250 + arr = "<"_ba + QByteArray("a").repeated(4000 + 1) + ":" + QByteArray("b").repeated(96);
251 + QTest::newRow("data5") << arr << QXmlStreamReader::NotWellFormedError;
252 +}
253 +
254 +void tst_QXmlStream::test_fastScanName() const
255 +{
256 + QFETCH(QByteArray, data);
257 + QFETCH(QXmlStreamReader::Error, errorType);
258 +
259 + QXmlStreamReader reader(data);
260 + QXmlStreamReader::TokenType tokenType;
261 + while (!reader.atEnd())
262 + tokenType = reader.readNext();
263 +
264 + QCOMPARE(tokenType, QXmlStreamReader::Invalid);
265 + QCOMPARE(reader.error(), errorType);
266 +}
267 +
268 #include "tst_qxmlstream.moc"
269 // vim: et:ts=4:sw=4:sts=4
0 From 6f79fea4b7ee471adbed09d7e4b6da688a571c80 Mon Sep 17 00:00:00 2001
1 From: Sona Kurazyan <sona.kurazyan@qt.io>
2 Date: Fri, 2 Sep 2022 16:52:04 +0200
3 Subject: QXmlStreamReader: use qOffsetStringArray for storing token types
4 MIME-Version: 1.0
5 Content-Type: text/plain; charset=UTF-8
6 Content-Transfer-Encoding: 8bit
7
8 Change-Id: I9e58c17d97c44e1b13899d30396f65b452d8600f
9 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
10 (cherry picked from commit d674f3f5454fb39de9405484a8c01fb928523f67)
11 ---
12 src/corelib/serialization/qxmlstream.cpp | 67 ++++++------------------
13 1 file changed, 16 insertions(+), 51 deletions(-)
14
15 diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp
16 index 34568b7351..535f98a215 100644
17 --- x/qtbase/src/corelib/serialization/qxmlstream.cpp
18 +++ y/qtbase/src/corelib/serialization/qxmlstream.cpp
19 @@ -15,6 +15,8 @@
20 #include <qscopeguard.h>
21 #include <qcoreapplication.h>
22
23 +#include <private/qoffsetstringarray_p.h>
24 +
25 #include <iterator>
26 #include "qxmlstream_p.h"
27 #include "qxmlstreamparser_p.h"
28 @@ -640,55 +642,19 @@ void QXmlStreamReader::skipCurrentElement()
29 }
30 }
31
32 -/*
33 - * Use the following Perl script to generate the error string index list:
34 -===== PERL SCRIPT ====
35 -print "static const char QXmlStreamReader_tokenTypeString_string[] =\n";
36 -$counter = 0;
37 -$i = 0;
38 -while (<STDIN>) {
39 - chomp;
40 - print " \"$_\\0\"\n";
41 - $sizes[$i++] = $counter;
42 - $counter += length 1 + $_;
43 -}
44 -print " \"\\0\";\n\nstatic const short QXmlStreamReader_tokenTypeString_indices[] = {\n ";
45 -for ($j = 0; $j < $i; ++$j) {
46 - printf "$sizes[$j], ";
47 -}
48 -print "0\n};\n";
49 -===== PERL SCRIPT ====
50 -
51 - * The input data is as follows (copied from qxmlstream.h):
52 -NoToken
53 -Invalid
54 -StartDocument
55 -EndDocument
56 -StartElement
57 -EndElement
58 -Characters
59 -Comment
60 -DTD
61 -EntityReference
62 -ProcessingInstruction
63 -*/
64 -static const char QXmlStreamReader_tokenTypeString_string[] =
65 - "NoToken\0"
66 - "Invalid\0"
67 - "StartDocument\0"
68 - "EndDocument\0"
69 - "StartElement\0"
70 - "EndElement\0"
71 - "Characters\0"
72 - "Comment\0"
73 - "DTD\0"
74 - "EntityReference\0"
75 - "ProcessingInstruction\0";
76 -
77 -static const short QXmlStreamReader_tokenTypeString_indices[] = {
78 - 0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0
79 -};
80 -
81 +static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
82 + "NoToken",
83 + "Invalid",
84 + "StartDocument",
85 + "EndDocument",
86 + "StartElement",
87 + "EndElement",
88 + "Characters",
89 + "Comment",
90 + "DTD",
91 + "EntityReference",
92 + "ProcessingInstruction"
93 +);
94
95 /*!
96 \property QXmlStreamReader::namespaceProcessing
97 @@ -721,8 +687,7 @@ bool QXmlStreamReader::namespaceProcessing() const
98 QString QXmlStreamReader::tokenString() const
99 {
100 Q_D(const QXmlStreamReader);
101 - return QLatin1StringView(QXmlStreamReader_tokenTypeString_string +
102 - QXmlStreamReader_tokenTypeString_indices[d->type]);
103 + return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
104 }
105
106 #endif // QT_NO_XMLSTREAMREADER
0 From ce9ffbc726f7a0d90561db7206f3061371126190 Mon Sep 17 00:00:00 2001
1 From: Axel Spoerl <axel.spoerl@qt.io>
2 Date: Fri, 30 Jun 2023 12:43:59 +0200
3 Subject: QXmlStreamReader: Raise error on unexpected tokens
4
5 QXmlStreamReader accepted multiple DOCTYPE elements, containing DTD
6 fragments in the XML prolog, and in the XML body.
7 Well-formed but invalid XML files - with multiple DTD fragments in
8 prolog and body, combined with recursive entity expansions - have
9 caused infinite loops in QXmlStreamReader.
10
11 This patch implements a token check in QXmlStreamReader.
12 A stream is allowed to start with an XML prolog. StartDocument
13 and DOCTYPE elements are only allowed in this prolog, which
14 may also contain ProcessingInstruction and Comment elements.
15 As soon as anything else is seen, the prolog ends.
16 After that, the prolog-specific elements are treated as unexpected.
17 Furthermore, the prolog can contain at most one DOCTYPE element.
18
19 Update the documentation to reflect the new behavior.
20 Add an autotest that checks the new error cases are correctly detected,
21 and no error is raised for legitimate input.
22
23 The original OSS-Fuzz files (see bug reports) are not included in this
24 patch for file size reasons. They have been tested manually. Each of
25 them has more than one DOCTYPE element, causing infinite loops in
26 recursive entity expansions. The newly implemented functionality
27 detects those invalid DTD fragments. By raising an error, it aborts
28 stream reading before an infinite loop occurs.
29
30 Thanks to OSS-Fuzz for finding this.
31
32 Fixes: QTBUG-92113
33 Fixes: QTBUG-95188
34 Change-Id: I0a082b9188b2eee50b396c4d5b1c9e1fd237bbdd
35 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
36 (cherry picked from commit c4301be7d5f94852e1b17f2c2989d5ca807855d4)
37 (cherry picked from commit c216c3d9859a20b3aeec985512e89316423fc3a8)
38 ---
39 src/corelib/serialization/qxmlstream.cpp | 140 +++++++++++++++++-
40 src/corelib/serialization/qxmlstream_p.h | 11 ++
41 .../qxmlstream/tokenError/dtdInBody.xml | 20 +++
42 .../qxmlstream/tokenError/multipleDtd.xml | 20 +++
43 .../qxmlstream/tokenError/wellFormed.xml | 15 ++
44 .../qxmlstream/tst_qxmlstream.cpp | 39 +++++
45 6 files changed, 237 insertions(+), 8 deletions(-)
46 create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml
47 create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml
48 create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml
49
50 diff --git x/qtbase/src/corelib/serialization/qxmlstream.cpp y/qtbase/src/corelib/serialization/qxmlstream.cpp
51 index 535f98a215..050556f463 100644
52 --- x/qtbase/src/corelib/serialization/qxmlstream.cpp
53 +++ y/qtbase/src/corelib/serialization/qxmlstream.cpp
54 @@ -128,7 +128,7 @@ void reversed(const Range &&) = delete;
55 addData() or by waiting for it to arrive on the device().
56
57 \value UnexpectedElementError The parser encountered an element
58 - that was different to those it expected.
59 + or token that was different to those it expected.
60
61 */
62
63 @@ -263,13 +263,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
64
65 QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
66 include external parsed entities. As long as no error occurs, the
67 - application code can thus be assured that the data provided by the
68 - stream reader satisfies the W3C's criteria for well-formed XML. For
69 - example, you can be certain that all tags are indeed nested and
70 - closed properly, that references to internal entities have been
71 - replaced with the correct replacement text, and that attributes have
72 - been normalized or added according to the internal subset of the
73 - DTD.
74 + application code can thus be assured, that
75 + \list
76 + \li the data provided by the stream reader satisfies the W3C's
77 + criteria for well-formed XML,
78 + \li tokens are provided in a valid order.
79 + \endlist
80 +
81 + Unless QXmlStreamReader raises an error, it guarantees the following:
82 + \list
83 + \li All tags are nested and closed properly.
84 + \li References to internal entities have been replaced with the
85 + correct replacement text.
86 + \li Attributes have been normalized or added according to the
87 + internal subset of the \l DTD.
88 + \li Tokens of type \l StartDocument happen before all others,
89 + aside from comments and processing instructions.
90 + \li At most one DOCTYPE element (a token of type \l DTD) is present.
91 + \li If present, the DOCTYPE appears before all other elements,
92 + aside from StartDocument, comments and processing instructions.
93 + \endlist
94 +
95 + In particular, once any token of type \l StartElement, \l EndElement,
96 + \l Characters, \l EntityReference or \l EndDocument is seen, no
97 + tokens of type StartDocument or DTD will be seen. If one is present in
98 + the input stream, out of order, an error is raised.
99 +
100 + \note The token types \l Comment and \l ProcessingInstruction may appear
101 + anywhere in the stream.
102
103 If an error occurs while parsing, atEnd() and hasError() return
104 true, and error() returns the error that occurred. The functions
105 @@ -572,6 +593,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext()
106 d->token = -1;
107 return readNext();
108 }
109 + d->checkToken();
110 return d->type;
111 }
112
113 @@ -656,6 +678,11 @@ static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
114 "ProcessingInstruction"
115 );
116
117 +static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
118 + "Prolog",
119 + "Body"
120 +);
121 +
122 /*!
123 \property QXmlStreamReader::namespaceProcessing
124 \brief the namespace-processing flag of the stream reader.
125 @@ -690,6 +717,15 @@ QString QXmlStreamReader::tokenString() const
126 return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
127 }
128
129 +/*!
130 + \internal
131 + \return \param loc (Prolog/Body) as a string.
132 + */
133 +static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
134 +{
135 + return QLatin1StringView(QXmlStreamReader_XmlContextString.at(static_cast<int>(ctxt)));
136 +}
137 +
138 #endif // QT_NO_XMLSTREAMREADER
139
140 QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
141 @@ -776,6 +812,8 @@ void QXmlStreamReaderPrivate::init()
142
143 type = QXmlStreamReader::NoToken;
144 error = QXmlStreamReader::NoError;
145 + currentContext = XmlContext::Prolog;
146 + foundDTD = false;
147 }
148
149 /*
150 @@ -3692,6 +3730,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
151 }
152 }
153
154 +static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
155 + QXmlStreamReaderPrivate::XmlContext loc)
156 +{
157 + switch (type) {
158 + case QXmlStreamReader::StartDocument:
159 + case QXmlStreamReader::DTD:
160 + return loc == QXmlStreamReaderPrivate::XmlContext::Prolog;
161 +
162 + case QXmlStreamReader::StartElement:
163 + case QXmlStreamReader::EndElement:
164 + case QXmlStreamReader::Characters:
165 + case QXmlStreamReader::EntityReference:
166 + case QXmlStreamReader::EndDocument:
167 + return loc == QXmlStreamReaderPrivate::XmlContext::Body;
168 +
169 + case QXmlStreamReader::Comment:
170 + case QXmlStreamReader::ProcessingInstruction:
171 + return true;
172 +
173 + case QXmlStreamReader::NoToken:
174 + case QXmlStreamReader::Invalid:
175 + return false;
176 + }
177 +
178 + return false;
179 +}
180 +
181 +/*!
182 + \internal
183 + \brief QXmlStreamReader::isValidToken
184 + \return \c true if \param type is a valid token type.
185 + \return \c false if \param type is an unexpected token,
186 + which indicates a non-well-formed or invalid XML stream.
187 + */
188 +bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
189 +{
190 + // Don't change currentContext, if Invalid or NoToken occur in the prolog
191 + if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
192 + return false;
193 +
194 + // If a token type gets rejected in the body, there is no recovery
195 + const bool result = isTokenAllowedInContext(type, currentContext);
196 + if (result || currentContext == XmlContext::Body)
197 + return result;
198 +
199 + // First non-Prolog token observed => switch context to body and check again.
200 + currentContext = XmlContext::Body;
201 + return isTokenAllowedInContext(type, currentContext);
202 +}
203 +
204 +/*!
205 + \internal
206 + Checks token type and raises an error, if it is invalid
207 + in the current context (prolog/body).
208 + */
209 +void QXmlStreamReaderPrivate::checkToken()
210 +{
211 + Q_Q(QXmlStreamReader);
212 +
213 + // The token type must be consumed, to keep track if the body has been reached.
214 + const XmlContext context = currentContext;
215 + const bool ok = isValidToken(type);
216 +
217 + // Do nothing if an error has been raised already (going along with an unexpected token)
218 + if (error != QXmlStreamReader::Error::NoError)
219 + return;
220 +
221 + if (!ok) {
222 + raiseError(QXmlStreamReader::UnexpectedElementError,
223 + QObject::tr("Unexpected token type %1 in %2.")
224 + .arg(q->tokenString(), contextString(context)));
225 + return;
226 + }
227 +
228 + if (type != QXmlStreamReader::DTD)
229 + return;
230 +
231 + // Raise error on multiple DTD tokens
232 + if (foundDTD) {
233 + raiseError(QXmlStreamReader::UnexpectedElementError,
234 + QObject::tr("Found second DTD token in %1.").arg(contextString(context)));
235 + } else {
236 + foundDTD = true;
237 + }
238 +}
239 +
240 /*!
241 \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
242 \since 4.5
243 diff --git x/qtbase/src/corelib/serialization/qxmlstream_p.h y/qtbase/src/corelib/serialization/qxmlstream_p.h
244 index 7925e59014..c24c74d5c9 100644
245 --- x/qtbase/src/corelib/serialization/qxmlstream_p.h
246 +++ y/qtbase/src/corelib/serialization/qxmlstream_p.h
247 @@ -270,6 +270,17 @@ public:
248 QStringDecoder decoder;
249 bool atEnd;
250
251 + enum class XmlContext
252 + {
253 + Prolog,
254 + Body,
255 + };
256 +
257 + XmlContext currentContext = XmlContext::Prolog;
258 + bool foundDTD = false;
259 + bool isValidToken(QXmlStreamReader::TokenType type);
260 + void checkToken();
261 +
262 /*!
263 \sa setType()
264 */
265 diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml
266 new file mode 100644
267 index 0000000000..1c3ca4e271
268 --- /dev/null
269 +++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml
270 @@ -0,0 +1,20 @@
271 +<!DOCTYPE TEST [
272 + <!ELEMENT TESTATTRIBUTE (CASE+)>
273 + <!ELEMENT CASE (CLASS, FUNCTION)>
274 + <!ELEMENT CLASS (#PCDATA)>
275 +
276 + <!-- adding random ENTITY statement, as this is typical DTD content -->
277 + <!ENTITY unite "&#x222a;">
278 +
279 + <!ATTLIST CASE CLASS CDATA #REQUIRED>
280 +]>
281 +<TEST>
282 + <CASE>
283 + <CLASS>tst_QXmlStream</CLASS>
284 + </CASE>
285 + <!-- invalid DTD in XML body follows -->
286 + <!DOCTYPE DTDTEST [
287 + <!ELEMENT RESULT (CASE+)>
288 + <!ATTLIST RESULT OUTPUT CDATA #REQUIRED>
289 + ]>
290 +</TEST>
291 diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml
292 new file mode 100644
293 index 0000000000..cd398c0f9f
294 --- /dev/null
295 +++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml
296 @@ -0,0 +1,20 @@
297 +<!DOCTYPE TEST [
298 + <!ELEMENT TESTATTRIBUTE (CASE+)>
299 + <!ELEMENT CASE (CLASS, FUNCTION, DATASET, COMMENTS)>
300 + <!ELEMENT CLASS (#PCDATA)>
301 +
302 + <!-- adding random ENTITY statements, as this is typical DTD content -->
303 + <!ENTITY iff "&hArr;">
304 +
305 + <!ATTLIST CASE CLASS CDATA #REQUIRED>
306 +]>
307 +<!-- invalid second DTD follows -->
308 +<!DOCTYPE SECOND [
309 + <!ELEMENT SECONDATTRIBUTE (#PCDATA)>
310 + <!ENTITY on "&#8728;">
311 +]>
312 +<TEST>
313 + <CASE>
314 + <CLASS>tst_QXmlStream</CLASS>
315 + </CASE>
316 +</TEST>
317 diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml
318 new file mode 100644
319 index 0000000000..1b61a3f062
320 --- /dev/null
321 +++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml
322 @@ -0,0 +1,15 @@
323 +<!DOCTYPE TEST [
324 + <!ELEMENT TESTATTRIBUTE (CASE+)>
325 + <!ELEMENT CASE (CLASS, FUNCTION, DATASET, COMMENTS)>
326 + <!ELEMENT CLASS (#PCDATA)>
327 +
328 + <!-- adding random ENTITY statements, as this is typical DTD content -->
329 + <!ENTITY unite "&#x222a;">
330 +
331 + <!ATTLIST CASE CLASS CDATA #REQUIRED>
332 +]>
333 +<TEST>
334 + <CASE>
335 + <CLASS>tst_QXmlStream</CLASS>
336 + </CASE>
337 +</TEST>
338 diff --git x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
339 index 7eb0aac5cc..ee962d3870 100644
340 --- x/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
341 +++ y/qtbase/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
342 @@ -586,6 +586,9 @@ private slots:
343
344 void entityExpansionLimit() const;
345
346 + void tokenErrorHandling_data() const;
347 + void tokenErrorHandling() const;
348 +
349 private:
350 static QByteArray readFile(const QString &filename);
351
352 @@ -1792,5 +1795,41 @@ void tst_QXmlStream::test_fastScanName() const
353 QCOMPARE(reader.error(), errorType);
354 }
355
356 +void tst_QXmlStream::tokenErrorHandling_data() const
357 +{
358 + QTest::addColumn<QString>("fileName");
359 + QTest::addColumn<QXmlStreamReader::Error>("expectedError");
360 + QTest::addColumn<QString>("errorKeyWord");
361 +
362 + constexpr auto invalid = QXmlStreamReader::Error::UnexpectedElementError;
363 + constexpr auto valid = QXmlStreamReader::Error::NoError;
364 + QTest::newRow("DtdInBody") << "dtdInBody.xml" << invalid << "DTD";
365 + QTest::newRow("multipleDTD") << "multipleDtd.xml" << invalid << "second DTD";
366 + QTest::newRow("wellFormed") << "wellFormed.xml" << valid << "";
367 +}
368 +
369 +void tst_QXmlStream::tokenErrorHandling() const
370 +{
371 + QFETCH(const QString, fileName);
372 + QFETCH(const QXmlStreamReader::Error, expectedError);
373 + QFETCH(const QString, errorKeyWord);
374 +
375 + const QDir dir(QFINDTESTDATA("tokenError"));
376 + QFile file(dir.absoluteFilePath(fileName));
377 +
378 + // Cross-compiling: File will be on host only
379 + if (!file.exists())
380 + QSKIP("Testfile not found.");
381 +
382 + file.open(QIODevice::ReadOnly);
383 + QXmlStreamReader reader(&file);
384 + while (!reader.atEnd())
385 + reader.readNext();
386 +
387 + QCOMPARE(reader.error(), expectedError);
388 + if (expectedError != QXmlStreamReader::Error::NoError)
389 + QVERIFY(reader.errorString().contains(errorKeyWord));
390 +}
391 +
392 #include "tst_qxmlstream.moc"
393 // vim: et:ts=4:sw=4:sts=4
0 From e6d25e8d3b67cf7d9601d3fdd07131280f8ff056 Mon Sep 17 00:00:00 2001
1 From: Marc Mutz <marc.mutz@qt.io>
2 Date: Sun, 4 Sep 2022 12:31:10 +0200
3 Subject: QOffsetStringArray: fix ambiguous qOffsetStringArray overloads
4
5 There are two qOffsetStringArray overloads: one in QT_NAMESPACE, the
6 other in QT_PREPEND_NAMESPACE(QtPrivate). In TUs which use using
7 namespace QtPrivate, a call to qOffsetStringArray() may become
8 ambiguous.
9
10 Fix by renaming the qOffsetStringArray() to makeOffsetStringArray().
11
12 Pick-to: 6.4 6.3 6.2
13 Change-Id: I242a969f363e230d6a8dfb048601a0c024724f6a
14 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
15 (cherry picked from commit 21c5eeba673694f865badfd137ee9fc474177ae0)
16 ---
17 src/corelib/tools/qoffsetstringarray_p.h | 4 ++--
18 1 file changed, 2 insertions(+), 2 deletions(-)
19
20 diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h
21 index 3afb5cb731..68afef57d5 100644
22 --- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h
23 +++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h
24 @@ -116,7 +116,7 @@ template <size_t KL, size_t VL> struct StaticMapEntry
25 };
26
27 template <typename StringExtractor, typename... T>
28 -constexpr auto qOffsetStringArray(StringExtractor extractString, const T &... entries)
29 +constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries)
30 {
31 constexpr size_t Count = sizeof...(T);
32 constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...);
33 @@ -140,7 +140,7 @@ template<int ... Nx>
34 constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept
35 {
36 auto extractString = [](const auto &s) -> decltype(auto) { return s; };
37 - return QtPrivate::qOffsetStringArray(extractString, QtPrivate::StaticString(strings)...);
38 + return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...);
39 }
40
41 QT_WARNING_POP
0 From 72533c561d6952e63f86f11d9e4f0c6ffe8ed5a1 Mon Sep 17 00:00:00 2001
1 From: Marc Mutz <marc.mutz@qt.io>
2 Date: Mon, 5 Sep 2022 08:59:23 +0200
3 Subject: QOffsetStringArray: fix size_t/qsizetype mismatch
4
5 The sizeof operator returns, and both minifyValue and makeStaticString
6 accept, size_t. Don't funnel it through a qsizetype variable, then,
7 but maintain it as a size_t all the way.
8
9 Pick-to: 6.4 6.3 6.2
10 Task-number: QTBUG-103533
11 Change-Id: I05c6a6c5da3d02daabbf1d25a15531c6f44a80ce
12 Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
13 (cherry picked from commit 8932eee9a652d8a325410b147955c9939278f9ed)
14 ---
15 src/corelib/tools/qoffsetstringarray_p.h | 2 +-
16 1 file changed, 1 insertion(+), 1 deletion(-)
17
18 diff --git x/qtbase/src/corelib/tools/qoffsetstringarray_p.h y/qtbase/src/corelib/tools/qoffsetstringarray_p.h
19 index 68afef57d5..fbe714aca6 100644
20 --- x/qtbase/src/corelib/tools/qoffsetstringarray_p.h
21 +++ y/qtbase/src/corelib/tools/qoffsetstringarray_p.h
22 @@ -119,7 +119,7 @@ template <typename StringExtractor, typename... T>
23 constexpr auto makeOffsetStringArray(StringExtractor extractString, const T &... entries)
24 {
25 constexpr size_t Count = sizeof...(T);
26 - constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...);
27 + constexpr size_t StringLength = (sizeof(extractString(T{})) + ...);
28 using MinifiedOffsetType = decltype(QtPrivate::minifyValue<StringLength>());
29
30 size_t offset = 0;
0 From 37c9240e9d6d295118fcabedbaaf403310af8dba Mon Sep 17 00:00:00 2001
1 From: Julian Greilich <j.greilich@gmx.de>
2 Date: Thu, 26 Jan 2023 19:19:21 +0100
3 Subject: iOS NFC: Always ensure timeout after session invalidation
4
5 iOS needs some time after invalidating a session before a new session
6 can be started. Otherwise the NFC dialog of iOS will not show up.
7
8 For restarting a session inside the iOS NearfieldManager, this was
9 already solved with a timeout of 2 seconds.
10
11 This commit fixes the case, that a user of the Nearfieldmanager
12 restarts a session manually too fast.
13
14 Change-Id: Ic91ad225a9cab13ba92523f33a19f44af68575a0
15 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
16 (cherry picked from commit 849ba86ba9a073a266219b6a39786e20f4f3ed7b)
17 (cherry picked from commit 5052cd14c28bbf0ff93c465a4e33bf1dbd48c7dd)
18 ---
19 src/nfc/qnearfieldmanager_ios.mm | 44 +++++++++++++++++++++----------
20 src/nfc/qnearfieldmanager_ios_p.h | 5 +++-
21 2 files changed, 34 insertions(+), 15 deletions(-)
22
23 diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm
24 index 6fd71451..a0651626 100644
25 --- x/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm
26 +++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios.mm
27 @@ -25,6 +25,10 @@ QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
28 connect(this, &QNearFieldManagerPrivateImpl::didInvalidateWithError,
29 this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
30 Qt::QueuedConnection);
31 +
32 + sessionTimer.setInterval(2000);
33 + sessionTimer.setSingleShot(true);
34 + connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer);
35 }
36
37 QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
38 @@ -62,7 +66,7 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access
39 if (@available(iOS 13, *))
40 if (NFCTagReaderSession.readingAvailable) {
41 detectionRunning = true;
42 - startSession();
43 + scheduleSession();
44 return true;
45 }
46 return false;
47 @@ -71,16 +75,28 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::Access
48
49 void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage)
50 {
51 - if (detectionRunning) {
52 - stopSession(errorMessage);
53 - detectionRunning = false;
54 - Q_EMIT targetDetectionStopped();
55 - }
56 + if (!detectionRunning)
57 + return;
58 +
59 + isSessionScheduled = false;
60 + stopSession(errorMessage);
61 + detectionRunning = false;
62 + Q_EMIT targetDetectionStopped();
63 }
64
65 +void QNearFieldManagerPrivateImpl::scheduleSession()
66 +{
67 + if (sessionTimer.isActive()) {
68 + isSessionScheduled = true;
69 + return;
70 + }
71 +
72 + startSession();
73 +}
74
75 void QNearFieldManagerPrivateImpl::startSession()
76 {
77 + isSessionScheduled = false;
78 if (detectionRunning)
79 if (@available(iOS 13, *))
80 [delegate startSession];
81 @@ -132,17 +148,11 @@ void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *tar
82 void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
83 {
84 clearTargets();
85 + sessionTimer.start();
86
87 if (detectionRunning && doRestart)
88 {
89 - if (!isRestarting) {
90 - isRestarting = true;
91 - using namespace std::chrono_literals;
92 - QTimer::singleShot(2s, this, [this](){
93 - isRestarting = false;
94 - startSession();
95 - });
96 - }
97 + scheduleSession();
98 return;
99 }
100
101 @@ -150,4 +160,10 @@ void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
102 Q_EMIT targetDetectionStopped();
103 }
104
105 +void QNearFieldManagerPrivateImpl::onSessionTimer()
106 +{
107 + if (isSessionScheduled)
108 + scheduleSession();
109 +}
110 +
111 QT_END_NAMESPACE
112 diff --git x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h
113 index 6aa1574e..b3668ff6 100644
114 --- x/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h
115 +++ y/qtconnectivity/src/nfc/qnearfieldmanager_ios_p.h
116 @@ -54,9 +54,11 @@ Q_SIGNALS:
117 private:
118 QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) *delegate API_AVAILABLE(ios(13.0)) = nullptr;
119 bool detectionRunning = false;
120 - bool isRestarting = false;
121 + bool isSessionScheduled = false;
122 + QTimer sessionTimer;
123 QList<QNearFieldTargetPrivateImpl *> detectedTargets;
124
125 + void scheduleSession();
126 void startSession();
127 void stopSession(const QString &error);
128 void clearTargets();
129 @@ -65,6 +67,7 @@ private Q_SLOTS:
130 void onTagDiscovered(void *target);
131 void onTargetLost(QNearFieldTargetPrivateImpl *target);
132 void onDidInvalidateWithError(bool doRestart);
133 + void onSessionTimer();
134 };
135
136
0 From 7785342c8d6fe223977958c59cd4102ed417d442 Mon Sep 17 00:00:00 2001
1 From: Semih Yavuz <semih.yavuz@qt.io>
2 Date: Wed, 18 Jan 2023 15:36:23 +0100
3 Subject: qmlformat: fix omitting some comments while reformatting
4
5 We rewrite comments associated to a node on the preVisit call
6 (if they were marked as preComment), or postVisit( if comments were
7 marked as postComments) of the reformatter. If the comment
8 associated with a patternProperty kind of node, neither of these
9 functions are called. Add missing call to previsit/postVist
10 in the pattern property node visit.
11
12 Pick-to: 6.4 6.5
13 Fixes: QTBUG-109074
14 Change-Id: If57968b3f5dbd83aa23dc2cd2bca3608ee841d49
15 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
16 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
17 (cherry picked from commit 444d4f1f3f27a81996d9cbcc0642040b68728260)
18 ---
19 src/qmldom/qqmldomreformatter.cpp | 2 ++
20 .../qmlformat/data/dontRemoveComments.formatted.qml | 13 +++++++++++++
21 .../auto/qml/qmlformat/data/dontRemoveComments.qml | 13 +++++++++++++
22 tests/auto/qml/qmlformat/tst_qmlformat.cpp | 3 +++
23 4 files changed, 31 insertions(+)
24 create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml
25 create mode 100644 tests/auto/qml/qmlformat/data/dontRemoveComments.qml
26
27 diff --git x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp
28 index bb76f8f772..3dfacfc84e 100644
29 --- x/qtdeclarative/src/qmldom/qqmldomreformatter.cpp
30 +++ y/qtdeclarative/src/qmldom/qqmldomreformatter.cpp
31 @@ -301,6 +301,7 @@ protected:
32 for (PatternPropertyList *it = ast; it; it = it->next) {
33 PatternProperty *assignment = AST::cast<PatternProperty *>(it->property);
34 if (assignment) {
35 + preVisit(assignment);
36 bool isStringLike = AST::cast<StringLiteralPropertyName *>(assignment->name)
37 || cast<IdentifierPropertyName *>(assignment->name);
38 if (isStringLike)
39 @@ -316,6 +317,7 @@ protected:
40 accept(assignment->initializer);
41 if (it->next)
42 newLine();
43 + postVisit(assignment);
44 continue;
45 }
46 PatternPropertyList *getterSetter = AST::cast<PatternPropertyList *>(it->next);
47 diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml
48 new file mode 100644
49 index 0000000000..0c7a2829c9
50 --- /dev/null
51 +++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.formatted.qml
52 @@ -0,0 +1,13 @@
53 +Item {
54 + property var test: [{
55 + // Testing
56 + "foo": "bar"
57 + }]
58 +
59 + onTestChanged: {
60 + fooBar(test, {
61 + // Testing
62 + "foo": "bar"
63 + });
64 + }
65 +}
66 diff --git x/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml
67 new file mode 100644
68 index 0000000000..1797834879
69 --- /dev/null
70 +++ y/qtdeclarative/tests/auto/qml/qmlformat/data/dontRemoveComments.qml
71 @@ -0,0 +1,13 @@
72 +Item {
73 + property var test: [{
74 +// Testing
75 + "foo": "bar"
76 + }]
77 +
78 + onTestChanged: {
79 + fooBar(test, {
80 + // Testing
81 + "foo": "bar"
82 + });
83 + }
84 +}
85 diff --git x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp
86 index 9d7beb23a7..7755095acd 100644
87 --- x/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp
88 +++ y/qtdeclarative/tests/auto/qml/qmlformat/tst_qmlformat.cpp
89 @@ -276,6 +276,9 @@ void TestQmlformat::testFormat_data()
90 QTest::newRow("forWithLet")
91 << "forWithLet.qml"
92 << "forWithLet.formatted.qml" << QStringList {} << RunOption::OnCopy;
93 + QTest::newRow("dontRemoveComments")
94 + << "dontRemoveComments.qml"
95 + << "dontRemoveComments.formatted.qml" << QStringList {} << RunOption::OnCopy;
96 }
97
98 void TestQmlformat::testFormat()
0 From 26cac8dada39c83cfcebd8b0bbcacf92f1ce9e9f Mon Sep 17 00:00:00 2001
1 From: Sami Shalayel <sami.shalayel@qt.io>
2 Date: Mon, 17 Apr 2023 18:03:09 +0200
3 Subject: QQuickItem: item stays pressed after DoubleClicks
4
5 Amends 72651a50f83aa72998822312c7b5c6235d28978f.
6 This commit decided to ignore double clicks in the virtual
7 QQuickItem::mouseDoubleClickEvent().
8 If a subclass inheriting from QQuickItem wants to not ignore
9 a double click, it should override mouseDoubleClickEvent()
10 and handle the double click event accordingly.
11
12 Fix QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) to *not*
13 call the base implementation in QQuickItem after handling a double
14 click, because QQuickItem sets that double-click MouseEvent back to
15 the ignored state.
16
17 This was leading to weird behavior on platforms with touch
18 screens like Android or IOS where buttons "got stuck" after
19 a double click.
20
21 Fixes: QTBUG-112434
22 Fixes: QTBUG-109393
23 Pick-to: 6.5
24 Change-Id: I774189fbcb356b07336f35f053e05a12c34ce602
25 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
26 Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
27 (cherry picked from commit d7fac6923a6d4e4ac7dc22458256366968acbdb3)
28 ---
29 src/quick/items/qquickmousearea.cpp | 5 ++++
30 .../data/doubleClickInMouseArea.qml | 23 +++++++++++++++++++
31 .../tst_mousearea_interop.cpp | 21 +++++++++++++++++
32 3 files changed, 49 insertions(+)
33 create mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml
34
35 diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp
36 index 75b67d01e3..db338c7ae5 100644
37 --- x/qtdeclarative/src/quick/items/qquickmousearea.cpp
38 +++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp
39 @@ -795,6 +795,11 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
40 d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
41 if (d->pressed)
42 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
43 +
44 + // do not call the base implementation if the event is accepted
45 + // because it will revert the event back to ignored state
46 + if (me.isAccepted())
47 + return;
48 }
49 QQuickItem::mouseDoubleClickEvent(event);
50 }
51 diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml
52 new file mode 100644
53 index 0000000000..e43a2f3160
54 --- /dev/null
55 +++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml
56 @@ -0,0 +1,23 @@
57 +import QtQuick
58 +import QtQuick.Controls
59 +import QtQuick.Window
60 +
61 +Rectangle {
62 + width: 200; height: 200
63 + color: mouseArea.pressed ? "red" : "orange"
64 +
65 + Popup {
66 + visible: true
67 + closePolicy: Popup.NoAutoClose
68 + width: 100
69 + height: 100
70 + contentItem: MouseArea {
71 + id: mouseArea
72 +
73 + anchors.fill: parent
74 + }
75 + background: Rectangle {
76 + color: "green"
77 + }
78 + }
79 +}
80 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
81 index c4059a1fbd..bc0dfbc736 100644
82 --- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
83 +++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
84 @@ -31,6 +31,7 @@ private slots:
85 void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch();
86 void hoverHandlerDoesntHoverOnPress();
87 void doubleClickInMouseAreaWithDragHandlerInGrandparent();
88 + void doubleClickInMouseArea();
89
90 private:
91 void createView(QScopedPointer<QQuickView> &window, const char *fileName);
92 @@ -203,6 +204,26 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent()
93 QCOMPARE(dragActiveSpy.count(), 0);
94 }
95
96 +void tst_MouseAreaInterop::doubleClickInMouseArea()
97 +{
98 + QQuickView window;
99 + QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml")));
100 +
101 + auto *ma = window.rootObject()->findChild<QQuickMouseArea *>();
102 + QVERIFY(ma);
103 + QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked);
104 + QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold);
105 + QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint();
106 +
107 + // check with normal double click
108 + QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p);
109 + QCOMPARE(doubleClickSpy.count(), 1);
110 +
111 + // wait enough time for a wrong long press to happen
112 + QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10);
113 + QCOMPARE(longPressSpy.count(), 0);
114 +}
115 +
116 QTEST_MAIN(tst_MouseAreaInterop)
117
118 #include "tst_mousearea_interop.moc"
0 From 65fd0af4aece6028e82e018c50583aed706dd525 Mon Sep 17 00:00:00 2001
1 From: Shawn Rutledge <shawn.rutledge@qt.io>
2 Date: Mon, 12 Jun 2023 22:53:23 +0200
3 Subject: MouseArea: don't ignore double-click events
4
5 In 72651a50f83aa72998822312c7b5c6235d28978f
6 QQuickItem::mouseDoubleClickEvent() started to ignore double-clicks by
7 default, which is consistent with the fact that it ignores the other
8 pointer event types. But now we have to worry about subclasses that
9 override mouseDoubleClickEvent() and call the base class implementation.
10
11 d7fac6923a6d4e4ac7dc22458256366968acbdb3 tried to fix it but neglected
12 the case when the MouseArea does not have an onDoubleClicked signal
13 handling script. Since the QQuickMouseEvent object that we emit to QML
14 won't be accepted if isDoubleClickConnected() is false, and since the
15 code before 72651a50f83aa72998822312c7b5c6235d28978f was leaving the
16 event accepted regardless of whether QQuickMouseEvent was accepted, we
17 should not need to check it now either. Perhaps we should care about the
18 case when onDoubleClicked sets accepted to false, but so far that
19 doesn't seem very useful either: if you accept the press, a parent
20 MouseArea will not see either the press or the double-click; if you
21 ignore the press, you won't see the double-click, and a parent MouseArea
22 will see both by default. tst_QQuickMouseArea::clickThrough() tests
23 accepted = false in onDoubleClicked but not onPressed, and only with
24 mouse, not touch.
25
26 Added tst_QQuickMouseArea::doubleTap(); also moved the autotest from
27 d7fac6923a6d4e4ac7dc22458256366968acbdb3 which has nothing to do with
28 pointer handlers.
29
30 Fixes: QTBUG-112434
31 Fixes: QTBUG-109393
32 Pick-to: 6.6 6.5 6.5.2
33 Change-Id: I426827c20cdb2373e77744987dffba59cd941edc
34 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
35 Reviewed-by: Doris Verria <doris.verria@qt.io>
36 (cherry picked from commit 35b5511189f0f9dbb8cfd8b3ec97cca2c65b3e2e)
37 ---
38 src/quick/items/qquickmousearea.cpp | 6 +-
39 .../data/doubleClickInMouseArea.qml | 23 --------
40 .../tst_mousearea_interop.cpp | 21 -------
41 .../qquickmousearea/tst_qquickmousearea.cpp | 56 +++++++++++++++++++
42 .../data/doubleClickInMouseArea.qml | 23 ++++++++
43 .../qquickpopup/tst_qquickpopup.cpp | 22 ++++++++
44 6 files changed, 103 insertions(+), 48 deletions(-)
45 delete mode 100644 tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml
46 create mode 100644 tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml
47
48 diff --git x/qtdeclarative/src/quick/items/qquickmousearea.cpp y/qtdeclarative/src/quick/items/qquickmousearea.cpp
49 index db338c7ae5..de283672cc 100644
50 --- x/qtdeclarative/src/quick/items/qquickmousearea.cpp
51 +++ y/qtdeclarative/src/quick/items/qquickmousearea.cpp
52 @@ -796,10 +796,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
53 if (d->pressed)
54 d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
55
56 - // do not call the base implementation if the event is accepted
57 - // because it will revert the event back to ignored state
58 - if (me.isAccepted())
59 - return;
60 + // Do not call the base implementation: we don't want to call event->ignore().
61 + return;
62 }
63 QQuickItem::mouseDoubleClickEvent(event);
64 }
65 diff --git x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml
66 deleted file mode 100644
67 index e43a2f3160..0000000000
68 --- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/data/doubleClickInMouseArea.qml
69 +++ /dev/null
70 @@ -1,23 +0,0 @@
71 -import QtQuick
72 -import QtQuick.Controls
73 -import QtQuick.Window
74 -
75 -Rectangle {
76 - width: 200; height: 200
77 - color: mouseArea.pressed ? "red" : "orange"
78 -
79 - Popup {
80 - visible: true
81 - closePolicy: Popup.NoAutoClose
82 - width: 100
83 - height: 100
84 - contentItem: MouseArea {
85 - id: mouseArea
86 -
87 - anchors.fill: parent
88 - }
89 - background: Rectangle {
90 - color: "green"
91 - }
92 - }
93 -}
94 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
95 index bc0dfbc736..c4059a1fbd 100644
96 --- x/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
97 +++ y/qtdeclarative/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
98 @@ -31,7 +31,6 @@ private slots:
99 void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch();
100 void hoverHandlerDoesntHoverOnPress();
101 void doubleClickInMouseAreaWithDragHandlerInGrandparent();
102 - void doubleClickInMouseArea();
103
104 private:
105 void createView(QScopedPointer<QQuickView> &window, const char *fileName);
106 @@ -204,26 +203,6 @@ void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent()
107 QCOMPARE(dragActiveSpy.count(), 0);
108 }
109
110 -void tst_MouseAreaInterop::doubleClickInMouseArea()
111 -{
112 - QQuickView window;
113 - QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml")));
114 -
115 - auto *ma = window.rootObject()->findChild<QQuickMouseArea *>();
116 - QVERIFY(ma);
117 - QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked);
118 - QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold);
119 - QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint();
120 -
121 - // check with normal double click
122 - QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p);
123 - QCOMPARE(doubleClickSpy.count(), 1);
124 -
125 - // wait enough time for a wrong long press to happen
126 - QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10);
127 - QCOMPARE(longPressSpy.count(), 0);
128 -}
129 -
130 QTEST_MAIN(tst_MouseAreaInterop)
131
132 #include "tst_mousearea_interop.moc"
133 diff --git x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
134 index 7da0913e0c..0c7528320e 100644
135 --- x/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
136 +++ y/qtdeclarative/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
137 @@ -95,6 +95,7 @@ private slots:
138 void pressedCanceledOnWindowDeactivate();
139 void doubleClick_data() { acceptedButton_data(); }
140 void doubleClick();
141 + void doubleTap();
142 void clickTwice_data() { acceptedButton_data(); }
143 void clickTwice();
144 void invalidClick_data() { rejectedButton_data(); }
145 @@ -929,6 +930,61 @@ void tst_QQuickMouseArea::doubleClick()
146 QCOMPARE(window.rootObject()->property("released").toInt(), 2);
147 }
148
149 +void tst_QQuickMouseArea::doubleTap() // QTBUG-112434
150 +{
151 + QQuickView window;
152 + QVERIFY(QQuickTest::showView(window, testFileUrl("doubleclick.qml")));
153 +
154 + QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mousearea");
155 + QVERIFY(mouseArea);
156 + QPoint p1 = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint();
157 +
158 + QTest::touchEvent(&window, device).press(0, p1);
159 + QQuickTouchUtils::flush(&window);
160 + QTest::touchEvent(&window, device).release(0, p1);
161 + QQuickTouchUtils::flush(&window);
162 + QCOMPARE(window.rootObject()->property("released").toInt(), 1);
163 + QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
164 +
165 + p1 += QPoint(1, -1); // movement less than QPlatformTheme::TouchDoubleTapDistance
166 + QTest::touchEvent(&window, device).press(1, p1); // touchpoint ID is different the second time
167 + QQuickTouchUtils::flush(&window);
168 + QCOMPARE(mouseArea->isPressed(), true);
169 + // at this time QQuickDeliveryAgentPrivate::deliverTouchAsMouse() synthesizes the double-click event
170 + QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
171 +
172 + QTest::touchEvent(&window, device).release(1, p1);
173 + QQuickTouchUtils::flush(&window);
174 + QCOMPARE(window.rootObject()->property("released").toInt(), 2);
175 + QCOMPARE(mouseArea->isPressed(), false);
176 + QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
177 +
178 + // now tap with two fingers simultaneously: only one of them generates synth-mouse
179 + QPoint p2 = p1 + QPoint(50, 5);
180 + QTest::touchEvent(&window, device).press(2, p1).press(3, p2);
181 + QQuickTouchUtils::flush(&window);
182 + QCOMPARE(mouseArea->isPressed(), true);
183 + QTest::touchEvent(&window, device).release(2, p1).release(3, p2);
184 + QQuickTouchUtils::flush(&window);
185 + QCOMPARE(window.rootObject()->property("released").toInt(), 3);
186 + QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
187 + QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
188 + QCOMPARE(mouseArea->isPressed(), false);
189 +
190 + // tap with two fingers simultaneously again: get another double-click from one point
191 + p1 -= QPoint(1, -1);
192 + p2 += QPoint(1, -1);
193 + QTest::touchEvent(&window, device).press(4, p1).press(5, p2);
194 + QQuickTouchUtils::flush(&window);
195 + QCOMPARE(mouseArea->isPressed(), true);
196 + QTest::touchEvent(&window, device).release(4, p1).release(5, p2);
197 + QQuickTouchUtils::flush(&window);
198 + QCOMPARE(window.rootObject()->property("released").toInt(), 4);
199 + QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
200 + QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 2);
201 + QCOMPARE(mouseArea->isPressed(), false); // make sure it doesn't get stuck
202 +}
203 +
204 // QTBUG-14832
205 void tst_QQuickMouseArea::clickTwice()
206 {
207 diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml
208 new file mode 100644
209 index 0000000000..e43a2f3160
210 --- /dev/null
211 +++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/data/doubleClickInMouseArea.qml
212 @@ -0,0 +1,23 @@
213 +import QtQuick
214 +import QtQuick.Controls
215 +import QtQuick.Window
216 +
217 +Rectangle {
218 + width: 200; height: 200
219 + color: mouseArea.pressed ? "red" : "orange"
220 +
221 + Popup {
222 + visible: true
223 + closePolicy: Popup.NoAutoClose
224 + width: 100
225 + height: 100
226 + contentItem: MouseArea {
227 + id: mouseArea
228 +
229 + anchors.fill: parent
230 + }
231 + background: Rectangle {
232 + color: "green"
233 + }
234 + }
235 +}
236 diff --git x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
237 index ab20bd71b4..0e8ee05725 100644
238 --- x/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
239 +++ y/qtdeclarative/tests/auto/quickcontrols2/qquickpopup/tst_qquickpopup.cpp
240 @@ -10,6 +10,7 @@
241 #include <QtGui/qpa/qplatformintegration.h>
242 #include <QtGui/private/qguiapplication_p.h>
243 #include <QtQuick/qquickview.h>
244 +#include <QtQuick/private/qquickmousearea_p.h>
245 #include <QtQuick/private/qquickpalette_p.h>
246 #include <QtQuickTestUtils/private/qmlutils_p.h>
247 #include <QtQuickTestUtils/private/viewtestutils_p.h>
248 @@ -89,6 +90,7 @@ private slots:
249 void dimmerContainmentMask();
250 void shrinkPopupThatWasLargerThanWindow_data();
251 void shrinkPopupThatWasLargerThanWindow();
252 + void doubleClickInMouseArea();
253
254 private:
255 static bool hasWindowActivation();
256 @@ -1928,6 +1930,26 @@ void tst_QQuickPopup::shrinkPopupThatWasLargerThanWindow()
257 .arg(popup->height()).arg(window->height())));
258 }
259
260 +void tst_QQuickPopup::doubleClickInMouseArea()
261 +{
262 + QQuickView window;
263 + QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickInMouseArea.qml")));
264 +
265 + auto *ma = window.rootObject()->findChild<QQuickMouseArea *>();
266 + QVERIFY(ma);
267 + QSignalSpy doubleClickSpy(ma, &QQuickMouseArea::doubleClicked);
268 + QSignalSpy longPressSpy(ma, &QQuickMouseArea::pressAndHold);
269 + QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint();
270 +
271 + // check with normal double click
272 + QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p);
273 + QCOMPARE(doubleClickSpy.count(), 1);
274 +
275 + // wait enough time for a wrong long press to happen
276 + QTest::qWait(QGuiApplication::styleHints()->mousePressAndHoldInterval() + 10);
277 + QCOMPARE(longPressSpy.count(), 0);
278 +}
279 +
280 QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
281
282 #include "tst_qquickpopup.moc"
0 From abe6296550b5531a129b7d4a21466cdc50dbb2e0 Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= <aklitzing@gmail.com>
2 Date: Tue, 12 Apr 2022 10:21:19 +0200
3 Subject: Make qtdeclarative optional for CONTAINER_SDK
4
5 Change-Id: Ia25b91ea5e3716aef4cb096de1052267b70e343d
6 ---
7 dependencies.yaml | 2 +-
8 1 file changed, 1 insertion(+), 1 deletion(-)
9
10 diff --git x/qtscxml/dependencies.yaml y/qtscxml/dependencies.yaml
11 index ee6f92e0..73755512 100644
12 --- x/qtscxml/dependencies.yaml
13 +++ y/qtscxml/dependencies.yaml
14 @@ -4,4 +4,4 @@ dependencies:
15 required: true
16 ../qtdeclarative:
17 ref: a514640b2a38391fceaaac3ca01b390ad3d62f31
18 - required: true
19 + required: false
0 From 2fa2cbc5c55e862cee7fc495edc444c46d4193ee Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= <aklitzing@gmail.com>
2 Date: Tue, 12 Apr 2022 11:39:12 +0200
3 Subject: Disable qtscxml library
4
5 ---
6 src/CMakeLists.txt | 4 ++--
7 tools/CMakeLists.txt | 2 +-
8 2 files changed, 3 insertions(+), 3 deletions(-)
9
10 diff --git x/qtscxml/src/CMakeLists.txt y/qtscxml/src/CMakeLists.txt
11 index f1b7c2b9..7e28acc2 100644
12 --- x/qtscxml/src/CMakeLists.txt
13 +++ y/qtscxml/src/CMakeLists.txt
14 @@ -1,8 +1,8 @@
15
16 -add_subdirectory(scxml)
17 +#add_subdirectory(scxml)
18 add_subdirectory(statemachine)
19 if(TARGET Qt::Qml)
20 add_subdirectory(statemachineqml)
21 - add_subdirectory(scxmlqml)
22 +# add_subdirectory(scxmlqml)
23 endif()
24 add_subdirectory(plugins)
25 diff --git x/qtscxml/tools/CMakeLists.txt y/qtscxml/tools/CMakeLists.txt
26 index 9726a783..956f9048 100644
27 --- x/qtscxml/tools/CMakeLists.txt
28 +++ y/qtscxml/tools/CMakeLists.txt
29 @@ -1,4 +1,4 @@
30
31 if(QT_FEATURE_commandlineparser)
32 - add_subdirectory(qscxmlc)
33 + #add_subdirectory(qscxmlc)
34 endif()
0 From c3b8e687ca723262f15f31b181a3e5db847afb68 Mon Sep 17 00:00:00 2001
1 From: =?UTF-8?q?Robert=20L=C3=B6hning?= <robert.loehning@qt.io>
2 Date: Mon, 24 Apr 2023 15:27:17 +0200
3 Subject: QSvgFont: Initialize used member, remove unused
4
5 Credit to OSS-Fuzz
6
7 [ChangeLog][QtSvg] Fixed undefined behavior from using uninitialized
8 variable.
9
10 Pick-to: 6.5 6.2 5.15
11 Coverity-Id: 22618
12 Change-Id: Id52277bb0e2845f4d342e187dbb8093e9276b70c
13 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
14 (cherry picked from commit ff22c3ccf8ccf813fdcfda23f7740ba73ba5ce0a)
15 ---
16 src/svg/qsvgfont_p.h | 5 ++---
17 src/svg/qsvghandler.cpp | 2 +-
18 2 files changed, 3 insertions(+), 4 deletions(-)
19
20 diff --git x/qtsvg/src/svg/qsvgfont_p.h y/qtsvg/src/svg/qsvgfont_p.h
21 index a7cc98b..9cf3dfe 100644
22 --- x/qtsvg/src/svg/qsvgfont_p.h
23 +++ y/qtsvg/src/svg/qsvgfont_p.h
24 @@ -38,6 +38,7 @@ public:
25 class Q_SVG_PRIVATE_EXPORT QSvgFont : public QSvgRefCounted
26 {
27 public:
28 + static constexpr qreal DEFAULT_UNITS_PER_EM = 1000;
29 QSvgFont(qreal horizAdvX);
30
31 void setFamilyName(const QString &name);
32 @@ -50,9 +51,7 @@ public:
33 void draw(QPainter *p, const QPointF &point, const QString &str, qreal pixelSize, Qt::Alignment alignment) const;
34 public:
35 QString m_familyName;
36 - qreal m_unitsPerEm;
37 - qreal m_ascent;
38 - qreal m_descent;
39 + qreal m_unitsPerEm = DEFAULT_UNITS_PER_EM;
40 qreal m_horizAdvX;
41 QHash<QChar, QSvgGlyph> m_glyphs;
42 };
43 diff --git x/qtsvg/src/svg/qsvghandler.cpp y/qtsvg/src/svg/qsvghandler.cpp
44 index e88e83b..1e2b2fc 100644
45 --- x/qtsvg/src/svg/qsvghandler.cpp
46 +++ y/qtsvg/src/svg/qsvghandler.cpp
47 @@ -2622,7 +2622,7 @@ static bool parseFontFaceNode(QSvgStyleProperty *parent,
48
49 qreal unitsPerEm = toDouble(unitsPerEmStr);
50 if (!unitsPerEm)
51 - unitsPerEm = 1000;
52 + unitsPerEm = QSvgFont::DEFAULT_UNITS_PER_EM;
53
54 if (!name.isEmpty())
55 font->setFamilyName(name);
0 From d52894c2b13954d13ff940ba6b36e5cab7fbf3ac Mon Sep 17 00:00:00 2001
1 From: Jan Moeller <jan.moeller@governikus.de>
2 Date: Mon, 14 Feb 2022 13:46:46 +0100
3 Subject: Disable linguist but keep translation tools
4
5 Change-Id: I1c54eb0e7bb86ec0861b54b5abe753c86bb57dd9
6 ---
7 src/linguist/CMakeLists.txt | 3 ---
8 1 file changed, 3 deletions(-)
9
10 diff --git x/qttools/src/linguist/CMakeLists.txt y/qttools/src/linguist/CMakeLists.txt
11 index 16ff9f559..fde23b0c4 100644
12 --- x/qttools/src/linguist/CMakeLists.txt
13 +++ y/qttools/src/linguist/CMakeLists.txt
14 @@ -14,9 +14,6 @@ add_subdirectory(lrelease)
15 add_subdirectory(lrelease-pro)
16 add_subdirectory(lupdate)
17 add_subdirectory(lupdate-pro)
18 -if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png)
19 - add_subdirectory(linguist)
20 -endif()
21
22 # special case begin
23 # Create a fake module that would emulate the Qt5::LinguistTools CMake Config package
0 From 2cbc188e4facb12153f37a501f14384ec733c944 Mon Sep 17 00:00:00 2001
1 From: Lars Schmertmann <Lars.Schmertmann@governikus.de>
2 Date: Wed, 9 Nov 2022 09:49:38 +0100
3 Subject: Revert "Move UiTools and UiPlugin modules to a upper level
4 sub-directory"
5
6 This partially reverts commit 6af882fa2f45f73ec2ba4066d5ae3ad072d0c5ee.
7
8 Change-Id: I247e2189577b74d813a210ace0b49d672a90975e
9 ---
10 src/CMakeLists.txt | 5 -
11 src/designer/src/CMakeLists.txt | 2 +
12 .../src/designer/doc/qtdesigner.qdocconf | 4 +-
13 src/designer/src/uiplugin/CMakeLists.txt | 27 +
14 src/designer/src/uiplugin/customwidget.h | 62 ++
15 src/designer/src/uiplugin/customwidget.qdoc | 269 ++++++
16 .../src/uiplugin/qdesignerexportwidget.h | 24 +
17 src/designer/src/uitools/CMakeLists.txt | 46 +
18 src/designer/src/uitools/qtuitoolsglobal.h | 23 +
19 src/designer/src/uitools/quiloader.cpp | 914 ++++++++++++++++++
20 src/designer/src/uitools/quiloader.h | 61 ++
21 src/designer/src/uitools/quiloader_p.h | 77 ++
22 src/uiplugin/CMakeLists.txt | 27 -
23 src/uiplugin/customwidget.h | 62 --
24 src/uiplugin/customwidget.qdoc | 269 ------
25 src/uiplugin/qdesignerexportwidget.h | 24 -
26 src/uitools/CMakeLists.txt | 47 -
27 src/uitools/qtuitoolsglobal.h | 24 -
28 src/uitools/quiloader.cpp | 914 ------------------
29 src/uitools/quiloader.h | 61 --
30 src/uitools/quiloader_p.h | 77 --
31 sync.profile | 4 +-
32 22 files changed, 1509 insertions(+), 1514 deletions(-)
33 create mode 100644 src/designer/src/uiplugin/CMakeLists.txt
34 create mode 100644 src/designer/src/uiplugin/customwidget.h
35 create mode 100644 src/designer/src/uiplugin/customwidget.qdoc
36 create mode 100644 src/designer/src/uiplugin/qdesignerexportwidget.h
37 create mode 100644 src/designer/src/uitools/CMakeLists.txt
38 create mode 100644 src/designer/src/uitools/qtuitoolsglobal.h
39 create mode 100644 src/designer/src/uitools/quiloader.cpp
40 create mode 100644 src/designer/src/uitools/quiloader.h
41 create mode 100644 src/designer/src/uitools/quiloader_p.h
42 delete mode 100644 src/uiplugin/CMakeLists.txt
43 delete mode 100644 src/uiplugin/customwidget.h
44 delete mode 100644 src/uiplugin/customwidget.qdoc
45 delete mode 100644 src/uiplugin/qdesignerexportwidget.h
46 delete mode 100644 src/uitools/CMakeLists.txt
47 delete mode 100644 src/uitools/qtuitoolsglobal.h
48 delete mode 100644 src/uitools/quiloader.cpp
49 delete mode 100644 src/uitools/quiloader.h
50 delete mode 100644 src/uitools/quiloader_p.h
51
52 diff --git x/qttools/src/CMakeLists.txt y/qttools/src/CMakeLists.txt
53 index b42cd4946..cb0c21a70 100644
54 --- x/qttools/src/CMakeLists.txt
55 +++ y/qttools/src/CMakeLists.txt
56 @@ -21,11 +21,6 @@ qt_exclude_tool_directories_from_default_target(
57 qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake")
58 # special case end
59
60 -if(TARGET Qt::Widgets)
61 - add_subdirectory(uiplugin)
62 - add_subdirectory(uitools)
63 -endif()
64 -
65 add_subdirectory(global) # special case add as first directory
66 if(QT_FEATURE_linguist)
67 add_subdirectory(linguist)
68 diff --git x/qttools/src/designer/src/CMakeLists.txt y/qttools/src/designer/src/CMakeLists.txt
69 index 31fc1734e..32fb45160 100644
70 --- x/qttools/src/designer/src/CMakeLists.txt
71 +++ y/qttools/src/designer/src/CMakeLists.txt
72 @@ -8,6 +8,8 @@ qt_exclude_tool_directories_from_default_target(
73 plugins
74 )
75
76 +add_subdirectory(uiplugin)
77 +add_subdirectory(uitools)
78 if(QT_FEATURE_process)
79 add_subdirectory(lib)
80 add_subdirectory(components)
81 diff --git x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf
82 index 75c8c78dd..964fb47ed 100644
83 --- x/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf
84 +++ y/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf
85 @@ -28,11 +28,11 @@ qhp.QtDesigner.subprojects.classes.sortPages = true
86 language = Cpp
87
88 headerdirs += .. \
89 - ../../../../uiplugin \
90 + ../../uiplugin \
91 ../../lib
92
93 sourcedirs = .. \
94 - ../../../../uiplugin \
95 + ../../uiplugin \
96 ../../lib
97
98 exampledirs = ../../../../../examples/designer \
99 diff --git x/qttools/src/designer/src/uiplugin/CMakeLists.txt y/qttools/src/designer/src/uiplugin/CMakeLists.txt
100 new file mode 100644
101 index 000000000..4fedf8e33
102 --- /dev/null
103 +++ y/qttools/src/designer/src/uiplugin/CMakeLists.txt
104 @@ -0,0 +1,27 @@
105 +# Generated from uiplugin.pro.
106 +
107 +#####################################################################
108 +## UiPlugin Module:
109 +#####################################################################
110 +
111 +qt_internal_add_module(UiPlugin
112 + NO_PRIVATE_MODULE
113 + HEADER_MODULE
114 + QMAKE_MODULE_CONFIG designer_defines
115 + PUBLIC_LIBRARIES
116 + Qt::Core
117 + Qt::Gui
118 + Qt::Widgets
119 +)
120 +
121 +# special case begin
122 +set(is_plugin "$<TARGET_PROPERTY:QT_PLUGIN_CLASS_NAME>")
123 +target_compile_definitions(
124 + UiPlugin
125 + INTERFACE
126 + $<$<BOOL:${is_plugin}>:QDESIGNER_EXPORT_WIDGETS>
127 +)
128 +# special case end
129 +
130 +#### Keys ignored in scope 1:.:.:uiplugin.pro:<TRUE>:
131 +# MODULE_CONFIG = "designer_defines"
132 diff --git x/qttools/src/designer/src/uiplugin/customwidget.h y/qttools/src/designer/src/uiplugin/customwidget.h
133 new file mode 100644
134 index 000000000..2a47a32f8
135 --- /dev/null
136 +++ y/qttools/src/designer/src/uiplugin/customwidget.h
137 @@ -0,0 +1,62 @@
138 +// Copyright (C) 2016 The Qt Company Ltd.
139 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
140 +
141 +#ifndef CUSTOMWIDGET_H
142 +#define CUSTOMWIDGET_H
143 +
144 +#include <QtCore/qobject.h>
145 +#include <QtCore/qstring.h>
146 +#include <QtGui/qicon.h>
147 +
148 +QT_BEGIN_NAMESPACE
149 +
150 +class QWidget;
151 +class QDesignerFormEditorInterface;
152 +
153 +class QDesignerCustomWidgetInterface
154 +{
155 +public:
156 + virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable
157 +
158 + virtual QString name() const = 0;
159 + virtual QString group() const = 0;
160 + virtual QString toolTip() const = 0;
161 + virtual QString whatsThis() const = 0;
162 + virtual QString includeFile() const = 0;
163 + virtual QIcon icon() const = 0;
164 +
165 + virtual bool isContainer() const = 0;
166 +
167 + virtual QWidget *createWidget(QWidget *parent) = 0;
168 +
169 + virtual bool isInitialized() const { return false; }
170 + virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); }
171 +
172 + virtual QString domXml() const
173 + {
174 + return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
175 + .arg(name()).arg(name().toLower());
176 + }
177 +
178 + virtual QString codeTemplate() const { return QString(); }
179 +};
180 +
181 +#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface"
182 +
183 +Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid)
184 +
185 +class QDesignerCustomWidgetCollectionInterface
186 +{
187 +public:
188 + virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable
189 +
190 + virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const = 0;
191 +};
192 +
193 +#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface"
194 +
195 +Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid)
196 +
197 +QT_END_NAMESPACE
198 +
199 +#endif // CUSTOMWIDGET_H
200 diff --git x/qttools/src/designer/src/uiplugin/customwidget.qdoc y/qttools/src/designer/src/uiplugin/customwidget.qdoc
201 new file mode 100644
202 index 000000000..557e9a454
203 --- /dev/null
204 +++ y/qttools/src/designer/src/uiplugin/customwidget.qdoc
205 @@ -0,0 +1,269 @@
206 +// Copyright (C) 2016 The Qt Company Ltd.
207 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
208 +
209 +/*!
210 + \class QDesignerCustomWidgetInterface
211 +
212 + \brief The QDesignerCustomWidgetInterface class enables Qt Designer
213 + to access and construct custom widgets.
214 +
215 + \inmodule QtDesigner
216 +
217 + QDesignerCustomWidgetInterface provides a custom widget with an
218 + interface. The class contains a set of functions that must be subclassed
219 + to return basic information about the widget, such as its class name and
220 + the name of its header file. Other functions must be implemented to
221 + initialize the plugin when it is loaded, and to construct instances of
222 + the custom widget for \QD to use.
223 +
224 + When implementing a custom widget you must subclass
225 + QDesignerCustomWidgetInterface to expose your widget to \QD. For
226 + example, this is the declaration for the plugin used in the
227 + \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that
228 + enables an analog clock custom widget to be used by \QD:
229 +
230 + \snippet customwidgetplugin/customwidgetplugin.h 0
231 +
232 + Note that the only part of the class definition that is specific
233 + to this particular custom widget is the class name. In addition,
234 + since we are implementing an interface, we must ensure that it's
235 + made known to the meta object system using the Q_INTERFACES()
236 + macro. This enables \QD to use the qobject_cast() function to
237 + query for supported interfaces using nothing but a QObject
238 + pointer.
239 +
240 + After \QD loads a custom widget plugin, it calls the interface's
241 + initialize() function to enable it to set up any resources that it
242 + may need. This function is called with a QDesignerFormEditorInterface
243 + parameter that provides the plugin with a gateway to all of \QD's API.
244 +
245 + \QD constructs instances of the custom widget by calling the plugin's
246 + createWidget() function with a suitable parent widget. Plugins must
247 + construct and return an instance of a custom widget with the specified
248 + parent widget.
249 +
250 + Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA()
251 + macro. For example, if a library called \c libcustomwidgetplugin.so
252 + (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget
253 + class called \c MyCustomWidget, we can export it by adding the
254 + following line to the file containing the plugin header:
255 +
256 + \snippet plugins/doc_src_qtdesigner.cpp 14
257 +
258 + This macro ensures that \QD can access and construct the custom widget.
259 + Without this macro, there is no way for \QD to use it.
260 +
261 + When implementing a custom widget plugin, you build it as a
262 + separate library. If you want to include several custom widget
263 + plugins in the same library, you must in addition subclass
264 + QDesignerCustomWidgetCollectionInterface.
265 +
266 + \warning If your custom widget plugin contains QVariant
267 + properties, be aware that only the following \l
268 + {QVariant::Type}{types} are supported:
269 +
270 + \list
271 + \li QVariant::ByteArray
272 + \li QVariant::Bool
273 + \li QVariant::Color
274 + \li QVariant::Cursor
275 + \li QVariant::Date
276 + \li QVariant::DateTime
277 + \li QVariant::Double
278 + \li QVariant::Int
279 + \li QVariant::Point
280 + \li QVariant::Rect
281 + \li QVariant::Size
282 + \li QVariant::SizePolicy
283 + \li QVariant::String
284 + \li QVariant::Time
285 + \li QVariant::UInt
286 + \endlist
287 +
288 + For a complete example using the QDesignerCustomWidgetInterface
289 + class, see the \l {customwidgetplugin}{Custom Widget
290 + Example}. The example shows how to create a custom widget plugin
291 + for \QD.
292 +
293 + \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer}
294 +*/
295 +
296 +/*!
297 + \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface()
298 +
299 + Destroys the custom widget interface.
300 +*/
301 +
302 +/*!
303 + \fn QString QDesignerCustomWidgetInterface::name() const
304 +
305 + Returns the class name of the custom widget supplied by the interface.
306 +
307 + The name returned \e must be identical to the class name used for the
308 + custom widget.
309 +*/
310 +
311 +/*!
312 + \fn QString QDesignerCustomWidgetInterface::group() const
313 +
314 + Returns the name of the group to which the custom widget belongs.
315 +*/
316 +
317 +/*!
318 + \fn QString QDesignerCustomWidgetInterface::toolTip() const
319 +
320 + Returns a short description of the widget that can be used by \QD
321 + in a tool tip.
322 +*/
323 +
324 +/*!
325 + \fn QString QDesignerCustomWidgetInterface::whatsThis() const
326 +
327 + Returns a description of the widget that can be used by \QD in
328 + "What's This?" help for the widget.
329 +*/
330 +
331 +/*!
332 + \fn QString QDesignerCustomWidgetInterface::includeFile() const
333 +
334 + Returns the path to the include file that \l uic uses when
335 + creating code for the custom widget.
336 +*/
337 +
338 +/*!
339 + \fn QIcon QDesignerCustomWidgetInterface::icon() const
340 +
341 + Returns the icon used to represent the custom widget in \QD's
342 + widget box.
343 +*/
344 +
345 +/*!
346 + \fn bool QDesignerCustomWidgetInterface::isContainer() const
347 +
348 + Returns true if the custom widget is intended to be used as a
349 + container; otherwise returns false.
350 +
351 + Most custom widgets are not used to hold other widgets, so their
352 + implementations of this function will return false, but custom
353 + containers will return true to ensure that they behave correctly
354 + in \QD.
355 +*/
356 +
357 +/*!
358 + \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent)
359 +
360 + Returns a new instance of the custom widget, with the given \a
361 + parent.
362 +*/
363 +
364 +/*!
365 + \fn bool QDesignerCustomWidgetInterface::isInitialized() const
366 +
367 + Returns true if the widget has been initialized; otherwise returns
368 + false.
369 +
370 + \sa initialize()
371 +*/
372 +
373 +/*!
374 + \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor)
375 +
376 + Initializes the widget for use with the specified \a formEditor
377 + interface.
378 +
379 + \sa isInitialized()
380 +*/
381 +
382 +/*!
383 + \fn QString QDesignerCustomWidgetInterface::domXml() const
384 +
385 + Returns the XML that is used to describe the custom widget's
386 + properties to \QD.
387 +*/
388 +
389 +/*!
390 + \fn QString QDesignerCustomWidgetInterface::codeTemplate() const
391 +
392 + This function is reserved for future use by \QD.
393 +
394 + \omit
395 + Returns the code template that \QD includes in forms that contain
396 + the custom widget when they are saved.
397 + \endomit
398 +*/
399 +
400 +/*!
401 + \macro QDESIGNER_WIDGET_EXPORT
402 + \relates QDesignerCustomWidgetInterface
403 + \since 4.1
404 +
405 + This macro is used when defining custom widgets to ensure that they are
406 + correctly exported from plugins for use with \QD.
407 +
408 + On some platforms, the symbols required by \QD to create new widgets
409 + are removed from plugins by the build system, making them unusable.
410 + Using this macro ensures that the symbols are retained on those platforms,
411 + and has no side effects on other platforms.
412 +
413 + For example, the \l{worldtimeclockplugin}{World Time Clock Plugin}
414 + example exports a custom widget class with the following declaration:
415 +
416 + \snippet worldtimeclockplugin/worldtimeclock.h 0
417 + \dots
418 + \snippet worldtimeclockplugin/worldtimeclock.h 2
419 +
420 + \sa {Creating Custom Widgets for Qt Designer}
421 +*/
422 +
423 +
424 +
425 +
426 +
427 +/*!
428 + \class QDesignerCustomWidgetCollectionInterface
429 +
430 + \brief The QDesignerCustomWidgetCollectionInterface class allows
431 + you to include several custom widgets in one single library.
432 +
433 + \inmodule QtDesigner
434 +
435 + When implementing a custom widget plugin, you build it as a
436 + separate library. If you want to include several custom widget
437 + plugins in the same library, you must in addition subclass
438 + QDesignerCustomWidgetCollectionInterface.
439 +
440 + QDesignerCustomWidgetCollectionInterface contains one single
441 + function returning a list of the collection's
442 + QDesignerCustomWidgetInterface objects. For example, if you have
443 + several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and
444 + \c CustomWidgetThree, the class definition may look like this:
445 +
446 + \snippet plugins/doc_src_qtdesigner.cpp 12
447 +
448 + In the class constructor you add the interfaces to your custom
449 + widgets to the list which you return in the customWidgets()
450 + function:
451 +
452 + \snippet plugins/doc_src_qtdesigner.cpp 13
453 +
454 + Note that instead of exporting each custom widget plugin using the
455 + Q_PLUGIN_METADATA() macro, you export the entire collection. The
456 + Q_PLUGIN_METADATA() macro ensures that \QD can access and construct
457 + the custom widgets. Without this macro, there is no way for \QD to
458 + use them.
459 +
460 + \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for
461 + Qt Designer}
462 +*/
463 +
464 +/*!
465 + \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() {
466 +
467 + Destroys the custom widget collection interface.
468 +*/
469 +
470 +/*!
471 + \fn QList<QDesignerCustomWidgetInterface*> QDesignerCustomWidgetCollectionInterface::customWidgets() const
472 +
473 + Returns a list of interfaces to the collection's custom widgets.
474 +*/
475 diff --git x/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h
476 new file mode 100644
477 index 000000000..d90e9b217
478 --- /dev/null
479 +++ y/qttools/src/designer/src/uiplugin/qdesignerexportwidget.h
480 @@ -0,0 +1,24 @@
481 +// Copyright (C) 2016 The Qt Company Ltd.
482 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
483 +
484 +#ifndef QDESIGNEREXPORTWIDGET_H
485 +#define QDESIGNEREXPORTWIDGET_H
486 +
487 +#include <QtCore/qglobal.h>
488 +
489 +QT_BEGIN_NAMESPACE
490 +
491 +#if 0
492 +// pragma for syncqt, don't remove.
493 +#pragma qt_class(QDesignerExportWidget)
494 +#endif
495 +
496 +#if defined(QDESIGNER_EXPORT_WIDGETS)
497 +# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT
498 +#else
499 +# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT
500 +#endif
501 +
502 +QT_END_NAMESPACE
503 +
504 +#endif //QDESIGNEREXPORTWIDGET_H
505 diff --git x/qttools/src/designer/src/uitools/CMakeLists.txt y/qttools/src/designer/src/uitools/CMakeLists.txt
506 new file mode 100644
507 index 000000000..6040ac71d
508 --- /dev/null
509 +++ y/qttools/src/designer/src/uitools/CMakeLists.txt
510 @@ -0,0 +1,46 @@
511 +# Generated from uitools.pro.
512 +
513 +#####################################################################
514 +## UiTools Module:
515 +#####################################################################
516 +
517 +qt_internal_add_module(UiTools
518 + SOURCES
519 + ../lib/uilib/abstractformbuilder.cpp ../lib/uilib/abstractformbuilder.h
520 + ../lib/uilib/formbuilder.cpp ../lib/uilib/formbuilder.h
521 + ../lib/uilib/formbuilderextra.cpp ../lib/uilib/formbuilderextra_p.h
522 + ../lib/uilib/properties.cpp ../lib/uilib/properties_p.h
523 + ../lib/uilib/resourcebuilder.cpp ../lib/uilib/resourcebuilder_p.h
524 + ../lib/uilib/textbuilder.cpp ../lib/uilib/textbuilder_p.h
525 + ../lib/uilib/ui4.cpp ../lib/uilib/ui4_p.h
526 + quiloader.cpp quiloader.h
527 + DEFINES
528 + QFORMINTERNAL_NAMESPACE
529 + QT_DESIGNER
530 + QT_DESIGNER_STATIC
531 + QT_USE_QSTRINGBUILDER
532 + INCLUDE_DIRECTORIES
533 + ../lib/uilib
534 + LIBRARIES
535 + Qt::UiPlugin
536 + PUBLIC_LIBRARIES
537 + Qt::Core
538 + Qt::Gui
539 + Qt::Widgets
540 +)
541 +
542 +## Scopes:
543 +#####################################################################
544 +
545 +qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets
546 + PUBLIC_LIBRARIES
547 + Qt::OpenGLWidgets
548 +)
549 +
550 +qt_internal_extend_target(UiTools CONDITION QT_FEATURE_opengl
551 + LIBRARIES
552 + Qt::OpenGL
553 +)
554 +qt_internal_add_docs(UiTools
555 + doc/qtuitools.qdocconf
556 +)
557 diff --git x/qttools/src/designer/src/uitools/qtuitoolsglobal.h y/qttools/src/designer/src/uitools/qtuitoolsglobal.h
558 new file mode 100644
559 index 000000000..6874fb15b
560 --- /dev/null
561 +++ y/qttools/src/designer/src/uitools/qtuitoolsglobal.h
562 @@ -0,0 +1,23 @@
563 +// Copyright (C) 2020 The Qt Company Ltd.
564 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
565 +
566 +#ifndef QTUITOOLSGLOBAL_H
567 +#define QTUITOOLSGLOBAL_H
568 +
569 +#include <QtCore/qglobal.h>
570 +
571 +QT_BEGIN_NAMESPACE
572 +
573 +#ifndef QT_STATIC
574 +# if defined(QT_BUILD_UITOOLS_LIB)
575 +# define Q_UITOOLS_EXPORT Q_DECL_EXPORT
576 +# else
577 +# define Q_UITOOLS_EXPORT Q_DECL_IMPORT
578 +# endif
579 +#else
580 +# define Q_UITOOLS_EXPORT
581 +#endif
582 +
583 +QT_END_NAMESPACE
584 +
585 +#endif // QTUITOOLSGLOBAL_H
586 diff --git x/qttools/src/designer/src/uitools/quiloader.cpp y/qttools/src/designer/src/uitools/quiloader.cpp
587 new file mode 100644
588 index 000000000..a06d4717b
589 --- /dev/null
590 +++ y/qttools/src/designer/src/uitools/quiloader.cpp
591 @@ -0,0 +1,914 @@
592 +// Copyright (C) 2020 The Qt Company Ltd.
593 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
594 +
595 +
596 +#include "quiloader.h"
597 +#include "quiloader_p.h"
598 +
599 +#include <QtUiPlugin/customwidget.h>
600 +
601 +#include <formbuilder.h>
602 +#include <formbuilderextra_p.h>
603 +#include <textbuilder_p.h>
604 +#include <ui4_p.h>
605 +
606 +#include <QtWidgets/qapplication.h>
607 +#include <QtWidgets/qlayout.h>
608 +#include <QtWidgets/qwidget.h>
609 +#include <QtWidgets/qtabwidget.h>
610 +#include <QtWidgets/qtreewidget.h>
611 +#include <QtWidgets/qlistwidget.h>
612 +#include <QtWidgets/qtablewidget.h>
613 +#include <QtWidgets/qtoolbox.h>
614 +#include <QtWidgets/qcombobox.h>
615 +#include <QtWidgets/qfontcombobox.h>
616 +
617 +#include <QtGui/qaction.h>
618 +#include <QtGui/qactiongroup.h>
619 +
620 +#include <QtCore/qdebug.h>
621 +#include <QtCore/qdatastream.h>
622 +#include <QtCore/qmap.h>
623 +#include <QtCore/qdir.h>
624 +#include <QtCore/qlibraryinfo.h>
625 +
626 +QT_BEGIN_NAMESPACE
627 +
628 +typedef QMap<QString, bool> widget_map;
629 +Q_GLOBAL_STATIC(widget_map, g_widgets)
630 +
631 +class QUiLoader;
632 +class QUiLoaderPrivate;
633 +
634 +#ifndef QT_NO_DATASTREAM
635 +// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based
636 +// mime data when dragging items in views with QAbstractItemView::InternalMove.
637 +QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s)
638 +{
639 + out << s.qualifier() << s.value();
640 + return out;
641 +}
642 +
643 +QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s)
644 +{
645 + QByteArray qualifier, value;
646 + in >> qualifier >> value;
647 + s.setQualifier(qualifier);
648 + s.setValue(value);
649 + return in;
650 +}
651 +#endif // QT_NO_DATASTREAM
652 +
653 +QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const
654 +{
655 + return idBased
656 + ? qtTrId(m_qualifier.constData())
657 + : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData());
658 +}
659 +
660 +#ifdef QFORMINTERNAL_NAMESPACE
661 +namespace QFormInternal
662 +{
663 +#endif
664 +
665 +class TranslatingTextBuilder : public QTextBuilder
666 +{
667 +public:
668 + explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) :
669 + m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {}
670 +
671 + QVariant loadText(const DomProperty *icon) const override;
672 +
673 + QVariant toNativeValue(const QVariant &value) const override;
674 +
675 + bool idBased() const { return m_idBased; }
676 +
677 +private:
678 + bool m_idBased;
679 + bool m_trEnabled;
680 + QByteArray m_className;
681 +};
682 +
683 +QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const
684 +{
685 + const DomString *str = text->elementString();
686 + if (!str)
687 + return QVariant();
688 + if (str->hasAttributeNotr()) {
689 + const QString notr = str->attributeNotr();
690 + if (notr == QStringLiteral("true") || notr == QStringLiteral("yes"))
691 + return QVariant::fromValue(str->text());
692 + }
693 + QUiTranslatableStringValue strVal;
694 + strVal.setValue(str->text().toUtf8());
695 + if (m_idBased)
696 + strVal.setQualifier(str->attributeId().toUtf8());
697 + else if (str->hasAttributeComment())
698 + strVal.setQualifier(str->attributeComment().toUtf8());
699 + return QVariant::fromValue(strVal);
700 +}
701 +
702 +QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const
703 +{
704 + if (value.canConvert<QUiTranslatableStringValue>()) {
705 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(value);
706 + if (!m_trEnabled)
707 + return QString::fromUtf8(tsv.value().constData());
708 + return QVariant::fromValue(tsv.translate(m_className, m_idBased));
709 + }
710 + if (value.canConvert<QString>())
711 + return QVariant::fromValue(qvariant_cast<QString>(value));
712 + return value;
713 +}
714 +
715 +// This is "exported" to linguist
716 +const QUiItemRolePair qUiItemRoles[] = {
717 + { Qt::DisplayRole, Qt::DisplayPropertyRole },
718 +#if QT_CONFIG(tooltip)
719 + { Qt::ToolTipRole, Qt::ToolTipPropertyRole },
720 +#endif
721 +#if QT_CONFIG(statustip)
722 + { Qt::StatusTipRole, Qt::StatusTipPropertyRole },
723 +#endif
724 +#if QT_CONFIG(whatsthis)
725 + { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole },
726 +#endif
727 + { -1 , -1 }
728 +};
729 +
730 +static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased)
731 +{
732 + const QUiItemRolePair *irs = qUiItemRoles;
733 +
734 + int cnt = item->columnCount();
735 + for (int i = 0; i < cnt; ++i) {
736 + for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
737 + QVariant v = item->data(i, irs[j].shadowRole);
738 + if (v.isValid()) {
739 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
740 + item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased));
741 + }
742 + }
743 + }
744 +
745 + cnt = item->childCount();
746 + for (int i = 0; i < cnt; ++i)
747 + recursiveReTranslate(item->child(i), class_name, idBased);
748 +}
749 +
750 +template<typename T>
751 +static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
752 +{
753 + const QUiItemRolePair *irs = qUiItemRoles;
754 +
755 + for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
756 + QVariant v = item->data(irs[j].shadowRole);
757 + if (v.isValid()) {
758 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
759 + item->setData(irs[j].realRole, tsv.translate(class_name, idBased));
760 + }
761 + }
762 +}
763 +
764 +static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased)
765 +{
766 + if (item)
767 + reTranslateWidgetItem(item, class_name, idBased);
768 +}
769 +
770 +#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \
771 + do { \
772 + QVariant v = mainWidget->widget(i)->property(propName); \
773 + if (v.isValid()) { \
774 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v); \
775 + mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \
776 + } \
777 + } while (0)
778 +
779 +class TranslationWatcher: public QObject
780 +{
781 + Q_OBJECT
782 +
783 +public:
784 + explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased):
785 + QObject(parent),
786 + m_className(className),
787 + m_idBased(idBased)
788 + {
789 + }
790 +
791 + bool eventFilter(QObject *o, QEvent *event) override
792 + {
793 + if (event->type() == QEvent::LanguageChange) {
794 + const auto &dynamicPropertyNames = o->dynamicPropertyNames();
795 + for (const QByteArray &prop : dynamicPropertyNames) {
796 + if (prop.startsWith(PROP_GENERIC_PREFIX)) {
797 + const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
798 + const QUiTranslatableStringValue tsv =
799 + qvariant_cast<QUiTranslatableStringValue>(o->property(prop));
800 + o->setProperty(propName, tsv.translate(m_className, m_idBased));
801 + }
802 + }
803 + if (0) {
804 +#if QT_CONFIG(tabwidget)
805 + } else if (QTabWidget *tabw = qobject_cast<QTabWidget*>(o)) {
806 + const int cnt = tabw->count();
807 + for (int i = 0; i < cnt; ++i) {
808 + RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT);
809 +#if QT_CONFIG(tooltip)
810 + RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP);
811 +# endif
812 +#if QT_CONFIG(whatsthis)
813 + RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
814 +# endif
815 + }
816 +#endif
817 +#if QT_CONFIG(listwidget)
818 + } else if (QListWidget *listw = qobject_cast<QListWidget*>(o)) {
819 + const int cnt = listw->count();
820 + for (int i = 0; i < cnt; ++i)
821 + reTranslateWidgetItem(listw->item(i), m_className, m_idBased);
822 +#endif
823 +#if QT_CONFIG(treewidget)
824 + } else if (QTreeWidget *treew = qobject_cast<QTreeWidget*>(o)) {
825 + if (QTreeWidgetItem *item = treew->headerItem())
826 + recursiveReTranslate(item, m_className, m_idBased);
827 + const int cnt = treew->topLevelItemCount();
828 + for (int i = 0; i < cnt; ++i) {
829 + QTreeWidgetItem *item = treew->topLevelItem(i);
830 + recursiveReTranslate(item, m_className, m_idBased);
831 + }
832 +#endif
833 +#if QT_CONFIG(tablewidget)
834 + } else if (QTableWidget *tablew = qobject_cast<QTableWidget*>(o)) {
835 + const int row_cnt = tablew->rowCount();
836 + const int col_cnt = tablew->columnCount();
837 + for (int j = 0; j < col_cnt; ++j)
838 + reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased);
839 + for (int i = 0; i < row_cnt; ++i) {
840 + reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased);
841 + for (int j = 0; j < col_cnt; ++j)
842 + reTranslateTableItem(tablew->item(i, j), m_className, m_idBased);
843 + }
844 +#endif
845 +#if QT_CONFIG(combobox)
846 + } else if (QComboBox *combow = qobject_cast<QComboBox*>(o)) {
847 + if (!qobject_cast<QFontComboBox*>(o)) {
848 + const int cnt = combow->count();
849 + for (int i = 0; i < cnt; ++i) {
850 + const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole);
851 + if (v.isValid()) {
852 + QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
853 + combow->setItemText(i, tsv.translate(m_className, m_idBased));
854 + }
855 + }
856 + }
857 +#endif
858 +#if QT_CONFIG(toolbox)
859 + } else if (QToolBox *toolw = qobject_cast<QToolBox*>(o)) {
860 + const int cnt = toolw->count();
861 + for (int i = 0; i < cnt; ++i) {
862 + RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT);
863 +#if QT_CONFIG(tooltip)
864 + RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP);
865 +# endif
866 + }
867 +#endif
868 + }
869 + }
870 + return false;
871 + }
872 +
873 +private:
874 + QByteArray m_className;
875 + bool m_idBased;
876 +};
877 +
878 +class FormBuilderPrivate: public QFormBuilder
879 +{
880 + friend class QT_PREPEND_NAMESPACE(QUiLoader);
881 + friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate);
882 + using ParentClass = QFormBuilder;
883 +
884 +public:
885 + QUiLoader *loader = nullptr;
886 +
887 + bool dynamicTr = false;
888 + bool trEnabled = true;
889 +
890 + FormBuilderPrivate() = default;
891 +
892 + QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
893 + {
894 + return ParentClass::createWidget(className, parent, name);
895 + }
896 +
897 + QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
898 + {
899 + return ParentClass::createLayout(className, parent, name);
900 + }
901 +
902 + QAction *defaultCreateAction(QObject *parent, const QString &name)
903 + {
904 + return ParentClass::createAction(parent, name);
905 + }
906 +
907 + QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name)
908 + {
909 + return ParentClass::createActionGroup(parent, name);
910 + }
911 +
912 + QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override
913 + {
914 + if (QWidget *widget = loader->createWidget(className, parent, name)) {
915 + widget->setObjectName(name);
916 + return widget;
917 + }
918 +
919 + return nullptr;
920 + }
921 +
922 + QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override
923 + {
924 + if (QLayout *layout = loader->createLayout(className, parent, name)) {
925 + layout->setObjectName(name);
926 + return layout;
927 + }
928 +
929 + return nullptr;
930 + }
931 +
932 + QActionGroup *createActionGroup(QObject *parent, const QString &name) override
933 + {
934 + if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) {
935 + actionGroup->setObjectName(name);
936 + return actionGroup;
937 + }
938 +
939 + return nullptr;
940 + }
941 +
942 + QAction *createAction(QObject *parent, const QString &name) override
943 + {
944 + if (QAction *action = loader->createAction(parent, name)) {
945 + action->setObjectName(name);
946 + return action;
947 + }
948 +
949 + return nullptr;
950 + }
951 +
952 + void applyProperties(QObject *o, const QList<DomProperty*> &properties) override;
953 + QWidget *create(DomUI *ui, QWidget *parentWidget) override;
954 + QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override;
955 + bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override;
956 +
957 +private:
958 + QByteArray m_class;
959 + TranslationWatcher *m_trwatch = nullptr;
960 + bool m_idBased = false;
961 +};
962 +
963 +static QString convertTranslatable(const DomProperty *p, const QByteArray &className,
964 + bool idBased, QUiTranslatableStringValue *strVal)
965 +{
966 + if (p->kind() != DomProperty::String)
967 + return QString();
968 + const DomString *dom_str = p->elementString();
969 + if (!dom_str)
970 + return QString();
971 + if (dom_str->hasAttributeNotr()) {
972 + const QString notr = dom_str->attributeNotr();
973 + if (notr == QStringLiteral("yes") || notr == QStringLiteral("true"))
974 + return QString();
975 + }
976 + strVal->setValue(dom_str->text().toUtf8());
977 + strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8());
978 + if (strVal->value().isEmpty() && strVal->qualifier().isEmpty())
979 + return QString();
980 + return strVal->translate(className, idBased);
981 +}
982 +
983 +void FormBuilderPrivate::applyProperties(QObject *o, const QList<DomProperty*> &properties)
984 +{
985 + QFormBuilder::applyProperties(o, properties);
986 +
987 + if (!m_trwatch)
988 + m_trwatch = new TranslationWatcher(o, m_class, m_idBased);
989 +
990 + if (properties.isEmpty())
991 + return;
992 +
993 + // Unlike string item roles, string properties are not loaded via the textBuilder
994 + // (as they are "shadowed" by the property sheets in designer). So do the initial
995 + // translation here.
996 + bool anyTrs = false;
997 + for (const DomProperty *p : properties) {
998 + QUiTranslatableStringValue strVal;
999 + const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
1000 + if (text.isEmpty())
1001 + continue;
1002 + const QByteArray name = p->attributeName().toUtf8();
1003 + if (dynamicTr) {
1004 + const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
1005 + o->setProperty(dynname, QVariant::fromValue(strVal));
1006 + anyTrs = trEnabled;
1007 + }
1008 + if (p->elementString()->text() != text)
1009 + o->setProperty(name, text);
1010 + }
1011 + if (anyTrs)
1012 + o->installEventFilter(m_trwatch);
1013 +}
1014 +
1015 +QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget)
1016 +{
1017 + m_class = ui->elementClass().toUtf8();
1018 + m_trwatch = nullptr;
1019 + m_idBased = ui->attributeIdbasedtr();
1020 + setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class));
1021 + return QFormBuilder::create(ui, parentWidget);
1022 +}
1023 +
1024 +QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget)
1025 +{
1026 + QWidget *w = QFormBuilder::create(ui_widget, parentWidget);
1027 + if (w == nullptr)
1028 + return nullptr;
1029 +
1030 + if (0) {
1031 +#if QT_CONFIG(tabwidget)
1032 + } else if (qobject_cast<QTabWidget*>(w)) {
1033 +#endif
1034 +#if QT_CONFIG(listwidget)
1035 + } else if (qobject_cast<QListWidget*>(w)) {
1036 +#endif
1037 +#if QT_CONFIG(treewidget)
1038 + } else if (qobject_cast<QTreeWidget*>(w)) {
1039 +#endif
1040 +#if QT_CONFIG(tablewidget)
1041 + } else if (qobject_cast<QTableWidget*>(w)) {
1042 +#endif
1043 +#if QT_CONFIG(combobox)
1044 + } else if (qobject_cast<QComboBox*>(w)) {
1045 + if (qobject_cast<QFontComboBox*>(w))
1046 + return w;
1047 +#endif
1048 +#if QT_CONFIG(toolbox)
1049 + } else if (qobject_cast<QToolBox*>(w)) {
1050 +#endif
1051 + } else {
1052 + return w;
1053 + }
1054 + if (dynamicTr && trEnabled)
1055 + w->installEventFilter(m_trwatch);
1056 + return w;
1057 +}
1058 +
1059 +#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \
1060 + do { \
1061 + if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \
1062 + QUiTranslatableStringValue strVal; \
1063 + const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \
1064 + if (!text.isEmpty()) { \
1065 + if (dynamicTr) \
1066 + mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \
1067 + mainWidget->setter(i, text); \
1068 + } \
1069 + } \
1070 + } while (0)
1071 +
1072 +bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
1073 +{
1074 + if (parentWidget == nullptr)
1075 + return true;
1076 +
1077 + if (!ParentClass::addItem(ui_widget, widget, parentWidget))
1078 + return false;
1079 +
1080 + // Check special cases. First: Custom container
1081 + const QString className = QLatin1String(parentWidget->metaObject()->className());
1082 + if (!d->customWidgetAddPageMethod(className).isEmpty())
1083 + return true;
1084 +
1085 + const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
1086 +
1087 + if (0) {
1088 +#if QT_CONFIG(tabwidget)
1089 + } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
1090 + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
1091 + const int i = tabWidget->count() - 1;
1092 + TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT);
1093 +#if QT_CONFIG(tooltip)
1094 + TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP);
1095 +# endif
1096 +#if QT_CONFIG(whatsthis)
1097 + TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
1098 +# endif
1099 +#endif
1100 +#if QT_CONFIG(toolbox)
1101 + } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
1102 + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
1103 + const int i = toolBox->count() - 1;
1104 + TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT);
1105 +#if QT_CONFIG(tooltip)
1106 + TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP);
1107 +# endif
1108 +#endif
1109 + }
1110 +
1111 + return true;
1112 +}
1113 +
1114 +#ifdef QFORMINTERNAL_NAMESPACE
1115 +}
1116 +#endif
1117 +
1118 +class QUiLoaderPrivate
1119 +{
1120 +public:
1121 +#ifdef QFORMINTERNAL_NAMESPACE
1122 + QFormInternal::FormBuilderPrivate builder;
1123 +#else
1124 + FormBuilderPrivate builder;
1125 +#endif
1126 +
1127 + void setupWidgetMap() const;
1128 +};
1129 +
1130 +void QUiLoaderPrivate::setupWidgetMap() const
1131 +{
1132 + if (!g_widgets()->isEmpty())
1133 + return;
1134 +
1135 +#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true);
1136 +#define DECLARE_LAYOUT(a, b)
1137 +
1138 +#include "widgets.table"
1139 +
1140 +#undef DECLARE_WIDGET
1141 +#undef DECLARE_WIDGET_1
1142 +#undef DECLARE_LAYOUT
1143 +}
1144 +
1145 +/*!
1146 + \class QUiLoader
1147 + \inmodule QtUiTools
1148 +
1149 + \brief The QUiLoader class enables standalone applications to
1150 + dynamically create user interfaces at run-time using the
1151 + information stored in UI files or specified in plugin paths.
1152 +
1153 + In addition, you can customize or create your own user interface by
1154 + deriving your own loader class.
1155 +
1156 + If you have a custom component or an application that embeds \QD, you can
1157 + also use the QFormBuilder class provided by the QtDesigner module to create
1158 + user interfaces from UI files.
1159 +
1160 + The QUiLoader class provides a collection of functions allowing you to
1161 + create widgets based on the information stored in UI files (created
1162 + with \QD) or available in the specified plugin paths. The specified plugin
1163 + paths can be retrieved using the pluginPaths() function. Similarly, the
1164 + contents of a UI file can be retrieved using the load() function. For
1165 + example:
1166 +
1167 + \snippet quiloader/mywidget.cpp 0
1168 +
1169 + \if !defined(qtforpython)
1170 + By including the user interface in the form's resources (\c myform.qrc), we
1171 + ensure that it will be present at run-time:
1172 +
1173 + \quotefile quiloader/mywidget.qrc
1174 + \endif
1175 +
1176 + The availableWidgets() function returns a QStringList with the class names
1177 + of the widgets available in the specified plugin paths. To create these
1178 + widgets, simply use the createWidget() function. For example:
1179 +
1180 + \snippet quiloader/main.cpp 0
1181 +
1182 + To make a custom widget available to the loader, you can use the
1183 + addPluginPath() function; to remove all available widgets, you can call
1184 + the clearPluginPaths() function.
1185 +
1186 + The createAction(), createActionGroup(), createLayout(), and createWidget()
1187 + functions are used internally by the QUiLoader class whenever it has to
1188 + create an action, action group, layout, or widget respectively. For that
1189 + reason, you can subclass the QUiLoader class and reimplement these
1190 + functions to intervene the process of constructing a user interface. For
1191 + example, you might want to have a list of the actions created when loading
1192 + a form or creating a custom widget.
1193 +
1194 + For a complete example using the QUiLoader class, see the
1195 + \l{Calculator Builder Example}.
1196 +
1197 + \sa {Qt UI Tools}, QFormBuilder
1198 +*/
1199 +
1200 +/*!
1201 + Creates a form loader with the given \a parent.
1202 +*/
1203 +QUiLoader::QUiLoader(QObject *parent)
1204 + : QObject(parent), d_ptr(new QUiLoaderPrivate)
1205 +{
1206 + Q_D(QUiLoader);
1207 +
1208 +#ifndef QT_NO_DATASTREAM
1209 + static int metaTypeId = 0;
1210 + if (!metaTypeId) {
1211 + metaTypeId = qRegisterMetaType<QUiTranslatableStringValue>("QUiTranslatableStringValue");
1212 + }
1213 +#endif // QT_NO_DATASTREAM
1214 + d->builder.loader = this;
1215 +
1216 +#if QT_CONFIG(library)
1217 + QStringList paths;
1218 + const QStringList &libraryPaths = QApplication::libraryPaths();
1219 + for (const QString &path : libraryPaths) {
1220 + QString libPath = path;
1221 + libPath += QDir::separator();
1222 + libPath += QStringLiteral("designer");
1223 + paths.append(libPath);
1224 + }
1225 +
1226 + d->builder.setPluginPath(paths);
1227 +#endif // QT_CONFIG(library)
1228 +}
1229 +
1230 +/*!
1231 + Destroys the loader.
1232 +*/
1233 +QUiLoader::~QUiLoader() = default;
1234 +
1235 +/*!
1236 + Loads a form from the given \a device and creates a new widget with the
1237 + given \a parentWidget to hold its contents.
1238 +
1239 + \sa createWidget(), errorString()
1240 +*/
1241 +QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
1242 +{
1243 + Q_D(QUiLoader);
1244 + // QXmlStreamReader will report errors on open failure.
1245 + if (!device->isOpen())
1246 + device->open(QIODevice::ReadOnly|QIODevice::Text);
1247 + return d->builder.load(device, parentWidget);
1248 +}
1249 +
1250 +/*!
1251 + Returns a list naming the paths in which the loader will search when
1252 + locating custom widget plugins.
1253 +
1254 + \sa addPluginPath(), clearPluginPaths()
1255 +*/
1256 +QStringList QUiLoader::pluginPaths() const
1257 +{
1258 + Q_D(const QUiLoader);
1259 + return d->builder.pluginPaths();
1260 +}
1261 +
1262 +/*!
1263 + Clears the list of paths in which the loader will search when locating
1264 + plugins.
1265 +
1266 + \sa addPluginPath(), pluginPaths()
1267 +*/
1268 +void QUiLoader::clearPluginPaths()
1269 +{
1270 + Q_D(QUiLoader);
1271 + d->builder.clearPluginPaths();
1272 +}
1273 +
1274 +/*!
1275 + Adds the given \a path to the list of paths in which the loader will search
1276 + when locating plugins.
1277 +
1278 + \sa pluginPaths(), clearPluginPaths()
1279 +*/
1280 +void QUiLoader::addPluginPath(const QString &path)
1281 +{
1282 + Q_D(QUiLoader);
1283 + d->builder.addPluginPath(path);
1284 +}
1285 +
1286 +/*!
1287 + Creates a new widget with the given \a parent and \a name using the class
1288 + specified by \a className. You can use this function to create any of the
1289 + widgets returned by the availableWidgets() function.
1290 +
1291 + The function is also used internally by the QUiLoader class whenever it
1292 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1293 + function to intervene process of constructing a user interface or widget.
1294 + However, in your implementation, ensure that you call QUiLoader's version
1295 + first.
1296 +
1297 + \sa availableWidgets(), load()
1298 +*/
1299 +QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
1300 +{
1301 + Q_D(QUiLoader);
1302 + return d->builder.defaultCreateWidget(className, parent, name);
1303 +}
1304 +
1305 +/*!
1306 + Creates a new layout with the given \a parent and \a name using the class
1307 + specified by \a className.
1308 +
1309 + The function is also used internally by the QUiLoader class whenever it
1310 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1311 + function to intervene process of constructing a user interface or widget.
1312 + However, in your implementation, ensure that you call QUiLoader's version
1313 + first.
1314 +
1315 + \sa createWidget(), load()
1316 +*/
1317 +QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
1318 +{
1319 + Q_D(QUiLoader);
1320 + return d->builder.defaultCreateLayout(className, parent, name);
1321 +}
1322 +
1323 +/*!
1324 + Creates a new action group with the given \a parent and \a name.
1325 +
1326 + The function is also used internally by the QUiLoader class whenever it
1327 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1328 + function to intervene process of constructing a user interface or widget.
1329 + However, in your implementation, ensure that you call QUiLoader's version
1330 + first.
1331 +
1332 + \sa createAction(), createWidget(), load()
1333 + */
1334 +QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
1335 +{
1336 + Q_D(QUiLoader);
1337 + return d->builder.defaultCreateActionGroup(parent, name);
1338 +}
1339 +
1340 +/*!
1341 + Creates a new action with the given \a parent and \a name.
1342 +
1343 + The function is also used internally by the QUiLoader class whenever it
1344 + creates a widget. Hence, you can subclass QUiLoader and reimplement this
1345 + function to intervene process of constructing a user interface or widget.
1346 + However, in your implementation, ensure that you call QUiLoader's version
1347 + first.
1348 +
1349 + \sa createActionGroup(), createWidget(), load()
1350 +*/
1351 +QAction *QUiLoader::createAction(QObject *parent, const QString &name)
1352 +{
1353 + Q_D(QUiLoader);
1354 + return d->builder.defaultCreateAction(parent, name);
1355 +}
1356 +
1357 +/*!
1358 + Returns a list naming all available widgets that can be built using the
1359 + createWidget() function, i.e all the widgets specified within the given
1360 + plugin paths.
1361 +
1362 + \sa pluginPaths(), createWidget()
1363 +
1364 +*/
1365 +QStringList QUiLoader::availableWidgets() const
1366 +{
1367 + Q_D(const QUiLoader);
1368 +
1369 + d->setupWidgetMap();
1370 + widget_map available = *g_widgets();
1371 +
1372 + const auto &customWidgets = d->builder.customWidgets();
1373 + for (QDesignerCustomWidgetInterface *plugin : customWidgets)
1374 + available.insert(plugin->name(), true);
1375 +
1376 + return available.keys();
1377 +}
1378 +
1379 +
1380 +/*!
1381 + \since 4.5
1382 + Returns a list naming all available layouts that can be built using the
1383 + createLayout() function
1384 +
1385 + \sa createLayout()
1386 +*/
1387 +
1388 +QStringList QUiLoader::availableLayouts() const
1389 +{
1390 + QStringList rc;
1391 +#define DECLARE_WIDGET(a, b)
1392 +#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a));
1393 +
1394 +#include "widgets.table"
1395 +
1396 +#undef DECLARE_WIDGET
1397 +#undef DECLARE_LAYOUT
1398 + return rc;
1399 +}
1400 +
1401 +/*!
1402 + Sets the working directory of the loader to \a dir. The loader will look
1403 + for other resources, such as icons and resource files, in paths relative to
1404 + this directory.
1405 +
1406 + \sa workingDirectory()
1407 +*/
1408 +
1409 +void QUiLoader::setWorkingDirectory(const QDir &dir)
1410 +{
1411 + Q_D(QUiLoader);
1412 + d->builder.setWorkingDirectory(dir);
1413 +}
1414 +
1415 +/*!
1416 + Returns the working directory of the loader.
1417 +
1418 + \sa setWorkingDirectory()
1419 +*/
1420 +
1421 +QDir QUiLoader::workingDirectory() const
1422 +{
1423 + Q_D(const QUiLoader);
1424 + return d->builder.workingDirectory();
1425 +}
1426 +/*!
1427 + \since 4.5
1428 +
1429 + If \a enabled is true, user interfaces loaded by this loader will
1430 + automatically retranslate themselves upon receiving a language change
1431 + event. Otherwise, the user interfaces will not be retranslated.
1432 +
1433 + \sa isLanguageChangeEnabled()
1434 +*/
1435 +
1436 +void QUiLoader::setLanguageChangeEnabled(bool enabled)
1437 +{
1438 + Q_D(QUiLoader);
1439 + d->builder.dynamicTr = enabled;
1440 +}
1441 +
1442 +/*!
1443 + \since 4.5
1444 +
1445 + Returns true if dynamic retranslation on language change is enabled;
1446 + returns false otherwise.
1447 +
1448 + \sa setLanguageChangeEnabled()
1449 +*/
1450 +
1451 +bool QUiLoader::isLanguageChangeEnabled() const
1452 +{
1453 + Q_D(const QUiLoader);
1454 + return d->builder.dynamicTr;
1455 +}
1456 +
1457 +/*!
1458 + \internal
1459 + \since 4.5
1460 +
1461 + If \a enabled is true, user interfaces loaded by this loader will be
1462 + translated. Otherwise, the user interfaces will not be translated.
1463 +
1464 + \note This is orthogonal to languageChangeEnabled.
1465 +
1466 + \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
1467 +*/
1468 +
1469 +void QUiLoader::setTranslationEnabled(bool enabled)
1470 +{
1471 + Q_D(QUiLoader);
1472 + d->builder.trEnabled = enabled;
1473 +}
1474 +
1475 +/*!
1476 + \internal
1477 + \since 4.5
1478 +
1479 + Returns true if translation is enabled; returns false otherwise.
1480 +
1481 + \sa setTranslationEnabled()
1482 +*/
1483 +
1484 +bool QUiLoader::isTranslationEnabled() const
1485 +{
1486 + Q_D(const QUiLoader);
1487 + return d->builder.trEnabled;
1488 +}
1489 +
1490 +/*!
1491 + Returns a human-readable description of the last error occurred in load().
1492 +
1493 + \since 5.0
1494 + \sa load()
1495 +*/
1496 +
1497 +QString QUiLoader::errorString() const
1498 +{
1499 + Q_D(const QUiLoader);
1500 + return d->builder.errorString();
1501 +}
1502 +
1503 +QT_END_NAMESPACE
1504 +
1505 +#include "quiloader.moc"
1506 diff --git x/qttools/src/designer/src/uitools/quiloader.h y/qttools/src/designer/src/uitools/quiloader.h
1507 new file mode 100644
1508 index 000000000..742b5606f
1509 --- /dev/null
1510 +++ y/qttools/src/designer/src/uitools/quiloader.h
1511 @@ -0,0 +1,61 @@
1512 +// Copyright (C) 2020 The Qt Company Ltd.
1513 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
1514 +
1515 +#ifndef QUILOADER_H
1516 +#define QUILOADER_H
1517 +
1518 +#include <QtUiTools/qtuitoolsglobal.h>
1519 +#include <QtCore/qobject.h>
1520 +#include <QtCore/qscopedpointer.h>
1521 +
1522 +QT_BEGIN_NAMESPACE
1523 +
1524 +class QWidget;
1525 +class QLayout;
1526 +class QAction;
1527 +class QActionGroup;
1528 +class QString;
1529 +class QIODevice;
1530 +class QDir;
1531 +
1532 +class QUiLoaderPrivate;
1533 +class Q_UITOOLS_EXPORT QUiLoader : public QObject
1534 +{
1535 + Q_OBJECT
1536 +public:
1537 + explicit QUiLoader(QObject *parent = nullptr);
1538 + ~QUiLoader() override;
1539 +
1540 + QStringList pluginPaths() const;
1541 + void clearPluginPaths();
1542 + void addPluginPath(const QString &path);
1543 +
1544 + QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr);
1545 + QStringList availableWidgets() const;
1546 + QStringList availableLayouts() const;
1547 +
1548 + virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString());
1549 + virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString());
1550 + virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString());
1551 + virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString());
1552 +
1553 + void setWorkingDirectory(const QDir &dir);
1554 + QDir workingDirectory() const;
1555 +
1556 + void setLanguageChangeEnabled(bool enabled);
1557 + bool isLanguageChangeEnabled() const;
1558 +
1559 + void setTranslationEnabled(bool enabled);
1560 + bool isTranslationEnabled() const;
1561 +
1562 + QString errorString() const;
1563 +
1564 +private:
1565 + QScopedPointer<QUiLoaderPrivate> d_ptr;
1566 + Q_DECLARE_PRIVATE(QUiLoader)
1567 + Q_DISABLE_COPY_MOVE(QUiLoader)
1568 +};
1569 +
1570 +QT_END_NAMESPACE
1571 +
1572 +#endif // QUILOADER_H
1573 diff --git x/qttools/src/designer/src/uitools/quiloader_p.h y/qttools/src/designer/src/uitools/quiloader_p.h
1574 new file mode 100644
1575 index 000000000..efd943217
1576 --- /dev/null
1577 +++ y/qttools/src/designer/src/uitools/quiloader_p.h
1578 @@ -0,0 +1,77 @@
1579 +// Copyright (C) 2020 The Qt Company Ltd.
1580 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
1581 +
1582 +#ifndef QUILOADER_P_H
1583 +#define QUILOADER_P_H
1584 +
1585 +//
1586 +// W A R N I N G
1587 +// -------------
1588 +//
1589 +// This file is not part of the Qt API. It exists purely as an
1590 +// implementation detail. This header file may change from version to
1591 +// version without notice, or even be removed.
1592 +//
1593 +// We mean it.
1594 +//
1595 +
1596 +#include <QtUiTools/qtuitoolsglobal.h>
1597 +#include <QtCore/qbytearray.h>
1598 +#include <QtCore/qmetatype.h>
1599 +
1600 +QT_FORWARD_DECLARE_CLASS(QDataStream)
1601 +
1602 +// This file is here for use by the form preview in Linguist. If you change anything
1603 +// here or in the code which uses it, remember to adapt Linguist accordingly.
1604 +
1605 +#define PROP_GENERIC_PREFIX "_q_notr_"
1606 +#define PROP_TOOLITEMTEXT "_q_toolItemText_notr"
1607 +#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr"
1608 +#define PROP_TABPAGETEXT "_q_tabPageText_notr"
1609 +#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr"
1610 +#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr"
1611 +
1612 +QT_BEGIN_NAMESPACE
1613 +
1614 +class Q_UITOOLS_EXPORT QUiTranslatableStringValue
1615 +{
1616 +public:
1617 + QByteArray value() const { return m_value; }
1618 + void setValue(const QByteArray &value) { m_value = value; }
1619 + QByteArray qualifier() const { return m_qualifier; }
1620 + void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; }
1621 +
1622 + QString translate(const QByteArray &className, bool idBased) const;
1623 +
1624 +private:
1625 + QByteArray m_value;
1626 + QByteArray m_qualifier; // Comment or ID for id-based tr().
1627 +};
1628 +
1629 +#ifndef QT_NO_DATASTREAM
1630 +Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s);
1631 +Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s);
1632 +#endif // QT_NO_DATASTREAM
1633 +
1634 +struct QUiItemRolePair {
1635 + int realRole;
1636 + int shadowRole;
1637 +};
1638 +
1639 +#ifdef QFORMINTERNAL_NAMESPACE
1640 +namespace QFormInternal
1641 +{
1642 +#endif
1643 +
1644 +extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[];
1645 +
1646 +#ifdef QFORMINTERNAL_NAMESPACE
1647 +}
1648 +#endif
1649 +
1650 +QT_END_NAMESPACE
1651 +
1652 +Q_DECLARE_METATYPE(QUiTranslatableStringValue)
1653 +
1654 +
1655 +#endif // QUILOADER_P_H
1656 diff --git x/qttools/src/uiplugin/CMakeLists.txt y/qttools/src/uiplugin/CMakeLists.txt
1657 deleted file mode 100644
1658 index 4fedf8e33..000000000
1659 --- x/qttools/src/uiplugin/CMakeLists.txt
1660 +++ /dev/null
1661 @@ -1,27 +0,0 @@
1662 -# Generated from uiplugin.pro.
1663 -
1664 -#####################################################################
1665 -## UiPlugin Module:
1666 -#####################################################################
1667 -
1668 -qt_internal_add_module(UiPlugin
1669 - NO_PRIVATE_MODULE
1670 - HEADER_MODULE
1671 - QMAKE_MODULE_CONFIG designer_defines
1672 - PUBLIC_LIBRARIES
1673 - Qt::Core
1674 - Qt::Gui
1675 - Qt::Widgets
1676 -)
1677 -
1678 -# special case begin
1679 -set(is_plugin "$<TARGET_PROPERTY:QT_PLUGIN_CLASS_NAME>")
1680 -target_compile_definitions(
1681 - UiPlugin
1682 - INTERFACE
1683 - $<$<BOOL:${is_plugin}>:QDESIGNER_EXPORT_WIDGETS>
1684 -)
1685 -# special case end
1686 -
1687 -#### Keys ignored in scope 1:.:.:uiplugin.pro:<TRUE>:
1688 -# MODULE_CONFIG = "designer_defines"
1689 diff --git x/qttools/src/uiplugin/customwidget.h y/qttools/src/uiplugin/customwidget.h
1690 deleted file mode 100644
1691 index 2a47a32f8..000000000
1692 --- x/qttools/src/uiplugin/customwidget.h
1693 +++ /dev/null
1694 @@ -1,62 +0,0 @@
1695 -// Copyright (C) 2016 The Qt Company Ltd.
1696 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
1697 -
1698 -#ifndef CUSTOMWIDGET_H
1699 -#define CUSTOMWIDGET_H
1700 -
1701 -#include <QtCore/qobject.h>
1702 -#include <QtCore/qstring.h>
1703 -#include <QtGui/qicon.h>
1704 -
1705 -QT_BEGIN_NAMESPACE
1706 -
1707 -class QWidget;
1708 -class QDesignerFormEditorInterface;
1709 -
1710 -class QDesignerCustomWidgetInterface
1711 -{
1712 -public:
1713 - virtual ~QDesignerCustomWidgetInterface() = default; // ### FIXME: weak vtable
1714 -
1715 - virtual QString name() const = 0;
1716 - virtual QString group() const = 0;
1717 - virtual QString toolTip() const = 0;
1718 - virtual QString whatsThis() const = 0;
1719 - virtual QString includeFile() const = 0;
1720 - virtual QIcon icon() const = 0;
1721 -
1722 - virtual bool isContainer() const = 0;
1723 -
1724 - virtual QWidget *createWidget(QWidget *parent) = 0;
1725 -
1726 - virtual bool isInitialized() const { return false; }
1727 - virtual void initialize(QDesignerFormEditorInterface *core) { Q_UNUSED(core); }
1728 -
1729 - virtual QString domXml() const
1730 - {
1731 - return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
1732 - .arg(name()).arg(name().toLower());
1733 - }
1734 -
1735 - virtual QString codeTemplate() const { return QString(); }
1736 -};
1737 -
1738 -#define QDesignerCustomWidgetInterface_iid "org.qt-project.QDesignerCustomWidgetInterface"
1739 -
1740 -Q_DECLARE_INTERFACE(QDesignerCustomWidgetInterface, QDesignerCustomWidgetInterface_iid)
1741 -
1742 -class QDesignerCustomWidgetCollectionInterface
1743 -{
1744 -public:
1745 - virtual ~QDesignerCustomWidgetCollectionInterface() = default; // ### FIXME: weak vtable
1746 -
1747 - virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const = 0;
1748 -};
1749 -
1750 -#define QDesignerCustomWidgetCollectionInterface_iid "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface"
1751 -
1752 -Q_DECLARE_INTERFACE(QDesignerCustomWidgetCollectionInterface, QDesignerCustomWidgetCollectionInterface_iid)
1753 -
1754 -QT_END_NAMESPACE
1755 -
1756 -#endif // CUSTOMWIDGET_H
1757 diff --git x/qttools/src/uiplugin/customwidget.qdoc y/qttools/src/uiplugin/customwidget.qdoc
1758 deleted file mode 100644
1759 index 557e9a454..000000000
1760 --- x/qttools/src/uiplugin/customwidget.qdoc
1761 +++ /dev/null
1762 @@ -1,269 +0,0 @@
1763 -// Copyright (C) 2016 The Qt Company Ltd.
1764 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
1765 -
1766 -/*!
1767 - \class QDesignerCustomWidgetInterface
1768 -
1769 - \brief The QDesignerCustomWidgetInterface class enables Qt Designer
1770 - to access and construct custom widgets.
1771 -
1772 - \inmodule QtDesigner
1773 -
1774 - QDesignerCustomWidgetInterface provides a custom widget with an
1775 - interface. The class contains a set of functions that must be subclassed
1776 - to return basic information about the widget, such as its class name and
1777 - the name of its header file. Other functions must be implemented to
1778 - initialize the plugin when it is loaded, and to construct instances of
1779 - the custom widget for \QD to use.
1780 -
1781 - When implementing a custom widget you must subclass
1782 - QDesignerCustomWidgetInterface to expose your widget to \QD. For
1783 - example, this is the declaration for the plugin used in the
1784 - \l{Custom Widget Plugin Example}{Custom Widget Plugin example} that
1785 - enables an analog clock custom widget to be used by \QD:
1786 -
1787 - \snippet customwidgetplugin/customwidgetplugin.h 0
1788 -
1789 - Note that the only part of the class definition that is specific
1790 - to this particular custom widget is the class name. In addition,
1791 - since we are implementing an interface, we must ensure that it's
1792 - made known to the meta object system using the Q_INTERFACES()
1793 - macro. This enables \QD to use the qobject_cast() function to
1794 - query for supported interfaces using nothing but a QObject
1795 - pointer.
1796 -
1797 - After \QD loads a custom widget plugin, it calls the interface's
1798 - initialize() function to enable it to set up any resources that it
1799 - may need. This function is called with a QDesignerFormEditorInterface
1800 - parameter that provides the plugin with a gateway to all of \QD's API.
1801 -
1802 - \QD constructs instances of the custom widget by calling the plugin's
1803 - createWidget() function with a suitable parent widget. Plugins must
1804 - construct and return an instance of a custom widget with the specified
1805 - parent widget.
1806 -
1807 - Exporting your custom widget plugin to \QD using the Q_PLUGIN_METADATA()
1808 - macro. For example, if a library called \c libcustomwidgetplugin.so
1809 - (on Unix) or \c libcustomwidget.dll (on Windows) contains a widget
1810 - class called \c MyCustomWidget, we can export it by adding the
1811 - following line to the file containing the plugin header:
1812 -
1813 - \snippet plugins/doc_src_qtdesigner.cpp 14
1814 -
1815 - This macro ensures that \QD can access and construct the custom widget.
1816 - Without this macro, there is no way for \QD to use it.
1817 -
1818 - When implementing a custom widget plugin, you build it as a
1819 - separate library. If you want to include several custom widget
1820 - plugins in the same library, you must in addition subclass
1821 - QDesignerCustomWidgetCollectionInterface.
1822 -
1823 - \warning If your custom widget plugin contains QVariant
1824 - properties, be aware that only the following \l
1825 - {QVariant::Type}{types} are supported:
1826 -
1827 - \list
1828 - \li QVariant::ByteArray
1829 - \li QVariant::Bool
1830 - \li QVariant::Color
1831 - \li QVariant::Cursor
1832 - \li QVariant::Date
1833 - \li QVariant::DateTime
1834 - \li QVariant::Double
1835 - \li QVariant::Int
1836 - \li QVariant::Point
1837 - \li QVariant::Rect
1838 - \li QVariant::Size
1839 - \li QVariant::SizePolicy
1840 - \li QVariant::String
1841 - \li QVariant::Time
1842 - \li QVariant::UInt
1843 - \endlist
1844 -
1845 - For a complete example using the QDesignerCustomWidgetInterface
1846 - class, see the \l {customwidgetplugin}{Custom Widget
1847 - Example}. The example shows how to create a custom widget plugin
1848 - for \QD.
1849 -
1850 - \sa QDesignerCustomWidgetCollectionInterface, {Creating Custom Widgets for Qt Designer}
1851 -*/
1852 -
1853 -/*!
1854 - \fn QDesignerCustomWidgetInterface::~QDesignerCustomWidgetInterface()
1855 -
1856 - Destroys the custom widget interface.
1857 -*/
1858 -
1859 -/*!
1860 - \fn QString QDesignerCustomWidgetInterface::name() const
1861 -
1862 - Returns the class name of the custom widget supplied by the interface.
1863 -
1864 - The name returned \e must be identical to the class name used for the
1865 - custom widget.
1866 -*/
1867 -
1868 -/*!
1869 - \fn QString QDesignerCustomWidgetInterface::group() const
1870 -
1871 - Returns the name of the group to which the custom widget belongs.
1872 -*/
1873 -
1874 -/*!
1875 - \fn QString QDesignerCustomWidgetInterface::toolTip() const
1876 -
1877 - Returns a short description of the widget that can be used by \QD
1878 - in a tool tip.
1879 -*/
1880 -
1881 -/*!
1882 - \fn QString QDesignerCustomWidgetInterface::whatsThis() const
1883 -
1884 - Returns a description of the widget that can be used by \QD in
1885 - "What's This?" help for the widget.
1886 -*/
1887 -
1888 -/*!
1889 - \fn QString QDesignerCustomWidgetInterface::includeFile() const
1890 -
1891 - Returns the path to the include file that \l uic uses when
1892 - creating code for the custom widget.
1893 -*/
1894 -
1895 -/*!
1896 - \fn QIcon QDesignerCustomWidgetInterface::icon() const
1897 -
1898 - Returns the icon used to represent the custom widget in \QD's
1899 - widget box.
1900 -*/
1901 -
1902 -/*!
1903 - \fn bool QDesignerCustomWidgetInterface::isContainer() const
1904 -
1905 - Returns true if the custom widget is intended to be used as a
1906 - container; otherwise returns false.
1907 -
1908 - Most custom widgets are not used to hold other widgets, so their
1909 - implementations of this function will return false, but custom
1910 - containers will return true to ensure that they behave correctly
1911 - in \QD.
1912 -*/
1913 -
1914 -/*!
1915 - \fn QWidget *QDesignerCustomWidgetInterface::createWidget(QWidget *parent)
1916 -
1917 - Returns a new instance of the custom widget, with the given \a
1918 - parent.
1919 -*/
1920 -
1921 -/*!
1922 - \fn bool QDesignerCustomWidgetInterface::isInitialized() const
1923 -
1924 - Returns true if the widget has been initialized; otherwise returns
1925 - false.
1926 -
1927 - \sa initialize()
1928 -*/
1929 -
1930 -/*!
1931 - \fn void QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor)
1932 -
1933 - Initializes the widget for use with the specified \a formEditor
1934 - interface.
1935 -
1936 - \sa isInitialized()
1937 -*/
1938 -
1939 -/*!
1940 - \fn QString QDesignerCustomWidgetInterface::domXml() const
1941 -
1942 - Returns the XML that is used to describe the custom widget's
1943 - properties to \QD.
1944 -*/
1945 -
1946 -/*!
1947 - \fn QString QDesignerCustomWidgetInterface::codeTemplate() const
1948 -
1949 - This function is reserved for future use by \QD.
1950 -
1951 - \omit
1952 - Returns the code template that \QD includes in forms that contain
1953 - the custom widget when they are saved.
1954 - \endomit
1955 -*/
1956 -
1957 -/*!
1958 - \macro QDESIGNER_WIDGET_EXPORT
1959 - \relates QDesignerCustomWidgetInterface
1960 - \since 4.1
1961 -
1962 - This macro is used when defining custom widgets to ensure that they are
1963 - correctly exported from plugins for use with \QD.
1964 -
1965 - On some platforms, the symbols required by \QD to create new widgets
1966 - are removed from plugins by the build system, making them unusable.
1967 - Using this macro ensures that the symbols are retained on those platforms,
1968 - and has no side effects on other platforms.
1969 -
1970 - For example, the \l{worldtimeclockplugin}{World Time Clock Plugin}
1971 - example exports a custom widget class with the following declaration:
1972 -
1973 - \snippet worldtimeclockplugin/worldtimeclock.h 0
1974 - \dots
1975 - \snippet worldtimeclockplugin/worldtimeclock.h 2
1976 -
1977 - \sa {Creating Custom Widgets for Qt Designer}
1978 -*/
1979 -
1980 -
1981 -
1982 -
1983 -
1984 -/*!
1985 - \class QDesignerCustomWidgetCollectionInterface
1986 -
1987 - \brief The QDesignerCustomWidgetCollectionInterface class allows
1988 - you to include several custom widgets in one single library.
1989 -
1990 - \inmodule QtDesigner
1991 -
1992 - When implementing a custom widget plugin, you build it as a
1993 - separate library. If you want to include several custom widget
1994 - plugins in the same library, you must in addition subclass
1995 - QDesignerCustomWidgetCollectionInterface.
1996 -
1997 - QDesignerCustomWidgetCollectionInterface contains one single
1998 - function returning a list of the collection's
1999 - QDesignerCustomWidgetInterface objects. For example, if you have
2000 - several custom widgets \c CustomWidgetOne, \c CustomWidgetTwo and
2001 - \c CustomWidgetThree, the class definition may look like this:
2002 -
2003 - \snippet plugins/doc_src_qtdesigner.cpp 12
2004 -
2005 - In the class constructor you add the interfaces to your custom
2006 - widgets to the list which you return in the customWidgets()
2007 - function:
2008 -
2009 - \snippet plugins/doc_src_qtdesigner.cpp 13
2010 -
2011 - Note that instead of exporting each custom widget plugin using the
2012 - Q_PLUGIN_METADATA() macro, you export the entire collection. The
2013 - Q_PLUGIN_METADATA() macro ensures that \QD can access and construct
2014 - the custom widgets. Without this macro, there is no way for \QD to
2015 - use them.
2016 -
2017 - \sa QDesignerCustomWidgetInterface, {Creating Custom Widgets for
2018 - Qt Designer}
2019 -*/
2020 -
2021 -/*!
2022 - \fn QDesignerCustomWidgetCollectionInterface::~QDesignerCustomWidgetCollectionInterface() {
2023 -
2024 - Destroys the custom widget collection interface.
2025 -*/
2026 -
2027 -/*!
2028 - \fn QList<QDesignerCustomWidgetInterface*> QDesignerCustomWidgetCollectionInterface::customWidgets() const
2029 -
2030 - Returns a list of interfaces to the collection's custom widgets.
2031 -*/
2032 diff --git x/qttools/src/uiplugin/qdesignerexportwidget.h y/qttools/src/uiplugin/qdesignerexportwidget.h
2033 deleted file mode 100644
2034 index d90e9b217..000000000
2035 --- x/qttools/src/uiplugin/qdesignerexportwidget.h
2036 +++ /dev/null
2037 @@ -1,24 +0,0 @@
2038 -// Copyright (C) 2016 The Qt Company Ltd.
2039 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
2040 -
2041 -#ifndef QDESIGNEREXPORTWIDGET_H
2042 -#define QDESIGNEREXPORTWIDGET_H
2043 -
2044 -#include <QtCore/qglobal.h>
2045 -
2046 -QT_BEGIN_NAMESPACE
2047 -
2048 -#if 0
2049 -// pragma for syncqt, don't remove.
2050 -#pragma qt_class(QDesignerExportWidget)
2051 -#endif
2052 -
2053 -#if defined(QDESIGNER_EXPORT_WIDGETS)
2054 -# define QDESIGNER_WIDGET_EXPORT Q_DECL_EXPORT
2055 -#else
2056 -# define QDESIGNER_WIDGET_EXPORT Q_DECL_IMPORT
2057 -#endif
2058 -
2059 -QT_END_NAMESPACE
2060 -
2061 -#endif //QDESIGNEREXPORTWIDGET_H
2062 diff --git x/qttools/src/uitools/CMakeLists.txt y/qttools/src/uitools/CMakeLists.txt
2063 deleted file mode 100644
2064 index 448bd1840..000000000
2065 --- x/qttools/src/uitools/CMakeLists.txt
2066 +++ /dev/null
2067 @@ -1,47 +0,0 @@
2068 -# Generated from uitools.pro.
2069 -
2070 -#####################################################################
2071 -## UiTools Module:
2072 -#####################################################################
2073 -
2074 -qt_internal_add_module(UiTools
2075 - SOURCES
2076 - ../designer/src/lib/uilib/abstractformbuilder.cpp ../designer/src/lib/uilib/abstractformbuilder.h
2077 - ../designer/src/lib/uilib/formbuilder.cpp ../designer/src/lib/uilib/formbuilder.h
2078 - ../designer/src/lib/uilib/formbuilderextra.cpp ../designer/src/lib/uilib/formbuilderextra_p.h
2079 - ../designer/src/lib/uilib/properties.cpp ../designer/src/lib/uilib/properties_p.h
2080 - ../designer/src/lib/uilib/resourcebuilder.cpp ../designer/src/lib/uilib/resourcebuilder_p.h
2081 - ../designer/src/lib/uilib/textbuilder.cpp ../designer/src/lib/uilib/textbuilder_p.h
2082 - ../designer/src/lib/uilib/ui4.cpp ../designer/src/lib/uilib/ui4_p.h
2083 - quiloader.cpp quiloader.h
2084 - DEFINES
2085 - QFORMINTERNAL_NAMESPACE
2086 - QT_DESIGNER
2087 - QT_DESIGNER_STATIC
2088 - QT_USE_QSTRINGBUILDER
2089 - INCLUDE_DIRECTORIES
2090 - ../designer/src/lib/uilib
2091 - LIBRARIES
2092 - Qt::UiPlugin
2093 - PUBLIC_LIBRARIES
2094 - Qt::Core
2095 - Qt::Gui
2096 - Qt::Widgets
2097 -)
2098 -
2099 -## Scopes:
2100 -#####################################################################
2101 -
2102 -qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets
2103 - PUBLIC_LIBRARIES
2104 - Qt::OpenGLWidgets
2105 -)
2106 -
2107 -qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGL
2108 - LIBRARIES
2109 - Qt::OpenGL
2110 -)
2111 -qt_internal_add_docs(UiTools
2112 - doc/qtuitools.qdocconf
2113 -)
2114 -
2115 diff --git x/qttools/src/uitools/qtuitoolsglobal.h y/qttools/src/uitools/qtuitoolsglobal.h
2116 deleted file mode 100644
2117 index a2f967dee..000000000
2118 --- x/qttools/src/uitools/qtuitoolsglobal.h
2119 +++ /dev/null
2120 @@ -1,24 +0,0 @@
2121 -// Copyright (C) 2020 The Qt Company Ltd.
2122 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
2123 -
2124 -#ifndef QTUITOOLSGLOBAL_H
2125 -#define QTUITOOLSGLOBAL_H
2126 -
2127 -#include <QtCore/qglobal.h>
2128 -
2129 -QT_BEGIN_NAMESPACE
2130 -
2131 -#ifndef QT_STATIC
2132 -# if defined(QT_BUILD_UITOOLS_LIB)
2133 -# define Q_UITOOLS_EXPORT Q_DECL_EXPORT
2134 -# else
2135 -# define Q_UITOOLS_EXPORT Q_DECL_IMPORT
2136 -# endif
2137 -#else
2138 -# define Q_UITOOLS_EXPORT
2139 -#endif
2140 -
2141 -QT_END_NAMESPACE
2142 -
2143 -#endif // QTUITOOLSGLOBAL_H
2144 -
2145 diff --git x/qttools/src/uitools/quiloader.cpp y/qttools/src/uitools/quiloader.cpp
2146 deleted file mode 100644
2147 index a06d4717b..000000000
2148 --- x/qttools/src/uitools/quiloader.cpp
2149 +++ /dev/null
2150 @@ -1,914 +0,0 @@
2151 -// Copyright (C) 2020 The Qt Company Ltd.
2152 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
2153 -
2154 -
2155 -#include "quiloader.h"
2156 -#include "quiloader_p.h"
2157 -
2158 -#include <QtUiPlugin/customwidget.h>
2159 -
2160 -#include <formbuilder.h>
2161 -#include <formbuilderextra_p.h>
2162 -#include <textbuilder_p.h>
2163 -#include <ui4_p.h>
2164 -
2165 -#include <QtWidgets/qapplication.h>
2166 -#include <QtWidgets/qlayout.h>
2167 -#include <QtWidgets/qwidget.h>
2168 -#include <QtWidgets/qtabwidget.h>
2169 -#include <QtWidgets/qtreewidget.h>
2170 -#include <QtWidgets/qlistwidget.h>
2171 -#include <QtWidgets/qtablewidget.h>
2172 -#include <QtWidgets/qtoolbox.h>
2173 -#include <QtWidgets/qcombobox.h>
2174 -#include <QtWidgets/qfontcombobox.h>
2175 -
2176 -#include <QtGui/qaction.h>
2177 -#include <QtGui/qactiongroup.h>
2178 -
2179 -#include <QtCore/qdebug.h>
2180 -#include <QtCore/qdatastream.h>
2181 -#include <QtCore/qmap.h>
2182 -#include <QtCore/qdir.h>
2183 -#include <QtCore/qlibraryinfo.h>
2184 -
2185 -QT_BEGIN_NAMESPACE
2186 -
2187 -typedef QMap<QString, bool> widget_map;
2188 -Q_GLOBAL_STATIC(widget_map, g_widgets)
2189 -
2190 -class QUiLoader;
2191 -class QUiLoaderPrivate;
2192 -
2193 -#ifndef QT_NO_DATASTREAM
2194 -// QUiTranslatableStringValue must be streamable since they become part of the QVariant-based
2195 -// mime data when dragging items in views with QAbstractItemView::InternalMove.
2196 -QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s)
2197 -{
2198 - out << s.qualifier() << s.value();
2199 - return out;
2200 -}
2201 -
2202 -QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s)
2203 -{
2204 - QByteArray qualifier, value;
2205 - in >> qualifier >> value;
2206 - s.setQualifier(qualifier);
2207 - s.setValue(value);
2208 - return in;
2209 -}
2210 -#endif // QT_NO_DATASTREAM
2211 -
2212 -QString QUiTranslatableStringValue::translate(const QByteArray &className, bool idBased) const
2213 -{
2214 - return idBased
2215 - ? qtTrId(m_qualifier.constData())
2216 - : QCoreApplication::translate(className.constData(), m_value.constData(), m_qualifier.constData());
2217 -}
2218 -
2219 -#ifdef QFORMINTERNAL_NAMESPACE
2220 -namespace QFormInternal
2221 -{
2222 -#endif
2223 -
2224 -class TranslatingTextBuilder : public QTextBuilder
2225 -{
2226 -public:
2227 - explicit TranslatingTextBuilder(bool idBased, bool trEnabled, const QByteArray &className) :
2228 - m_idBased(idBased), m_trEnabled(trEnabled), m_className(className) {}
2229 -
2230 - QVariant loadText(const DomProperty *icon) const override;
2231 -
2232 - QVariant toNativeValue(const QVariant &value) const override;
2233 -
2234 - bool idBased() const { return m_idBased; }
2235 -
2236 -private:
2237 - bool m_idBased;
2238 - bool m_trEnabled;
2239 - QByteArray m_className;
2240 -};
2241 -
2242 -QVariant TranslatingTextBuilder::loadText(const DomProperty *text) const
2243 -{
2244 - const DomString *str = text->elementString();
2245 - if (!str)
2246 - return QVariant();
2247 - if (str->hasAttributeNotr()) {
2248 - const QString notr = str->attributeNotr();
2249 - if (notr == QStringLiteral("true") || notr == QStringLiteral("yes"))
2250 - return QVariant::fromValue(str->text());
2251 - }
2252 - QUiTranslatableStringValue strVal;
2253 - strVal.setValue(str->text().toUtf8());
2254 - if (m_idBased)
2255 - strVal.setQualifier(str->attributeId().toUtf8());
2256 - else if (str->hasAttributeComment())
2257 - strVal.setQualifier(str->attributeComment().toUtf8());
2258 - return QVariant::fromValue(strVal);
2259 -}
2260 -
2261 -QVariant TranslatingTextBuilder::toNativeValue(const QVariant &value) const
2262 -{
2263 - if (value.canConvert<QUiTranslatableStringValue>()) {
2264 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(value);
2265 - if (!m_trEnabled)
2266 - return QString::fromUtf8(tsv.value().constData());
2267 - return QVariant::fromValue(tsv.translate(m_className, m_idBased));
2268 - }
2269 - if (value.canConvert<QString>())
2270 - return QVariant::fromValue(qvariant_cast<QString>(value));
2271 - return value;
2272 -}
2273 -
2274 -// This is "exported" to linguist
2275 -const QUiItemRolePair qUiItemRoles[] = {
2276 - { Qt::DisplayRole, Qt::DisplayPropertyRole },
2277 -#if QT_CONFIG(tooltip)
2278 - { Qt::ToolTipRole, Qt::ToolTipPropertyRole },
2279 -#endif
2280 -#if QT_CONFIG(statustip)
2281 - { Qt::StatusTipRole, Qt::StatusTipPropertyRole },
2282 -#endif
2283 -#if QT_CONFIG(whatsthis)
2284 - { Qt::WhatsThisRole, Qt::WhatsThisPropertyRole },
2285 -#endif
2286 - { -1 , -1 }
2287 -};
2288 -
2289 -static void recursiveReTranslate(QTreeWidgetItem *item, const QByteArray &class_name, bool idBased)
2290 -{
2291 - const QUiItemRolePair *irs = qUiItemRoles;
2292 -
2293 - int cnt = item->columnCount();
2294 - for (int i = 0; i < cnt; ++i) {
2295 - for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
2296 - QVariant v = item->data(i, irs[j].shadowRole);
2297 - if (v.isValid()) {
2298 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
2299 - item->setData(i, irs[j].realRole, tsv.translate(class_name, idBased));
2300 - }
2301 - }
2302 - }
2303 -
2304 - cnt = item->childCount();
2305 - for (int i = 0; i < cnt; ++i)
2306 - recursiveReTranslate(item->child(i), class_name, idBased);
2307 -}
2308 -
2309 -template<typename T>
2310 -static void reTranslateWidgetItem(T *item, const QByteArray &class_name, bool idBased)
2311 -{
2312 - const QUiItemRolePair *irs = qUiItemRoles;
2313 -
2314 - for (unsigned j = 0; irs[j].shadowRole >= 0; j++) {
2315 - QVariant v = item->data(irs[j].shadowRole);
2316 - if (v.isValid()) {
2317 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
2318 - item->setData(irs[j].realRole, tsv.translate(class_name, idBased));
2319 - }
2320 - }
2321 -}
2322 -
2323 -static void reTranslateTableItem(QTableWidgetItem *item, const QByteArray &class_name, bool idBased)
2324 -{
2325 - if (item)
2326 - reTranslateWidgetItem(item, class_name, idBased);
2327 -}
2328 -
2329 -#define RETRANSLATE_SUBWIDGET_PROP(mainWidget, setter, propName) \
2330 - do { \
2331 - QVariant v = mainWidget->widget(i)->property(propName); \
2332 - if (v.isValid()) { \
2333 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v); \
2334 - mainWidget->setter(i, tsv.translate(m_className, m_idBased)); \
2335 - } \
2336 - } while (0)
2337 -
2338 -class TranslationWatcher: public QObject
2339 -{
2340 - Q_OBJECT
2341 -
2342 -public:
2343 - explicit TranslationWatcher(QObject *parent, const QByteArray &className, bool idBased):
2344 - QObject(parent),
2345 - m_className(className),
2346 - m_idBased(idBased)
2347 - {
2348 - }
2349 -
2350 - bool eventFilter(QObject *o, QEvent *event) override
2351 - {
2352 - if (event->type() == QEvent::LanguageChange) {
2353 - const auto &dynamicPropertyNames = o->dynamicPropertyNames();
2354 - for (const QByteArray &prop : dynamicPropertyNames) {
2355 - if (prop.startsWith(PROP_GENERIC_PREFIX)) {
2356 - const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1);
2357 - const QUiTranslatableStringValue tsv =
2358 - qvariant_cast<QUiTranslatableStringValue>(o->property(prop));
2359 - o->setProperty(propName, tsv.translate(m_className, m_idBased));
2360 - }
2361 - }
2362 - if (0) {
2363 -#if QT_CONFIG(tabwidget)
2364 - } else if (QTabWidget *tabw = qobject_cast<QTabWidget*>(o)) {
2365 - const int cnt = tabw->count();
2366 - for (int i = 0; i < cnt; ++i) {
2367 - RETRANSLATE_SUBWIDGET_PROP(tabw, setTabText, PROP_TABPAGETEXT);
2368 -#if QT_CONFIG(tooltip)
2369 - RETRANSLATE_SUBWIDGET_PROP(tabw, setTabToolTip, PROP_TABPAGETOOLTIP);
2370 -# endif
2371 -#if QT_CONFIG(whatsthis)
2372 - RETRANSLATE_SUBWIDGET_PROP(tabw, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
2373 -# endif
2374 - }
2375 -#endif
2376 -#if QT_CONFIG(listwidget)
2377 - } else if (QListWidget *listw = qobject_cast<QListWidget*>(o)) {
2378 - const int cnt = listw->count();
2379 - for (int i = 0; i < cnt; ++i)
2380 - reTranslateWidgetItem(listw->item(i), m_className, m_idBased);
2381 -#endif
2382 -#if QT_CONFIG(treewidget)
2383 - } else if (QTreeWidget *treew = qobject_cast<QTreeWidget*>(o)) {
2384 - if (QTreeWidgetItem *item = treew->headerItem())
2385 - recursiveReTranslate(item, m_className, m_idBased);
2386 - const int cnt = treew->topLevelItemCount();
2387 - for (int i = 0; i < cnt; ++i) {
2388 - QTreeWidgetItem *item = treew->topLevelItem(i);
2389 - recursiveReTranslate(item, m_className, m_idBased);
2390 - }
2391 -#endif
2392 -#if QT_CONFIG(tablewidget)
2393 - } else if (QTableWidget *tablew = qobject_cast<QTableWidget*>(o)) {
2394 - const int row_cnt = tablew->rowCount();
2395 - const int col_cnt = tablew->columnCount();
2396 - for (int j = 0; j < col_cnt; ++j)
2397 - reTranslateTableItem(tablew->horizontalHeaderItem(j), m_className, m_idBased);
2398 - for (int i = 0; i < row_cnt; ++i) {
2399 - reTranslateTableItem(tablew->verticalHeaderItem(i), m_className, m_idBased);
2400 - for (int j = 0; j < col_cnt; ++j)
2401 - reTranslateTableItem(tablew->item(i, j), m_className, m_idBased);
2402 - }
2403 -#endif
2404 -#if QT_CONFIG(combobox)
2405 - } else if (QComboBox *combow = qobject_cast<QComboBox*>(o)) {
2406 - if (!qobject_cast<QFontComboBox*>(o)) {
2407 - const int cnt = combow->count();
2408 - for (int i = 0; i < cnt; ++i) {
2409 - const QVariant v = combow->itemData(i, Qt::DisplayPropertyRole);
2410 - if (v.isValid()) {
2411 - QUiTranslatableStringValue tsv = qvariant_cast<QUiTranslatableStringValue>(v);
2412 - combow->setItemText(i, tsv.translate(m_className, m_idBased));
2413 - }
2414 - }
2415 - }
2416 -#endif
2417 -#if QT_CONFIG(toolbox)
2418 - } else if (QToolBox *toolw = qobject_cast<QToolBox*>(o)) {
2419 - const int cnt = toolw->count();
2420 - for (int i = 0; i < cnt; ++i) {
2421 - RETRANSLATE_SUBWIDGET_PROP(toolw, setItemText, PROP_TOOLITEMTEXT);
2422 -#if QT_CONFIG(tooltip)
2423 - RETRANSLATE_SUBWIDGET_PROP(toolw, setItemToolTip, PROP_TOOLITEMTOOLTIP);
2424 -# endif
2425 - }
2426 -#endif
2427 - }
2428 - }
2429 - return false;
2430 - }
2431 -
2432 -private:
2433 - QByteArray m_className;
2434 - bool m_idBased;
2435 -};
2436 -
2437 -class FormBuilderPrivate: public QFormBuilder
2438 -{
2439 - friend class QT_PREPEND_NAMESPACE(QUiLoader);
2440 - friend class QT_PREPEND_NAMESPACE(QUiLoaderPrivate);
2441 - using ParentClass = QFormBuilder;
2442 -
2443 -public:
2444 - QUiLoader *loader = nullptr;
2445 -
2446 - bool dynamicTr = false;
2447 - bool trEnabled = true;
2448 -
2449 - FormBuilderPrivate() = default;
2450 -
2451 - QWidget *defaultCreateWidget(const QString &className, QWidget *parent, const QString &name)
2452 - {
2453 - return ParentClass::createWidget(className, parent, name);
2454 - }
2455 -
2456 - QLayout *defaultCreateLayout(const QString &className, QObject *parent, const QString &name)
2457 - {
2458 - return ParentClass::createLayout(className, parent, name);
2459 - }
2460 -
2461 - QAction *defaultCreateAction(QObject *parent, const QString &name)
2462 - {
2463 - return ParentClass::createAction(parent, name);
2464 - }
2465 -
2466 - QActionGroup *defaultCreateActionGroup(QObject *parent, const QString &name)
2467 - {
2468 - return ParentClass::createActionGroup(parent, name);
2469 - }
2470 -
2471 - QWidget *createWidget(const QString &className, QWidget *parent, const QString &name) override
2472 - {
2473 - if (QWidget *widget = loader->createWidget(className, parent, name)) {
2474 - widget->setObjectName(name);
2475 - return widget;
2476 - }
2477 -
2478 - return nullptr;
2479 - }
2480 -
2481 - QLayout *createLayout(const QString &className, QObject *parent, const QString &name) override
2482 - {
2483 - if (QLayout *layout = loader->createLayout(className, parent, name)) {
2484 - layout->setObjectName(name);
2485 - return layout;
2486 - }
2487 -
2488 - return nullptr;
2489 - }
2490 -
2491 - QActionGroup *createActionGroup(QObject *parent, const QString &name) override
2492 - {
2493 - if (QActionGroup *actionGroup = loader->createActionGroup(parent, name)) {
2494 - actionGroup->setObjectName(name);
2495 - return actionGroup;
2496 - }
2497 -
2498 - return nullptr;
2499 - }
2500 -
2501 - QAction *createAction(QObject *parent, const QString &name) override
2502 - {
2503 - if (QAction *action = loader->createAction(parent, name)) {
2504 - action->setObjectName(name);
2505 - return action;
2506 - }
2507 -
2508 - return nullptr;
2509 - }
2510 -
2511 - void applyProperties(QObject *o, const QList<DomProperty*> &properties) override;
2512 - QWidget *create(DomUI *ui, QWidget *parentWidget) override;
2513 - QWidget *create(DomWidget *ui_widget, QWidget *parentWidget) override;
2514 - bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) override;
2515 -
2516 -private:
2517 - QByteArray m_class;
2518 - TranslationWatcher *m_trwatch = nullptr;
2519 - bool m_idBased = false;
2520 -};
2521 -
2522 -static QString convertTranslatable(const DomProperty *p, const QByteArray &className,
2523 - bool idBased, QUiTranslatableStringValue *strVal)
2524 -{
2525 - if (p->kind() != DomProperty::String)
2526 - return QString();
2527 - const DomString *dom_str = p->elementString();
2528 - if (!dom_str)
2529 - return QString();
2530 - if (dom_str->hasAttributeNotr()) {
2531 - const QString notr = dom_str->attributeNotr();
2532 - if (notr == QStringLiteral("yes") || notr == QStringLiteral("true"))
2533 - return QString();
2534 - }
2535 - strVal->setValue(dom_str->text().toUtf8());
2536 - strVal->setQualifier(idBased ? dom_str->attributeId().toUtf8() : dom_str->attributeComment().toUtf8());
2537 - if (strVal->value().isEmpty() && strVal->qualifier().isEmpty())
2538 - return QString();
2539 - return strVal->translate(className, idBased);
2540 -}
2541 -
2542 -void FormBuilderPrivate::applyProperties(QObject *o, const QList<DomProperty*> &properties)
2543 -{
2544 - QFormBuilder::applyProperties(o, properties);
2545 -
2546 - if (!m_trwatch)
2547 - m_trwatch = new TranslationWatcher(o, m_class, m_idBased);
2548 -
2549 - if (properties.isEmpty())
2550 - return;
2551 -
2552 - // Unlike string item roles, string properties are not loaded via the textBuilder
2553 - // (as they are "shadowed" by the property sheets in designer). So do the initial
2554 - // translation here.
2555 - bool anyTrs = false;
2556 - for (const DomProperty *p : properties) {
2557 - QUiTranslatableStringValue strVal;
2558 - const QString text = convertTranslatable(p, m_class, m_idBased, &strVal);
2559 - if (text.isEmpty())
2560 - continue;
2561 - const QByteArray name = p->attributeName().toUtf8();
2562 - if (dynamicTr) {
2563 - const QByteArray dynname = QByteArray(PROP_GENERIC_PREFIX + name);
2564 - o->setProperty(dynname, QVariant::fromValue(strVal));
2565 - anyTrs = trEnabled;
2566 - }
2567 - if (p->elementString()->text() != text)
2568 - o->setProperty(name, text);
2569 - }
2570 - if (anyTrs)
2571 - o->installEventFilter(m_trwatch);
2572 -}
2573 -
2574 -QWidget *FormBuilderPrivate::create(DomUI *ui, QWidget *parentWidget)
2575 -{
2576 - m_class = ui->elementClass().toUtf8();
2577 - m_trwatch = nullptr;
2578 - m_idBased = ui->attributeIdbasedtr();
2579 - setTextBuilder(new TranslatingTextBuilder(m_idBased, trEnabled, m_class));
2580 - return QFormBuilder::create(ui, parentWidget);
2581 -}
2582 -
2583 -QWidget *FormBuilderPrivate::create(DomWidget *ui_widget, QWidget *parentWidget)
2584 -{
2585 - QWidget *w = QFormBuilder::create(ui_widget, parentWidget);
2586 - if (w == nullptr)
2587 - return nullptr;
2588 -
2589 - if (0) {
2590 -#if QT_CONFIG(tabwidget)
2591 - } else if (qobject_cast<QTabWidget*>(w)) {
2592 -#endif
2593 -#if QT_CONFIG(listwidget)
2594 - } else if (qobject_cast<QListWidget*>(w)) {
2595 -#endif
2596 -#if QT_CONFIG(treewidget)
2597 - } else if (qobject_cast<QTreeWidget*>(w)) {
2598 -#endif
2599 -#if QT_CONFIG(tablewidget)
2600 - } else if (qobject_cast<QTableWidget*>(w)) {
2601 -#endif
2602 -#if QT_CONFIG(combobox)
2603 - } else if (qobject_cast<QComboBox*>(w)) {
2604 - if (qobject_cast<QFontComboBox*>(w))
2605 - return w;
2606 -#endif
2607 -#if QT_CONFIG(toolbox)
2608 - } else if (qobject_cast<QToolBox*>(w)) {
2609 -#endif
2610 - } else {
2611 - return w;
2612 - }
2613 - if (dynamicTr && trEnabled)
2614 - w->installEventFilter(m_trwatch);
2615 - return w;
2616 -}
2617 -
2618 -#define TRANSLATE_SUBWIDGET_PROP(mainWidget, attribute, setter, propName) \
2619 - do { \
2620 - if (const DomProperty *p##attribute = attributes.value(strings.attribute)) { \
2621 - QUiTranslatableStringValue strVal; \
2622 - const QString text = convertTranslatable(p##attribute, m_class, m_idBased, &strVal); \
2623 - if (!text.isEmpty()) { \
2624 - if (dynamicTr) \
2625 - mainWidget->widget(i)->setProperty(propName, QVariant::fromValue(strVal)); \
2626 - mainWidget->setter(i, text); \
2627 - } \
2628 - } \
2629 - } while (0)
2630 -
2631 -bool FormBuilderPrivate::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget)
2632 -{
2633 - if (parentWidget == nullptr)
2634 - return true;
2635 -
2636 - if (!ParentClass::addItem(ui_widget, widget, parentWidget))
2637 - return false;
2638 -
2639 - // Check special cases. First: Custom container
2640 - const QString className = QLatin1String(parentWidget->metaObject()->className());
2641 - if (!d->customWidgetAddPageMethod(className).isEmpty())
2642 - return true;
2643 -
2644 - const QFormBuilderStrings &strings = QFormBuilderStrings::instance();
2645 -
2646 - if (0) {
2647 -#if QT_CONFIG(tabwidget)
2648 - } else if (QTabWidget *tabWidget = qobject_cast<QTabWidget*>(parentWidget)) {
2649 - const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
2650 - const int i = tabWidget->count() - 1;
2651 - TRANSLATE_SUBWIDGET_PROP(tabWidget, titleAttribute, setTabText, PROP_TABPAGETEXT);
2652 -#if QT_CONFIG(tooltip)
2653 - TRANSLATE_SUBWIDGET_PROP(tabWidget, toolTipAttribute, setTabToolTip, PROP_TABPAGETOOLTIP);
2654 -# endif
2655 -#if QT_CONFIG(whatsthis)
2656 - TRANSLATE_SUBWIDGET_PROP(tabWidget, whatsThisAttribute, setTabWhatsThis, PROP_TABPAGEWHATSTHIS);
2657 -# endif
2658 -#endif
2659 -#if QT_CONFIG(toolbox)
2660 - } else if (QToolBox *toolBox = qobject_cast<QToolBox*>(parentWidget)) {
2661 - const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute());
2662 - const int i = toolBox->count() - 1;
2663 - TRANSLATE_SUBWIDGET_PROP(toolBox, labelAttribute, setItemText, PROP_TOOLITEMTEXT);
2664 -#if QT_CONFIG(tooltip)
2665 - TRANSLATE_SUBWIDGET_PROP(toolBox, toolTipAttribute, setItemToolTip, PROP_TOOLITEMTOOLTIP);
2666 -# endif
2667 -#endif
2668 - }
2669 -
2670 - return true;
2671 -}
2672 -
2673 -#ifdef QFORMINTERNAL_NAMESPACE
2674 -}
2675 -#endif
2676 -
2677 -class QUiLoaderPrivate
2678 -{
2679 -public:
2680 -#ifdef QFORMINTERNAL_NAMESPACE
2681 - QFormInternal::FormBuilderPrivate builder;
2682 -#else
2683 - FormBuilderPrivate builder;
2684 -#endif
2685 -
2686 - void setupWidgetMap() const;
2687 -};
2688 -
2689 -void QUiLoaderPrivate::setupWidgetMap() const
2690 -{
2691 - if (!g_widgets()->isEmpty())
2692 - return;
2693 -
2694 -#define DECLARE_WIDGET(a, b) g_widgets()->insert(QLatin1String(#a), true);
2695 -#define DECLARE_LAYOUT(a, b)
2696 -
2697 -#include "widgets.table"
2698 -
2699 -#undef DECLARE_WIDGET
2700 -#undef DECLARE_WIDGET_1
2701 -#undef DECLARE_LAYOUT
2702 -}
2703 -
2704 -/*!
2705 - \class QUiLoader
2706 - \inmodule QtUiTools
2707 -
2708 - \brief The QUiLoader class enables standalone applications to
2709 - dynamically create user interfaces at run-time using the
2710 - information stored in UI files or specified in plugin paths.
2711 -
2712 - In addition, you can customize or create your own user interface by
2713 - deriving your own loader class.
2714 -
2715 - If you have a custom component or an application that embeds \QD, you can
2716 - also use the QFormBuilder class provided by the QtDesigner module to create
2717 - user interfaces from UI files.
2718 -
2719 - The QUiLoader class provides a collection of functions allowing you to
2720 - create widgets based on the information stored in UI files (created
2721 - with \QD) or available in the specified plugin paths. The specified plugin
2722 - paths can be retrieved using the pluginPaths() function. Similarly, the
2723 - contents of a UI file can be retrieved using the load() function. For
2724 - example:
2725 -
2726 - \snippet quiloader/mywidget.cpp 0
2727 -
2728 - \if !defined(qtforpython)
2729 - By including the user interface in the form's resources (\c myform.qrc), we
2730 - ensure that it will be present at run-time:
2731 -
2732 - \quotefile quiloader/mywidget.qrc
2733 - \endif
2734 -
2735 - The availableWidgets() function returns a QStringList with the class names
2736 - of the widgets available in the specified plugin paths. To create these
2737 - widgets, simply use the createWidget() function. For example:
2738 -
2739 - \snippet quiloader/main.cpp 0
2740 -
2741 - To make a custom widget available to the loader, you can use the
2742 - addPluginPath() function; to remove all available widgets, you can call
2743 - the clearPluginPaths() function.
2744 -
2745 - The createAction(), createActionGroup(), createLayout(), and createWidget()
2746 - functions are used internally by the QUiLoader class whenever it has to
2747 - create an action, action group, layout, or widget respectively. For that
2748 - reason, you can subclass the QUiLoader class and reimplement these
2749 - functions to intervene the process of constructing a user interface. For
2750 - example, you might want to have a list of the actions created when loading
2751 - a form or creating a custom widget.
2752 -
2753 - For a complete example using the QUiLoader class, see the
2754 - \l{Calculator Builder Example}.
2755 -
2756 - \sa {Qt UI Tools}, QFormBuilder
2757 -*/
2758 -
2759 -/*!
2760 - Creates a form loader with the given \a parent.
2761 -*/
2762 -QUiLoader::QUiLoader(QObject *parent)
2763 - : QObject(parent), d_ptr(new QUiLoaderPrivate)
2764 -{
2765 - Q_D(QUiLoader);
2766 -
2767 -#ifndef QT_NO_DATASTREAM
2768 - static int metaTypeId = 0;
2769 - if (!metaTypeId) {
2770 - metaTypeId = qRegisterMetaType<QUiTranslatableStringValue>("QUiTranslatableStringValue");
2771 - }
2772 -#endif // QT_NO_DATASTREAM
2773 - d->builder.loader = this;
2774 -
2775 -#if QT_CONFIG(library)
2776 - QStringList paths;
2777 - const QStringList &libraryPaths = QApplication::libraryPaths();
2778 - for (const QString &path : libraryPaths) {
2779 - QString libPath = path;
2780 - libPath += QDir::separator();
2781 - libPath += QStringLiteral("designer");
2782 - paths.append(libPath);
2783 - }
2784 -
2785 - d->builder.setPluginPath(paths);
2786 -#endif // QT_CONFIG(library)
2787 -}
2788 -
2789 -/*!
2790 - Destroys the loader.
2791 -*/
2792 -QUiLoader::~QUiLoader() = default;
2793 -
2794 -/*!
2795 - Loads a form from the given \a device and creates a new widget with the
2796 - given \a parentWidget to hold its contents.
2797 -
2798 - \sa createWidget(), errorString()
2799 -*/
2800 -QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget)
2801 -{
2802 - Q_D(QUiLoader);
2803 - // QXmlStreamReader will report errors on open failure.
2804 - if (!device->isOpen())
2805 - device->open(QIODevice::ReadOnly|QIODevice::Text);
2806 - return d->builder.load(device, parentWidget);
2807 -}
2808 -
2809 -/*!
2810 - Returns a list naming the paths in which the loader will search when
2811 - locating custom widget plugins.
2812 -
2813 - \sa addPluginPath(), clearPluginPaths()
2814 -*/
2815 -QStringList QUiLoader::pluginPaths() const
2816 -{
2817 - Q_D(const QUiLoader);
2818 - return d->builder.pluginPaths();
2819 -}
2820 -
2821 -/*!
2822 - Clears the list of paths in which the loader will search when locating
2823 - plugins.
2824 -
2825 - \sa addPluginPath(), pluginPaths()
2826 -*/
2827 -void QUiLoader::clearPluginPaths()
2828 -{
2829 - Q_D(QUiLoader);
2830 - d->builder.clearPluginPaths();
2831 -}
2832 -
2833 -/*!
2834 - Adds the given \a path to the list of paths in which the loader will search
2835 - when locating plugins.
2836 -
2837 - \sa pluginPaths(), clearPluginPaths()
2838 -*/
2839 -void QUiLoader::addPluginPath(const QString &path)
2840 -{
2841 - Q_D(QUiLoader);
2842 - d->builder.addPluginPath(path);
2843 -}
2844 -
2845 -/*!
2846 - Creates a new widget with the given \a parent and \a name using the class
2847 - specified by \a className. You can use this function to create any of the
2848 - widgets returned by the availableWidgets() function.
2849 -
2850 - The function is also used internally by the QUiLoader class whenever it
2851 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2852 - function to intervene process of constructing a user interface or widget.
2853 - However, in your implementation, ensure that you call QUiLoader's version
2854 - first.
2855 -
2856 - \sa availableWidgets(), load()
2857 -*/
2858 -QWidget *QUiLoader::createWidget(const QString &className, QWidget *parent, const QString &name)
2859 -{
2860 - Q_D(QUiLoader);
2861 - return d->builder.defaultCreateWidget(className, parent, name);
2862 -}
2863 -
2864 -/*!
2865 - Creates a new layout with the given \a parent and \a name using the class
2866 - specified by \a className.
2867 -
2868 - The function is also used internally by the QUiLoader class whenever it
2869 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2870 - function to intervene process of constructing a user interface or widget.
2871 - However, in your implementation, ensure that you call QUiLoader's version
2872 - first.
2873 -
2874 - \sa createWidget(), load()
2875 -*/
2876 -QLayout *QUiLoader::createLayout(const QString &className, QObject *parent, const QString &name)
2877 -{
2878 - Q_D(QUiLoader);
2879 - return d->builder.defaultCreateLayout(className, parent, name);
2880 -}
2881 -
2882 -/*!
2883 - Creates a new action group with the given \a parent and \a name.
2884 -
2885 - The function is also used internally by the QUiLoader class whenever it
2886 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2887 - function to intervene process of constructing a user interface or widget.
2888 - However, in your implementation, ensure that you call QUiLoader's version
2889 - first.
2890 -
2891 - \sa createAction(), createWidget(), load()
2892 - */
2893 -QActionGroup *QUiLoader::createActionGroup(QObject *parent, const QString &name)
2894 -{
2895 - Q_D(QUiLoader);
2896 - return d->builder.defaultCreateActionGroup(parent, name);
2897 -}
2898 -
2899 -/*!
2900 - Creates a new action with the given \a parent and \a name.
2901 -
2902 - The function is also used internally by the QUiLoader class whenever it
2903 - creates a widget. Hence, you can subclass QUiLoader and reimplement this
2904 - function to intervene process of constructing a user interface or widget.
2905 - However, in your implementation, ensure that you call QUiLoader's version
2906 - first.
2907 -
2908 - \sa createActionGroup(), createWidget(), load()
2909 -*/
2910 -QAction *QUiLoader::createAction(QObject *parent, const QString &name)
2911 -{
2912 - Q_D(QUiLoader);
2913 - return d->builder.defaultCreateAction(parent, name);
2914 -}
2915 -
2916 -/*!
2917 - Returns a list naming all available widgets that can be built using the
2918 - createWidget() function, i.e all the widgets specified within the given
2919 - plugin paths.
2920 -
2921 - \sa pluginPaths(), createWidget()
2922 -
2923 -*/
2924 -QStringList QUiLoader::availableWidgets() const
2925 -{
2926 - Q_D(const QUiLoader);
2927 -
2928 - d->setupWidgetMap();
2929 - widget_map available = *g_widgets();
2930 -
2931 - const auto &customWidgets = d->builder.customWidgets();
2932 - for (QDesignerCustomWidgetInterface *plugin : customWidgets)
2933 - available.insert(plugin->name(), true);
2934 -
2935 - return available.keys();
2936 -}
2937 -
2938 -
2939 -/*!
2940 - \since 4.5
2941 - Returns a list naming all available layouts that can be built using the
2942 - createLayout() function
2943 -
2944 - \sa createLayout()
2945 -*/
2946 -
2947 -QStringList QUiLoader::availableLayouts() const
2948 -{
2949 - QStringList rc;
2950 -#define DECLARE_WIDGET(a, b)
2951 -#define DECLARE_LAYOUT(a, b) rc.push_back(QLatin1String(#a));
2952 -
2953 -#include "widgets.table"
2954 -
2955 -#undef DECLARE_WIDGET
2956 -#undef DECLARE_LAYOUT
2957 - return rc;
2958 -}
2959 -
2960 -/*!
2961 - Sets the working directory of the loader to \a dir. The loader will look
2962 - for other resources, such as icons and resource files, in paths relative to
2963 - this directory.
2964 -
2965 - \sa workingDirectory()
2966 -*/
2967 -
2968 -void QUiLoader::setWorkingDirectory(const QDir &dir)
2969 -{
2970 - Q_D(QUiLoader);
2971 - d->builder.setWorkingDirectory(dir);
2972 -}
2973 -
2974 -/*!
2975 - Returns the working directory of the loader.
2976 -
2977 - \sa setWorkingDirectory()
2978 -*/
2979 -
2980 -QDir QUiLoader::workingDirectory() const
2981 -{
2982 - Q_D(const QUiLoader);
2983 - return d->builder.workingDirectory();
2984 -}
2985 -/*!
2986 - \since 4.5
2987 -
2988 - If \a enabled is true, user interfaces loaded by this loader will
2989 - automatically retranslate themselves upon receiving a language change
2990 - event. Otherwise, the user interfaces will not be retranslated.
2991 -
2992 - \sa isLanguageChangeEnabled()
2993 -*/
2994 -
2995 -void QUiLoader::setLanguageChangeEnabled(bool enabled)
2996 -{
2997 - Q_D(QUiLoader);
2998 - d->builder.dynamicTr = enabled;
2999 -}
3000 -
3001 -/*!
3002 - \since 4.5
3003 -
3004 - Returns true if dynamic retranslation on language change is enabled;
3005 - returns false otherwise.
3006 -
3007 - \sa setLanguageChangeEnabled()
3008 -*/
3009 -
3010 -bool QUiLoader::isLanguageChangeEnabled() const
3011 -{
3012 - Q_D(const QUiLoader);
3013 - return d->builder.dynamicTr;
3014 -}
3015 -
3016 -/*!
3017 - \internal
3018 - \since 4.5
3019 -
3020 - If \a enabled is true, user interfaces loaded by this loader will be
3021 - translated. Otherwise, the user interfaces will not be translated.
3022 -
3023 - \note This is orthogonal to languageChangeEnabled.
3024 -
3025 - \sa isLanguageChangeEnabled(), setLanguageChangeEnabled()
3026 -*/
3027 -
3028 -void QUiLoader::setTranslationEnabled(bool enabled)
3029 -{
3030 - Q_D(QUiLoader);
3031 - d->builder.trEnabled = enabled;
3032 -}
3033 -
3034 -/*!
3035 - \internal
3036 - \since 4.5
3037 -
3038 - Returns true if translation is enabled; returns false otherwise.
3039 -
3040 - \sa setTranslationEnabled()
3041 -*/
3042 -
3043 -bool QUiLoader::isTranslationEnabled() const
3044 -{
3045 - Q_D(const QUiLoader);
3046 - return d->builder.trEnabled;
3047 -}
3048 -
3049 -/*!
3050 - Returns a human-readable description of the last error occurred in load().
3051 -
3052 - \since 5.0
3053 - \sa load()
3054 -*/
3055 -
3056 -QString QUiLoader::errorString() const
3057 -{
3058 - Q_D(const QUiLoader);
3059 - return d->builder.errorString();
3060 -}
3061 -
3062 -QT_END_NAMESPACE
3063 -
3064 -#include "quiloader.moc"
3065 diff --git x/qttools/src/uitools/quiloader.h y/qttools/src/uitools/quiloader.h
3066 deleted file mode 100644
3067 index 742b5606f..000000000
3068 --- x/qttools/src/uitools/quiloader.h
3069 +++ /dev/null
3070 @@ -1,61 +0,0 @@
3071 -// Copyright (C) 2020 The Qt Company Ltd.
3072 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3073 -
3074 -#ifndef QUILOADER_H
3075 -#define QUILOADER_H
3076 -
3077 -#include <QtUiTools/qtuitoolsglobal.h>
3078 -#include <QtCore/qobject.h>
3079 -#include <QtCore/qscopedpointer.h>
3080 -
3081 -QT_BEGIN_NAMESPACE
3082 -
3083 -class QWidget;
3084 -class QLayout;
3085 -class QAction;
3086 -class QActionGroup;
3087 -class QString;
3088 -class QIODevice;
3089 -class QDir;
3090 -
3091 -class QUiLoaderPrivate;
3092 -class Q_UITOOLS_EXPORT QUiLoader : public QObject
3093 -{
3094 - Q_OBJECT
3095 -public:
3096 - explicit QUiLoader(QObject *parent = nullptr);
3097 - ~QUiLoader() override;
3098 -
3099 - QStringList pluginPaths() const;
3100 - void clearPluginPaths();
3101 - void addPluginPath(const QString &path);
3102 -
3103 - QWidget *load(QIODevice *device, QWidget *parentWidget = nullptr);
3104 - QStringList availableWidgets() const;
3105 - QStringList availableLayouts() const;
3106 -
3107 - virtual QWidget *createWidget(const QString &className, QWidget *parent = nullptr, const QString &name = QString());
3108 - virtual QLayout *createLayout(const QString &className, QObject *parent = nullptr, const QString &name = QString());
3109 - virtual QActionGroup *createActionGroup(QObject *parent = nullptr, const QString &name = QString());
3110 - virtual QAction *createAction(QObject *parent = nullptr, const QString &name = QString());
3111 -
3112 - void setWorkingDirectory(const QDir &dir);
3113 - QDir workingDirectory() const;
3114 -
3115 - void setLanguageChangeEnabled(bool enabled);
3116 - bool isLanguageChangeEnabled() const;
3117 -
3118 - void setTranslationEnabled(bool enabled);
3119 - bool isTranslationEnabled() const;
3120 -
3121 - QString errorString() const;
3122 -
3123 -private:
3124 - QScopedPointer<QUiLoaderPrivate> d_ptr;
3125 - Q_DECLARE_PRIVATE(QUiLoader)
3126 - Q_DISABLE_COPY_MOVE(QUiLoader)
3127 -};
3128 -
3129 -QT_END_NAMESPACE
3130 -
3131 -#endif // QUILOADER_H
3132 diff --git x/qttools/src/uitools/quiloader_p.h y/qttools/src/uitools/quiloader_p.h
3133 deleted file mode 100644
3134 index efd943217..000000000
3135 --- x/qttools/src/uitools/quiloader_p.h
3136 +++ /dev/null
3137 @@ -1,77 +0,0 @@
3138 -// Copyright (C) 2020 The Qt Company Ltd.
3139 -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3140 -
3141 -#ifndef QUILOADER_P_H
3142 -#define QUILOADER_P_H
3143 -
3144 -//
3145 -// W A R N I N G
3146 -// -------------
3147 -//
3148 -// This file is not part of the Qt API. It exists purely as an
3149 -// implementation detail. This header file may change from version to
3150 -// version without notice, or even be removed.
3151 -//
3152 -// We mean it.
3153 -//
3154 -
3155 -#include <QtUiTools/qtuitoolsglobal.h>
3156 -#include <QtCore/qbytearray.h>
3157 -#include <QtCore/qmetatype.h>
3158 -
3159 -QT_FORWARD_DECLARE_CLASS(QDataStream)
3160 -
3161 -// This file is here for use by the form preview in Linguist. If you change anything
3162 -// here or in the code which uses it, remember to adapt Linguist accordingly.
3163 -
3164 -#define PROP_GENERIC_PREFIX "_q_notr_"
3165 -#define PROP_TOOLITEMTEXT "_q_toolItemText_notr"
3166 -#define PROP_TOOLITEMTOOLTIP "_q_toolItemToolTip_notr"
3167 -#define PROP_TABPAGETEXT "_q_tabPageText_notr"
3168 -#define PROP_TABPAGETOOLTIP "_q_tabPageToolTip_notr"
3169 -#define PROP_TABPAGEWHATSTHIS "_q_tabPageWhatsThis_notr"
3170 -
3171 -QT_BEGIN_NAMESPACE
3172 -
3173 -class Q_UITOOLS_EXPORT QUiTranslatableStringValue
3174 -{
3175 -public:
3176 - QByteArray value() const { return m_value; }
3177 - void setValue(const QByteArray &value) { m_value = value; }
3178 - QByteArray qualifier() const { return m_qualifier; }
3179 - void setQualifier(const QByteArray &qualifier) { m_qualifier = qualifier; }
3180 -
3181 - QString translate(const QByteArray &className, bool idBased) const;
3182 -
3183 -private:
3184 - QByteArray m_value;
3185 - QByteArray m_qualifier; // Comment or ID for id-based tr().
3186 -};
3187 -
3188 -#ifndef QT_NO_DATASTREAM
3189 -Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s);
3190 -Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s);
3191 -#endif // QT_NO_DATASTREAM
3192 -
3193 -struct QUiItemRolePair {
3194 - int realRole;
3195 - int shadowRole;
3196 -};
3197 -
3198 -#ifdef QFORMINTERNAL_NAMESPACE
3199 -namespace QFormInternal
3200 -{
3201 -#endif
3202 -
3203 -extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[];
3204 -
3205 -#ifdef QFORMINTERNAL_NAMESPACE
3206 -}
3207 -#endif
3208 -
3209 -QT_END_NAMESPACE
3210 -
3211 -Q_DECLARE_METATYPE(QUiTranslatableStringValue)
3212 -
3213 -
3214 -#endif // QUILOADER_P_H
3215 diff --git x/qttools/sync.profile y/qttools/sync.profile
3216 index caa7ed5ad..de4261afc 100644
3217 --- x/qttools/sync.profile
3218 +++ y/qttools/sync.profile
3219 @@ -1,8 +1,8 @@
3220 %modules = ( # path to module name map
3221 "QtTools" => "$basedir/src/global",
3222 "QtHelp" => "$basedir/src/assistant/help",
3223 - "QtUiTools" => "$basedir/src/uitools",
3224 - "QtUiPlugin" => "$basedir/src/uiplugin",
3225 + "QtUiTools" => "$basedir/src/designer/src/uitools",
3226 + "QtUiPlugin" => "$basedir/src/designer/src/uiplugin",
3227 "QtDesigner" => "$basedir/src/designer/src/lib",
3228 "QtDesignerComponents" => "$basedir/src/designer/src/components/lib",
3229 );
0 From a120b53dcef4aebd5e7bea35bc6fc6c462e748f1 Mon Sep 17 00:00:00 2001
1 From: Alexey Edelev <alexey.edelev@qt.io>
2 Date: Wed, 23 Nov 2022 12:40:45 +0100
3 Subject: Fix Linux build with CMake versions >= 3.25
4 MIME-Version: 1.0
5 Content-Type: text/plain; charset=UTF-8
6 Content-Transfer-Encoding: 8bit
7
8 The 'LINUX' variable exists in CMake since the version 3.25. This
9 variable previously was undefined while preparsing the configure.cmake
10 files. Since the CMake script that defines the 'check_for_ulimit'
11 function is not included while evaluating configure.cmake first time
12 we need to add a stub.
13
14 Change-Id: I25bdec4f4a1b6af23174507a8f0f9cbf01f0c398
15 Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
16 (cherry picked from commit 240e71877865ed07e4c8d5bd4553aa0772c2adf4)
17 Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
18 (cherry picked from commit 517d0890f9e95c841bea3421f2455651ca0d8070)
19 ---
20 configure.cmake | 2 ++
21 1 file changed, 2 insertions(+)
22
23 diff --git x/qtwebengine/configure.cmake y/qtwebengine/configure.cmake
24 index f485c1b4b..fff76d54a 100644
25 --- x/qtwebengine/configure.cmake
26 +++ y/qtwebengine/configure.cmake
27 @@ -3,6 +3,8 @@ if(QT_CONFIGURE_RUNNING)
28 endfunction()
29 function(add_check_for_support)
30 endfunction()
31 + function(check_for_ulimit)
32 + endfunction()
33 else()
34 find_package(Ninja 1.7.2)
35 find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT)
0 cmake_minimum_required(VERSION 3.19.0)
1
2 # How to use
3 #
4 # Create an empty directory and provide it by -DREPOSITORY_DIR or set
5 # REPOSITORY_DIR as environment variable.
6 #
7 # - Apply existing patches
8 # $ cmake -DCMD=apply -P libs/patches.cmake
9 # 1. This will clone all repositores to REPOSITORY_DIR.
10 # 2. Checkout git tag from Versions.cmake to a new ausweisap_ branch.
11 # It will delete that branch if it exist.
12 # 3. Apply all patches to the new branch.
13 #
14 # - Generate patches from repositories
15 # $ cmake -DCMD=generate -P libs/patches.cmake
16 # 1. All existing patches in "patches" directory will be deleted.
17 # 2. Branch of current Version on all repositories in REPOSITORY_DIR will be scanned.
18 # 3. All changesets from the latest tag will be exported to "patches" dir.
19 #
20 # If you need a new repository you can clone it into REPOSITORY_DIR.
21 # Checkout the release tag of used Version.cmake and cherry-pick or add
22 # changesets to it. It will be exported with "generate".
23 # If you need to remove patches, just delete the changesets or the whole clone.
24 #
25 # - Upgrade Qt or OpenSSL
26 # 1. Apply all patches with this script and do the following on each repository.
27 # The version is an example and should be adjusted!
28 # 2. git checkout ausweisapp_6.4.3 -b ausweisapp_6.6.0
29 # 3. git rebase --onto v6.6.0 v6.4.3 HEAD
30 # 4. Bump version in Versions.cmake and use this script to generate the patches.
31
32 if(NOT CMAKE_SCRIPT_MODE_FILE OR NOT CMD)
33 message(FATAL_ERROR "Usage: cmake -DCMD=apply|generate -P libs/patches.cmake")
34 endif()
35
36 find_package(Git REQUIRED)
37
38 if(NOT REPOSITORY_DIR)
39 set(REPOSITORY_DIR $ENV{REPOSITORY_DIR})
40 if(NOT REPOSITORY_DIR)
41 message(FATAL_ERROR "Define REPOSITORY_DIR for local repositories")
42 endif()
43 if(NOT EXISTS "${REPOSITORY_DIR}")
44 message(FATAL_ERROR "REPOSITORY_DIR ${REPOSITORY_DIR} does not exist")
45 endif()
46 endif()
47
48 get_filename_component(libs_dir "${CMAKE_SCRIPT_MODE_FILE}" DIRECTORY)
49 set(patch_dir "${libs_dir}/patches")
50 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../cmake;${libs_dir}")
51 include(Versions)
52
53 function(execute_dir dir)
54 execute_process(COMMAND ${GIT_EXECUTABLE} ${ARGN}
55 WORKING_DIRECTORY "${REPOSITORY_DIR}/${dir}"
56 RESULT_VARIABLE _result)
57
58 if(NOT "${_result}" EQUAL 0)
59 message(FATAL_ERROR "git failed: ${_result}")
60 endif()
61 endfunction()
62
63 function(execute)
64 execute_dir("" ${ARGN})
65 endfunction()
66
67 function(git_clone prefix)
68 if(NOT EXISTS "${REPOSITORY_DIR}/${prefix}")
69 message(STATUS "Repository not found: ${prefix}")
70 if(prefix STREQUAL "openssl")
71 execute(clone "https://github.com/openssl/openssl" "${prefix}")
72 elseif(prefix MATCHES "qt")
73 execute(clone "https://code.qt.io/qt/${prefix}.git" "${prefix}")
74 endif()
75 endif()
76 endfunction()
77
78 function(git_checkout prefix)
79 get_version_branch("${prefix}" version tmp_branch)
80 execute_dir("${prefix}" fetch)
81 execute_dir("${prefix}" checkout -q ${version})
82 execute_process(COMMAND ${GIT_EXECUTABLE} branch -D ${tmp_branch} WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix})
83 execute_process(COMMAND ${GIT_EXECUTABLE} am --abort WORKING_DIRECTORY ${REPOSITORY_DIR}/${prefix} OUTPUT_QUIET ERROR_QUIET)
84 execute_dir("${prefix}" checkout ${version} -b ${tmp_branch})
85 endfunction()
86
87 function(get_version_branch prefix _version _branch)
88 set(tmp_branch ausweisapp)
89 if(prefix STREQUAL "openssl")
90 set(version openssl-${OPENSSL})
91 set(tmp_branch ${tmp_branch}_${OPENSSL})
92 elseif(prefix MATCHES "qt")
93 set(version v${QT})
94 set(tmp_branch ${tmp_branch}_${QT})
95 endif()
96
97 set(${_version} "${version}" PARENT_SCOPE)
98 set(${_branch} "${tmp_branch}" PARENT_SCOPE)
99 endfunction()
100
101 function(apply_patches)
102 file(GLOB PATCHES "${patch_dir}/*.patch")
103 foreach(patch ${PATCHES})
104 get_filename_component(filename "${patch}" NAME)
105 string(REGEX MATCH "([a-z|-]+)-[0-9]+.+" _unused "${filename}")
106 set(prefix ${CMAKE_MATCH_1})
107
108 list(APPEND prefixes "${prefix}")
109 list(APPEND "${prefix}" "${patch}")
110
111 if(NOT (prefix STREQUAL "openssl" OR prefix MATCHES "qt"))
112 message(FATAL_ERROR "Prefix unknown: ${prefix}")
113 endif()
114 endforeach()
115
116 list(REMOVE_DUPLICATES prefixes)
117 foreach(prefix ${prefixes})
118 message(STATUS "Apply component: ${prefix}")
119 git_clone(${prefix})
120 git_checkout(${prefix})
121
122 foreach(patch ${${prefix}})
123 if(prefix STREQUAL "openssl")
124 set(p 1)
125 elseif(prefix MATCHES "qt")
126 set(p 2)
127 endif()
128
129 execute_process(COMMAND ${CMAKE_COMMAND} -E env GIT_COMMITTER_NAME="Governikus" GIT_COMMITTER_EMAIL="" --
130 ${GIT_EXECUTABLE} am --whitespace=fix --no-gpg-sign --committer-date-is-author-date -p${p} "${patch}"
131 WORKING_DIRECTORY "${REPOSITORY_DIR}/${prefix}"
132 RESULT_VARIABLE _result)
133
134 if(NOT "${_result}" EQUAL 0)
135 message(FATAL_ERROR "cannot apply patch: ${_result}")
136 endif()
137 endforeach()
138 endforeach()
139 endfunction()
140
141
142 function(get_latest_tag _out repo)
143 execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
144 WORKING_DIRECTORY ${repo}
145 OUTPUT_VARIABLE _output
146 RESULT_VARIABLE _result
147 ERROR_QUIET
148 OUTPUT_STRIP_TRAILING_WHITESPACE)
149
150 if(${_result} EQUAL 0)
151 set(${_out} "${_output}" PARENT_SCOPE)
152 endif()
153 endfunction()
154
155 function(get_current_branch _out repo)
156 execute_process(COMMAND ${GIT_EXECUTABLE} branch --show-current
157 WORKING_DIRECTORY ${repo}
158 OUTPUT_VARIABLE _output
159 RESULT_VARIABLE _result
160 ERROR_QUIET
161 OUTPUT_STRIP_TRAILING_WHITESPACE)
162
163 if(NOT "${_result}" EQUAL 0)
164 message(FATAL_ERROR "git failed: ${_result}")
165 endif()
166 set(${_out} "${_output}" PARENT_SCOPE)
167 endfunction()
168
169 function(rename_patches component)
170 file(GLOB PATCHES "${patch_dir}/*.patch")
171 foreach(patch ${PATCHES})
172 get_filename_component(filename "${patch}" NAME)
173 if(filename MATCHES "^[0-9]+.*")
174 file(RENAME "${patch}" "${patch_dir}/${component}-${filename}")
175 endif()
176 endforeach()
177 endfunction()
178
179 function(generate_patches)
180 file(GLOB PATCHES "${patch_dir}/*.patch")
181 if(PATCHES)
182 file(REMOVE ${PATCHES})
183 endif()
184
185 list(APPEND prefixes openssl qt)
186 foreach(prefix ${prefixes})
187 file(GLOB REPOS "${REPOSITORY_DIR}/${prefix}*")
188 foreach(repo ${REPOS})
189 get_filename_component(dirname "${repo}" NAME)
190 get_version_branch("${prefix}" version tmp_branch)
191 execute_process(COMMAND ${GIT_EXECUTABLE} checkout -q ${tmp_branch} WORKING_DIRECTORY ${repo} OUTPUT_QUIET ERROR_QUIET)
192 get_current_branch(current_branch "${repo}")
193 if(current_branch STREQUAL tmp_branch)
194 get_latest_tag(latesttag "${repo}")
195 message(STATUS "Generate patches of ${dirname} since tag ${latesttag}")
196
197 if(dirname STREQUAL "openssl")
198 set(component "")
199 else()
200 set(component "${dirname}/")
201 endif()
202
203 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}")
204 rename_patches(${dirname})
205 else()
206 message(STATUS "Skip patches of ${dirname} and branch ${current_branch}")
207 endif()
208 endforeach()
209 endforeach()
210 endfunction()
211
212
213
214 if(CMD STREQUAL "generate")
215 message(STATUS "Generate patches!")
216 generate_patches()
217 elseif(CMD STREQUAL "apply")
218 message(STATUS "Apply patches!")
219 apply_patches()
220 else()
221 message(FATAL_ERROR "Unknown CMD: ${CMD}")
222 endif()
00 <RCC>
11 <qresource prefix="/">
2 <file alias="images/mobile/platform_specific_phone.svg">images/android/material_phone_android.svg</file>
32 <file alias="images/mobile/platform_specific_share.svg">images/android/material_share.svg</file>
43 </qresource>
54 </RCC>
00 <RCC>
11 <qresource prefix="/">
22 <file>images/macos/appIcon.svg</file>
3 <file>images/desktop/info_white.svg</file>
34 <file>images/desktop/titlebar_arrow.svg</file>
45 <file>images/desktop/material_assistant.svg</file>
56 <file>images/desktop/material_bug_report.svg</file>
1213 <file>images/desktop/material_question_answer.svg</file>
1314 <file>images/desktop/material_highlight.svg</file>
1415 <file>images/desktop/material_menu_book.svg</file>
16 <file>images/desktop/material_menu_book_white.svg</file>
17 <file>images/desktop/material_settings_white.svg</file>
1518 <file>images/desktop/material_open_in_browser.svg</file>
1619 <file>images/desktop/material_a11y.svg</file>
1720 <file>images/desktop/material_privacy.svg</file>
00 <RCC>
11 <qresource prefix="/">
2 <file alias="images/mobile/platform_specific_phone.svg">images/ios/material_phone_iphone.svg</file>
32 <file alias="images/mobile/platform_specific_share.svg">images/ios/share.svg</file>
43 </qresource>
54 </RCC>
00 <RCC>
11 <qresource prefix="/">
2 <file>qtquickcontrols2.conf</file>
3 <file>images/mobile/device.svg</file>
4 <file>images/mobile/icon_nfc.svg</file>
5 <file>images/mobile/icon_smart.svg</file>
6 <file>images/mobile/icon_remote.svg</file>
7 <file>images/mobile/icon_simulator.svg</file>
8 <file>images/mobile/material_arrow_right.svg</file>
9 <file>images/mobile/material_arrow_back.svg</file>
10 <file>images/mobile/material_backspace.svg</file>
11 <file>images/mobile/material_view_headline.svg</file>
12 <file>images/mobile/material_home.svg</file>
13 <file>images/mobile/phone_smart.svg</file>
14 <file>images/mobile/phone_nfc.svg</file>
15 <file>images/mobile/phone_nfc_with_card.svg</file>
16 <file>images/mobile/phone_remote.svg</file>
17 <file>images/mobile/phone_simulator.svg</file>
18 <file>images/mobile/generic_id_card.svg</file>
192 <file>images/android/stay_primary_landscape-24px.svg</file>
203 <file>images/android/stay_primary_portrait-24px.svg</file>
214 <file>images/ios/material_arrow_left.svg</file>
225 <file>images/ios/material_cancel.svg</file>
236 <file>images/ios/material_more_horiz.svg</file>
7 <file>images/material_add.svg</file>
8 <file>images/mobile/device.svg</file>
9 <file>images/mobile/generic_id_card.svg</file>
10 <file>images/mobile/icon_nfc.svg</file>
11 <file>images/mobile/icon_remote.svg</file>
12 <file>images/mobile/icon_simulator.svg</file>
13 <file>images/mobile/icon_smart.svg</file>
14 <file>images/mobile/material_arrow_back.svg</file>
15 <file>images/mobile/material_arrow_right.svg</file>
16 <file>images/mobile/material_backspace.svg</file>
17 <file>images/mobile/material_home.svg</file>
18 <file>images/mobile/material_view_headline.svg</file>
19 <file>images/mobile/phone_card_reader.svg</file>
20 <file>images/mobile/phone_nfc.svg</file>
21 <file>images/mobile/phone_nfc_with_card.svg</file>
22 <file>images/mobile/phone_remote.svg</file>
23 <file>images/mobile/phone_simulator.svg</file>
24 <file>images/mobile/phone_smart.svg</file>
25 <file>images/provider/ios/citizen.svg</file>
26 <file alias="images/provider/ios/citizen_bg.svg">images/provider/citizen_bg.svg</file>
27 <file alias="images/provider/ios/citizen_button.svg">images/provider/citizen_button.svg</file>
28 <file alias="images/provider/ios/default_bg.svg">images/provider/default_bg.svg</file>
29 <file>images/provider/ios/finance.svg</file>
30 <file alias="images/provider/ios/finance_bg.svg">images/provider/finance_bg.svg</file>
31 <file alias="images/provider/ios/finance_button.svg">images/provider/finance_button.svg</file>
2432 <file>images/provider/ios/general.svg</file>
25 <file>images/provider/ios/citizen.svg</file>
26 <file>images/provider/ios/finance.svg</file>
33 <file alias="images/provider/ios/general_bg.svg">images/provider/general_bg.svg</file>
34 <file alias="images/provider/ios/general_button.svg">images/provider/general_button.svg</file>
2735 <file>images/provider/ios/insurance.svg</file>
36 <file alias="images/provider/ios/insurance_bg.svg">images/provider/insurance_bg.svg</file>
37 <file alias="images/provider/ios/insurance_button.svg">images/provider/insurance_button.svg</file>
2838 <file>images/provider/ios/other.svg</file>
29 <file alias="images/provider/ios/default_bg.svg">images/provider/default_bg.svg</file>
30 <file alias="images/provider/ios/citizen_button.svg">images/provider/citizen_button.svg</file>
31 <file alias="images/provider/ios/finance_button.svg">images/provider/finance_button.svg</file>
32 <file alias="images/provider/ios/general_button.svg">images/provider/general_button.svg</file>
33 <file alias="images/provider/ios/insurance_button.svg">images/provider/insurance_button.svg</file>
39 <file alias="images/provider/ios/other_bg.svg">images/provider/other_bg.svg</file>
3440 <file alias="images/provider/ios/other_button.svg">images/provider/other_button.svg</file>
35 <file alias="images/provider/ios/citizen_bg.svg">images/provider/citizen_bg.svg</file>
36 <file alias="images/provider/ios/finance_bg.svg">images/provider/finance_bg.svg</file>
37 <file alias="images/provider/ios/general_bg.svg">images/provider/general_bg.svg</file>
38 <file alias="images/provider/ios/insurance_bg.svg">images/provider/insurance_bg.svg</file>
39 <file alias="images/provider/ios/other_bg.svg">images/provider/other_bg.svg</file>
40 <file>images/tutorial/main_menu_what_caret.svg</file>
41 <file>images/tutorial/main_menu_where_caret.svg</file>
42 <file>images/tutorial/main_menu_how_caret.svg</file>
43 <file>images/tutorial/main_menu_important_caret.svg</file>
41 <file>images/tutorial/arrow_blue.svg</file>
42 <file>images/tutorial/arrows.svg</file>
4443 <file>images/tutorial/background_icon_how.svg</file>
44 <file>images/tutorial/background_icon_important.svg</file>
4545 <file>images/tutorial/background_icon_where.svg</file>
46 <file>images/tutorial/background_icon_important.svg</file>
46 <file>images/tutorial/button_de.png</file>
47 <file>images/tutorial/button_en.png</file>
48 <file alias="images/tutorial/button_uk.png">images/tutorial/button_en.png</file>
49 <file alias="images/tutorial/button_ru.png">images/tutorial/button_en.png</file>
50 <file>images/tutorial/bva.svg</file>
51 <file>images/tutorial/check.svg</file>
52 <file>images/tutorial/circle-1.svg</file>
53 <file>images/tutorial/circle-2.svg</file>
54 <file>images/tutorial/circle-3.svg</file>
55 <file>images/tutorial/circle-4.svg</file>
56 <file>images/tutorial/circle-lock-2.svg</file>
57 <file>images/tutorial/circle-lock.svg</file>
58 <file>images/tutorial/click.svg</file>
59 <file>images/tutorial/cross.svg</file>
60 <file>images/tutorial/desktop.svg</file>
61 <file>images/tutorial/hand.svg</file>
62 <file>images/tutorial/hint.svg</file>
63 <file>images/tutorial/how_desktop.svg</file>
64 <file>images/tutorial/how_device_lineup.svg</file>
65 <file>images/tutorial/how_form_no_fun.svg</file>
66 <file>images/tutorial/how_method_nfc.svg</file>
67 <file>images/tutorial/how_method_sac_desktop.svg</file>
68 <file>images/tutorial/how_method_sac_mobile.svg</file>
69 <file>images/tutorial/how_questions_everywhere.svg</file>
4770 <file>images/tutorial/icon_box.svg</file>
4871 <file>images/tutorial/icon_circle.svg</file>
4972 <file>images/tutorial/icon_diamond.svg</file>
5073 <file>images/tutorial/icon_star.svg</file>
51 <file>images/tutorial/arrow_blue.svg</file>
52 <file>images/tutorial/arrows.svg</file>
53 <file>images/tutorial/button_de.png</file>
54 <file>images/tutorial/button_en.png</file>
5574 <file>images/tutorial/identify.svg</file>
56 <file>images/tutorial/questionmark.svg</file>
57 <file>images/tutorial/hint.svg</file>
58 <file>images/tutorial/thumb_up.svg</file>
59 <file>images/tutorial/hand.svg</file>
60 <file>images/tutorial/check.svg</file>
61 <file>images/tutorial/cross.svg</file>
62 <file>images/tutorial/click.svg</file>
63 <file>images/tutorial/save.svg</file>
64 <file>images/tutorial/bva.svg</file>
65 <file>images/tutorial/provider_home.svg</file>
66 <file>images/tutorial/rectangles.svg</file>
75 <file>images/tutorial/important_lets_go.svg</file>
76 <file>images/tutorial/important_pin5.svg</file>
77 <file>images/tutorial/important_pin6.svg</file>
78 <file>images/tutorial/important_space_questionmark.svg</file>
6779 <file>images/tutorial/laptop.svg</file>
68 <file>images/tutorial/tablet.svg</file>
69 <file>images/tutorial/tablet-nfc.svg</file>
70 <file>images/tutorial/tablet-no-nfc.svg</file>
71 <file>images/tutorial/reader.svg</file>
72 <file>images/tutorial/desktop.svg</file>
80 <file>images/tutorial/letters.svg</file>
81 <file>images/tutorial/main_menu_how_caret.svg</file>
82 <file>images/tutorial/main_menu_important_caret.svg</file>
83 <file>images/tutorial/main_menu_what_caret.svg</file>
84 <file>images/tutorial/main_menu_where_caret.svg</file>
85 <file>images/tutorial/nfc.svg</file>
86 <file>images/tutorial/no-nfc.svg</file>
7387 <file>images/tutorial/phone.svg</file>
7488 <file>images/tutorial/phone_border.svg</file>
7589 <file>images/tutorial/phone_list.svg</file>
7690 <file>images/tutorial/phone_screen.svg</file>
77 <file>images/tutorial/nfc.svg</file>
78 <file>images/tutorial/no-nfc.svg</file>
79 <file>images/tutorial/wifi.svg</file>
80 <file>images/tutorial/letters.svg</file>
81 <file>images/tutorial/usb.svg</file>
82 <file>images/tutorial/circle-1.svg</file>
83 <file>images/tutorial/circle-2.svg</file>
84 <file>images/tutorial/circle-3.svg</file>
85 <file>images/tutorial/circle-4.svg</file>
86 <file>images/tutorial/circle-lock.svg</file>
87 <file>images/tutorial/circle-lock-2.svg</file>
88 <file>images/tutorial/up_icon.svg</file>
8991 <file>images/tutorial/phone_screen_de.png</file>
9092 <file>images/tutorial/phone_screen_en.png</file>
93 <file alias="images/tutorial/phone_screen_uk.png">images/tutorial/phone_screen_en.png</file>
94 <file alias="images/tutorial/phone_screen_ru.png">images/tutorial/phone_screen_en.png</file>
9195 <file>images/tutorial/pin-5@2x.png</file>
9296 <file>images/tutorial/pin-6@2x.png</file>
93 <file>images/tutorial/user-tine@3x.png</file>
97 <file>images/tutorial/play_movie.png</file>
98 <file>images/tutorial/provider_home.svg</file>
9499 <file>images/tutorial/providericons.png</file>
95 <file>images/tutorial/play_movie.png</file>
96 <file>images/tutorial/screenshot_check_id_card_android_de.png</file>
97 <file>images/tutorial/screenshot_check_id_card_android_en.png</file>
98 <file>images/tutorial/screenshot_check_id_card_ios_de.png</file>
99 <file>images/tutorial/screenshot_check_id_card_ios_en.png</file>
100 <file>images/tutorial/screenshot_cert_android_de.png</file>
101 <file>images/tutorial/screenshot_cert_android_en.png</file>
102 <file>images/tutorial/screenshot_cert_ios_de.png</file>
103 <file>images/tutorial/screenshot_cert_ios_en.png</file>
104 <file>images/tutorial/screenshot_providerlist_android_de.png</file>
105 <file>images/tutorial/screenshot_providerlist_android_en.png</file>
106 <file>images/tutorial/screenshot_providerlist_ios_de.png</file>
107 <file>images/tutorial/screenshot_providerlist_ios_en.png</file>
108 <file>images/tutorial/screenshot_remoteservice_android_de.png</file>
109 <file>images/tutorial/screenshot_remoteservice_android_en.png</file>
110 <file>images/tutorial/screenshot_remoteservice_ios_en.png</file>
111 <file>images/tutorial/screenshot_remoteservice_ios_de.png</file>
112 <file>images/tutorial/screenshot_pairing_de.png</file>
113 <file>images/tutorial/screenshot_pairing_en.png</file>
114 <file>images/tutorial/screenshot_choose_reader_android_de.png</file>
115 <file>images/tutorial/screenshot_choose_reader_android_en.png</file>
116 <file>images/tutorial/screenshot_choose_reader_ios_de.png</file>
117 <file>images/tutorial/screenshot_choose_reader_ios_en.png</file>
118 <file>images/tutorial/screenshot_pin_management_menu_android_en.png</file>
119 <file>images/tutorial/screenshot_pin_management_menu_android_de.png</file>
120 <file>images/tutorial/screenshot_pin_management_menu_ios_en.png</file>
121 <file>images/tutorial/screenshot_pin_management_menu_ios_de.png</file>
122 <file>images/tutorial/screenshot_start_android_en.png</file>
123 <file>images/tutorial/screenshot_start_android_de.png</file>
124 <file>images/tutorial/screenshot_start_ios_en.png</file>
125 <file>images/tutorial/screenshot_start_ios_de.png</file>
126 <file>images/tutorial/screenshot_selfauthentication_android_de.png</file>
127 <file>images/tutorial/screenshot_selfauthentication_android_en.png</file>
128 <file>images/tutorial/screenshot_selfauthentication_ios_de.png</file>
129 <file>images/tutorial/screenshot_selfauthentication_ios_en.png</file>
130 <file>images/tutorial/section_seperator_what.svg</file>
131 <file>images/tutorial/section_seperator_where.svg</file>
132 <file>images/tutorial/section_seperator_how.svg</file>
133 <file>images/tutorial/section_seperator_important.svg</file>
134 <file>images/tutorial/where_overview_question.svg</file>
135 <file>images/tutorial/where_identify_now_de.svg</file>
136 <file>images/tutorial/where_identify_now_en.svg</file>
137 <file>images/tutorial/where_userdata_example_de.svg</file>
138 <file>images/tutorial/where_userdata_example_en.svg</file>
139 <file>images/tutorial/where_lay_down_id.svg</file>
140 <file>images/tutorial/where_pin6.svg</file>
141 <file>images/tutorial/how_questions_everywhere.svg</file>
142 <file>images/tutorial/how_device_lineup.svg</file>
143 <file>images/tutorial/how_method_nfc.svg</file>
144 <file>images/tutorial/how_method_sac_desktop.svg</file>
145 <file>images/tutorial/how_method_sac_mobile.svg</file>
146 <file>images/tutorial/how_form_no_fun.svg</file>
147 <file>images/tutorial/how_desktop.svg</file>
148 <file>images/tutorial/important_pin5.svg</file>
149 <file>images/tutorial/important_pin6.svg</file>
150 <file>images/tutorial/important_lets_go.svg</file>
151 <file>images/tutorial/important_space_questionmark.svg</file>
100 <file>images/tutorial/questionmark.svg</file>
101 <file>images/tutorial/reader.svg</file>
102 <file>images/tutorial/reader_nfc_finished.svg</file>
103 <file>images/tutorial/reader_nfc_npa_on_smartphone.svg</file>
104 <file>images/tutorial/reader_nfc_pin6.svg</file>
152105 <file>images/tutorial/reader_nfc_provider_on_smartphone.svg</file>
153 <file>images/tutorial/reader_nfc_npa_on_smartphone.svg</file>
154106 <file>images/tutorial/reader_nfc_smartphone_nfc_position.svg</file>
155 <file>images/tutorial/reader_nfc_finished.svg</file>
156 <file>images/tutorial/reader_nfc_pin6.svg</file>
157107 <file>images/tutorial/reader_nfc_userdata_example_de.svg</file>
158108 <file>images/tutorial/reader_nfc_userdata_example_en.svg</file>
159 <file>images/tutorial/reader_sac_provider_on_laptop.svg</file>
160 <file>images/tutorial/reader_sac_npa_on_laptop.svg</file>
109 <file alias="images/tutorial/reader_nfc_userdata_example_uk.svg">images/tutorial/reader_nfc_userdata_example_en.svg</file>
110 <file alias="images/tutorial/reader_nfc_userdata_example_ru.svg">images/tutorial/reader_nfc_userdata_example_en.svg</file>
161111 <file>images/tutorial/reader_sac_aa2_ok.svg</file>
162112 <file>images/tutorial/reader_sac_menu_android_de.svg</file>
163113 <file>images/tutorial/reader_sac_menu_android_en.svg</file>
114 <file alias="images/tutorial/reader_sac_menu_android_ru.svg">images/tutorial/reader_sac_menu_android_en.svg</file>
115 <file alias="images/tutorial/reader_sac_menu_android_uk.svg">images/tutorial/reader_sac_menu_android_en.svg</file>
164116 <file>images/tutorial/reader_sac_menu_ios_de.svg</file>
165117 <file>images/tutorial/reader_sac_menu_ios_en.svg</file>
118 <file alias="images/tutorial/reader_sac_menu_ios_uk.svg">images/tutorial/reader_sac_menu_ios_en.svg</file>
119 <file alias="images/tutorial/reader_sac_menu_ios_ru.svg">images/tutorial/reader_sac_menu_ios_en.svg</file>
166120 <file>images/tutorial/reader_sac_no_nfc_devices.svg</file>
167121 <file>images/tutorial/reader_sac_no_nfc_provider.svg</file>
168 </qresource>
169 <qresource prefix="/">
170 <file alias="images/tutorial/button_ru.png">images/tutorial/button_en.png</file>
171 <file alias="images/tutorial/phone_screen_ru.png">images/tutorial/phone_screen_en.png</file>
122 <file>images/tutorial/reader_sac_npa_on_laptop.svg</file>
123 <file>images/tutorial/reader_sac_provider_on_laptop.svg</file>
124 <file>images/tutorial/rectangles.svg</file>
125 <file>images/tutorial/save.svg</file>
126 <file>images/tutorial/screenshot_cert_android_de.png</file>
127 <file>images/tutorial/screenshot_cert_android_en.png</file>
172128 <file alias="images/tutorial/screenshot_cert_android_ru.png">images/tutorial/screenshot_cert_android_en.png</file>
129 <file alias="images/tutorial/screenshot_cert_android_uk.png">images/tutorial/screenshot_cert_android_en.png</file>
130 <file>images/tutorial/screenshot_cert_ios_de.png</file>
131 <file>images/tutorial/screenshot_cert_ios_en.png</file>
173132 <file alias="images/tutorial/screenshot_cert_ios_ru.png">images/tutorial/screenshot_cert_ios_en.png</file>
133 <file alias="images/tutorial/screenshot_cert_ios_uk.png">images/tutorial/screenshot_cert_ios_en.png</file>
134 <file>images/tutorial/screenshot_check_id_card_android_de.png</file>
135 <file>images/tutorial/screenshot_check_id_card_android_en.png</file>
136 <file alias="images/tutorial/screenshot_check_id_card_android_uk.png">images/tutorial/screenshot_check_id_card_android_en.png</file>
174137 <file alias="images/tutorial/screenshot_check_id_card_android_ru.png">images/tutorial/screenshot_check_id_card_android_en.png</file>
138 <file>images/tutorial/screenshot_check_id_card_ios_de.png</file>
139 <file>images/tutorial/screenshot_check_id_card_ios_en.png</file>
140 <file alias="images/tutorial/screenshot_check_id_card_ios_uk.png">images/tutorial/screenshot_check_id_card_ios_en.png</file>
175141 <file alias="images/tutorial/screenshot_check_id_card_ios_ru.png">images/tutorial/screenshot_check_id_card_ios_en.png</file>
142 <file>images/tutorial/screenshot_choose_reader_android_de.png</file>
143 <file>images/tutorial/screenshot_choose_reader_android_en.png</file>
176144 <file alias="images/tutorial/screenshot_choose_reader_android_ru.png">images/tutorial/screenshot_choose_reader_android_en.png</file>
145 <file alias="images/tutorial/screenshot_choose_reader_android_uk.png">images/tutorial/screenshot_choose_reader_android_en.png</file>
146 <file>images/tutorial/screenshot_choose_reader_ios_de.png</file>
147 <file>images/tutorial/screenshot_choose_reader_ios_en.png</file>
177148 <file alias="images/tutorial/screenshot_choose_reader_ios_ru.png">images/tutorial/screenshot_choose_reader_ios_en.png</file>
149 <file alias="images/tutorial/screenshot_choose_reader_ios_uk.png">images/tutorial/screenshot_choose_reader_ios_en.png</file>
150 <file>images/tutorial/screenshot_pairing_de.png</file>
151 <file>images/tutorial/screenshot_pairing_en.png</file>
178152 <file alias="images/tutorial/screenshot_pairing_ru.png">images/tutorial/screenshot_pairing_en.png</file>
153 <file alias="images/tutorial/screenshot_pairing_uk.png">images/tutorial/screenshot_pairing_en.png</file>
154 <file>images/tutorial/screenshot_pin_management_menu_android_de.png</file>
155 <file>images/tutorial/screenshot_pin_management_menu_android_en.png</file>
156 <file alias="images/tutorial/screenshot_pin_management_menu_android_uk.png">images/tutorial/screenshot_pin_management_menu_android_en.png</file>
179157 <file alias="images/tutorial/screenshot_pin_management_menu_android_ru.png">images/tutorial/screenshot_pin_management_menu_android_en.png</file>
158 <file>images/tutorial/screenshot_pin_management_menu_ios_de.png</file>
159 <file>images/tutorial/screenshot_pin_management_menu_ios_en.png</file>
180160 <file alias="images/tutorial/screenshot_pin_management_menu_ios_ru.png">images/tutorial/screenshot_pin_management_menu_ios_en.png</file>
161 <file alias="images/tutorial/screenshot_pin_management_menu_ios_uk.png">images/tutorial/screenshot_pin_management_menu_ios_en.png</file>
162 <file>images/tutorial/screenshot_providerlist_android_de.png</file>
163 <file>images/tutorial/screenshot_providerlist_android_en.png</file>
164 <file alias="images/tutorial/screenshot_providerlist_android_uk.png">images/tutorial/screenshot_providerlist_android_en.png</file>
181165 <file alias="images/tutorial/screenshot_providerlist_android_ru.png">images/tutorial/screenshot_providerlist_android_en.png</file>
166 <file>images/tutorial/screenshot_providerlist_ios_de.png</file>
167 <file>images/tutorial/screenshot_providerlist_ios_en.png</file>
168 <file alias="images/tutorial/screenshot_providerlist_ios_uk.png">images/tutorial/screenshot_providerlist_ios_en.png</file>
182169 <file alias="images/tutorial/screenshot_providerlist_ios_ru.png">images/tutorial/screenshot_providerlist_ios_en.png</file>
170 <file>images/tutorial/screenshot_remoteservice_android_de.png</file>
171 <file>images/tutorial/screenshot_remoteservice_android_en.png</file>
183172 <file alias="images/tutorial/screenshot_remoteservice_android_ru.png">images/tutorial/screenshot_remoteservice_android_en.png</file>
173 <file alias="images/tutorial/screenshot_remoteservice_android_uk.png">images/tutorial/screenshot_remoteservice_android_en.png</file>
174 <file>images/tutorial/screenshot_remoteservice_ios_de.png</file>
175 <file>images/tutorial/screenshot_remoteservice_ios_en.png</file>
184176 <file alias="images/tutorial/screenshot_remoteservice_ios_ru.png">images/tutorial/screenshot_remoteservice_ios_en.png</file>
177 <file alias="images/tutorial/screenshot_remoteservice_ios_uk.png">images/tutorial/screenshot_remoteservice_ios_en.png</file>
178 <file>images/tutorial/screenshot_selfauthentication_android_de.png</file>
179 <file>images/tutorial/screenshot_selfauthentication_android_en.png</file>
180 <file alias="images/tutorial/screenshot_selfauthentication_android_uk.png">images/tutorial/screenshot_selfauthentication_android_en.png</file>
185181 <file alias="images/tutorial/screenshot_selfauthentication_android_ru.png">images/tutorial/screenshot_selfauthentication_android_en.png</file>
182 <file>images/tutorial/screenshot_selfauthentication_ios_de.png</file>
183 <file>images/tutorial/screenshot_selfauthentication_ios_en.png</file>
184 <file alias="images/tutorial/screenshot_selfauthentication_ios_uk.png">images/tutorial/screenshot_selfauthentication_ios_en.png</file>
186185 <file alias="images/tutorial/screenshot_selfauthentication_ios_ru.png">images/tutorial/screenshot_selfauthentication_ios_en.png</file>
186 <file>images/tutorial/screenshot_start_android_de.png</file>
187 <file>images/tutorial/screenshot_start_android_en.png</file>
187188 <file alias="images/tutorial/screenshot_start_android_ru.png">images/tutorial/screenshot_start_android_en.png</file>
189 <file alias="images/tutorial/screenshot_start_android_uk.png">images/tutorial/screenshot_start_android_en.png</file>
190 <file>images/tutorial/screenshot_start_ios_de.png</file>
191 <file>images/tutorial/screenshot_start_ios_en.png</file>
188192 <file alias="images/tutorial/screenshot_start_ios_ru.png">images/tutorial/screenshot_start_ios_en.png</file>
189 <file alias="images/tutorial/reader_nfc_userdata_example_ru.svg">images/tutorial/reader_nfc_userdata_example_en.svg</file>
190 <file alias="images/tutorial/reader_sac_menu_android_ru.svg">images/tutorial/reader_sac_menu_android_en.svg</file>
191 <file alias="images/tutorial/reader_sac_menu_ios_ru.svg">images/tutorial/reader_sac_menu_ios_en.svg</file>
192 <file alias="images/tutorial/src/phone_screen_ru.svg">images/tutorial/src/phone_screen_en.svg</file>
193 <file alias="images/tutorial/screenshot_start_ios_uk.png">images/tutorial/screenshot_start_ios_en.png</file>
194 <file>images/tutorial/section_seperator_how.svg</file>
195 <file>images/tutorial/section_seperator_important.svg</file>
196 <file>images/tutorial/section_seperator_what.svg</file>
197 <file>images/tutorial/section_seperator_where.svg</file>
198 <file>images/tutorial/tablet-nfc.svg</file>
199 <file>images/tutorial/tablet-no-nfc.svg</file>
200 <file>images/tutorial/tablet.svg</file>
201 <file>images/tutorial/thumb_up.svg</file>
202 <file>images/tutorial/up_icon.svg</file>
203 <file>images/tutorial/usb.svg</file>
204 <file>images/tutorial/user-tine@3x.png</file>
205 <file>images/tutorial/where_identify_now_de.svg</file>
206 <file>images/tutorial/where_identify_now_en.svg</file>
193207 <file alias="images/tutorial/where_identify_now_ru.svg">images/tutorial/where_identify_now_en.svg</file>
208 <file alias="images/tutorial/where_identify_now_uk.svg">images/tutorial/where_identify_now_en.svg</file>
209 <file>images/tutorial/where_lay_down_id.svg</file>
210 <file>images/tutorial/where_overview_question.svg</file>
211 <file>images/tutorial/where_pin6.svg</file>
212 <file>images/tutorial/where_userdata_example_de.svg</file>
213 <file>images/tutorial/where_userdata_example_en.svg</file>
194214 <file alias="images/tutorial/where_userdata_example_ru.svg">images/tutorial/where_userdata_example_en.svg</file>
195 </qresource>
196 <qresource prefix="/">
197 <file alias="images/tutorial/button_uk.png">images/tutorial/button_en.png</file>
198 <file alias="images/tutorial/phone_screen_uk.png">images/tutorial/phone_screen_en.png</file>
199 <file alias="images/tutorial/screenshot_cert_android_uk.png">images/tutorial/screenshot_cert_android_en.png</file>
200 <file alias="images/tutorial/screenshot_cert_ios_uk.png">images/tutorial/screenshot_cert_ios_en.png</file>
201 <file alias="images/tutorial/screenshot_check_id_card_android_uk.png">images/tutorial/screenshot_check_id_card_android_en.png</file>
202 <file alias="images/tutorial/screenshot_check_id_card_ios_uk.png">images/tutorial/screenshot_check_id_card_ios_en.png</file>
203 <file alias="images/tutorial/screenshot_choose_reader_android_uk.png">images/tutorial/screenshot_choose_reader_android_en.png</file>
204 <file alias="images/tutorial/screenshot_choose_reader_ios_uk.png">images/tutorial/screenshot_choose_reader_ios_en.png</file>
205 <file alias="images/tutorial/screenshot_pairing_uk.png">images/tutorial/screenshot_pairing_en.png</file>
206 <file alias="images/tutorial/screenshot_pin_management_menu_android_uk.png">images/tutorial/screenshot_pin_management_menu_android_en.png</file>
207 <file alias="images/tutorial/screenshot_pin_management_menu_ios_uk.png">images/tutorial/screenshot_pin_management_menu_ios_en.png</file>
208 <file alias="images/tutorial/screenshot_providerlist_android_uk.png">images/tutorial/screenshot_providerlist_android_en.png</file>
209 <file alias="images/tutorial/screenshot_providerlist_ios_uk.png">images/tutorial/screenshot_providerlist_ios_en.png</file>
210 <file alias="images/tutorial/screenshot_remoteservice_android_uk.png">images/tutorial/screenshot_remoteservice_android_en.png</file>
211 <file alias="images/tutorial/screenshot_remoteservice_ios_uk.png">images/tutorial/screenshot_remoteservice_ios_en.png</file>
212 <file alias="images/tutorial/screenshot_selfauthentication_android_uk.png">images/tutorial/screenshot_selfauthentication_android_en.png</file>
213 <file alias="images/tutorial/screenshot_selfauthentication_ios_uk.png">images/tutorial/screenshot_selfauthentication_ios_en.png</file>
214 <file alias="images/tutorial/screenshot_start_android_uk.png">images/tutorial/screenshot_start_android_en.png</file>
215 <file alias="images/tutorial/screenshot_start_ios_uk.png">images/tutorial/screenshot_start_ios_en.png</file>
216 <file alias="images/tutorial/reader_nfc_userdata_example_uk.svg">images/tutorial/reader_nfc_userdata_example_en.svg</file>
217 <file alias="images/tutorial/reader_sac_menu_android_uk.svg">images/tutorial/reader_sac_menu_android_en.svg</file>
218 <file alias="images/tutorial/reader_sac_menu_ios_uk.svg">images/tutorial/reader_sac_menu_ios_en.svg</file>
219 <file alias="images/tutorial/src/phone_screen_uk.svg">images/tutorial/src/phone_screen_en.svg</file>
220 <file alias="images/tutorial/where_identify_now_uk.svg">images/tutorial/where_identify_now_en.svg</file>
221215 <file alias="images/tutorial/where_userdata_example_uk.svg">images/tutorial/where_userdata_example_en.svg</file>
216 <file>images/tutorial/wifi.svg</file>
217 <file>qtquickcontrols2.conf</file>
222218 </qresource>
223219 </RCC>
0 <?xml version="1.0" encoding="UTF-8" ?>
1 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64.8" height="64.8" viewBox="0 0 37 37">
2 <use xlink:href="./adaptive_monochrome_release.svg#background" />
3 <use xlink:href="./adaptive_monochrome_release.svg#circle" transform="translate(7 7) scale(0.622 0.622)" />
4 <!-- <text style="font-weight:bold; font-size:10px; font-family:sans-serif;" x="15" y="22">B</text> -->
5 <path id="beta" d="m 15.82,22 h 3.28 c 0.84,0 1.4,-0.16 1.84,-0.53 0.44,-0.37 0.72,-0.98 0.72,-1.57 0,-0.72 -0.38,-1.29 -1.21,-1.77 0.72,-0.46 1,-0.88 1,-1.5 0,-0.51 -0.25,-1.03 -0.66,-1.39 -0.43,-0.37 -0.94,-0.53 -1.72,-0.53 h -3.25 z m 1.5,-6.04 h 1.63 c 0.7,0 1.06,0.28 1.06,0.82 0,0.55 -0.36,0.83 -1.06,0.83 h -1.63 z m 0,2.9 h 1.79 c 0.73,0 1.11,0.32 1.11,0.95 0,0.62 -0.38,0.94 -1.11,0.94 h -1.79 z" />
6 </svg>
0 <?xml version="1.0" encoding="UTF-8" ?>
1 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64.8" height="64.8" viewBox="0 0 37 37">
2 <use xlink:href="./adaptive_monochrome_release.svg#background" />
3 <use xlink:href="./adaptive_monochrome_release.svg#circle" transform="translate(7 7) scale(0.622 0.622)" />
4 <!-- <text style="font-weight:bold; font-size:10px; font-family:sans-serif;" x="15" y="22">P</text> -->
5 <path id="preview" d="m 17.26,19.4 h 1.87 c 1.34,0 2.2,-0.95 2.2,-2.43 0,-1.46 -0.83,-2.26 -2.35,-2.26 H 15.76 V 22 h 1.5 z m 0,-1.25 v -2.19 h 1.4 c 0.8,0 1.17,0.35 1.17,1.09 0,0.75 -0.37,1.1 -1.17,1.1 z" />
6 </svg>
0 <?xml version="1.0" encoding="UTF-8" ?>
1 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64.8" height="64.8" viewBox="0 0 37 37">
2 <defs>
3 <g id="background">
4 <path d="M 0 0 h 37 v 37 h -37
5 M 7.5 18.5 a 11 11 0 0 0 22 0 a 11 11 0 0 0 -22 0" />
6 </g>
7 <g id="circle">
8 <path d="M 17.25 5.058 v 4.832 a 8.7 8.7 0 0 0 0 17.22 v 4.832 a 13.5 13.5 0 0 1 0 -26.884 z" />
9 <path d="M 19.75 5.058 v 4.832 a 8.7 8.7 0 0 1 0 17.22 v 4.832 a 13.5 13.5 0 0 0 0 -26.884 z" />
10 </g>
11 </defs>
12 <use xlink:href="#background" />
13 <use xlink:href="#circle" transform="translate(7 7) scale(0.622 0.622)" />
14 </svg>
+0
-1
resources/images/android/material_phone_android.svg less more
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 1H8C6.34 1 5 2.34 5 4v16c0 1.66 1.34 3 3 3h8c1.66 0 3-1.34 3-3V4c0-1.66-1.34-3-3-3zm-2 20h-4v-1h4v1zm3.25-3H6.75V4h10.5v14z"/></svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
1 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="240" height="240" viewBox="0 0 320 320">
2 <path fill="#ffffff"
3 d="M 23 160
4 a 137 137 0 0 1 274 0
5 a 137 137 0 0 1 -274 0
6 z
7 M 135 100
8 a 25 25 0 0 0 50 0
9 a 25 25 0 0 0 -50 0
10 z
11 m 10 40
12 a 10 10 0 0 0 -10 10
13 v 85
14 a 10 10 0 0 0 10 10
15 h 30
16 a 10 10 0 0 0 10 -10
17 v -85
18 a 10 10 0 0 0 -10 -10
19 z" />
20 </svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20.5 6c-2.61.7-5.67 1-8.5 1s-5.89-.3-8.5-1L3 8c1.86.5 4 .83 6 1v13h2v-6h2v6h2V9c2-.17 4.14-.5 6-1l-.5-2zM12 6c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20.5 6c-2.61.7-5.67 1-8.5 1s-5.89-.3-8.5-1L3 8c1.86.5 4 .83 6 1v13h2v-6h2v6h2V9c2-.17 4.14-.5 6-1l-.5-2zM12 6c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z" fill="#164a8c"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5.12 10.88L12 17l-1.88-4.12L6 11l4.12-1.88L12 5l1.88 4.12L18 11l-4.12 1.88z" fill="#ffffff"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5.12 10.88L12 17l-1.88-4.12L6 11l4.12-1.88L12 5l1.88 4.12L18 11l-4.12 1.88z" fill="#164a8c"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z" fill="#ffffff"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z" fill="#164a8c"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g><g><path d="M6,14l3,3v5h6v-5l3-3V9H6V14z M11,2h2v3h-2V2z M3.5,5.88l1.41-1.41l2.12,2.12L5.62,8L3.5,5.88z M16.96,6.59l2.12-2.12 l1.41,1.41L18.38,8L16.96,6.59z" fill="#ffffff"/></g></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g><g><path d="M6,14l3,3v5h6v-5l3-3V9H6V14z M11,2h2v3h-2V2z M3.5,5.88l1.41-1.41l2.12,2.12L5.62,8L3.5,5.88z M16.96,6.59l2.12-2.12 l1.41,1.41L18.38,8L16.96,6.59z" fill="#164a8c"/></g></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g/><g fill="#ffffff"><path d="M21,5c-1.11-0.35-2.33-0.5-3.5-0.5c-1.95,0-4.05,0.4-5.5,1.5c-1.45-1.1-3.55-1.5-5.5-1.5S2.45,4.9,1,6v14.65 c0,0.25,0.25,0.5,0.5,0.5c0.1,0,0.15-0.05,0.25-0.05C3.1,20.45,5.05,20,6.5,20c1.95,0,4.05,0.4,5.5,1.5c1.35-0.85,3.8-1.5,5.5-1.5 c1.65,0,3.35,0.3,4.75,1.05c0.1,0.05,0.15,0.05,0.25,0.05c0.25,0,0.5-0.25,0.5-0.5V6C22.4,5.55,21.75,5.25,21,5z M21,18.5 c-1.1-0.35-2.3-0.5-3.5-0.5c-1.7,0-4.15,0.65-5.5,1.5V8c1.35-0.85,3.8-1.5,5.5-1.5c1.2,0,2.4,0.15,3.5,0.5V18.5z"/><g><path d="M17.5,10.5c0.88,0,1.73,0.09,2.5,0.26V9.24C19.21,9.09,18.36,9,17.5,9c-1.7,0-3.24,0.29-4.5,0.83v1.66 C14.13,10.85,15.7,10.5,17.5,10.5z"/><path d="M13,12.49v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26V11.9c-0.79-0.15-1.64-0.24-2.5-0.24 C15.8,11.66,14.26,11.96,13,12.49z"/><path d="M17.5,14.33c-1.7,0-3.24,0.29-4.5,0.83v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26v-1.52 C19.21,14.41,18.36,14.33,17.5,14.33z"/></g></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g/><g fill="#164a8c"><path d="M21,5c-1.11-0.35-2.33-0.5-3.5-0.5c-1.95,0-4.05,0.4-5.5,1.5c-1.45-1.1-3.55-1.5-5.5-1.5S2.45,4.9,1,6v14.65 c0,0.25,0.25,0.5,0.5,0.5c0.1,0,0.15-0.05,0.25-0.05C3.1,20.45,5.05,20,6.5,20c1.95,0,4.05,0.4,5.5,1.5c1.35-0.85,3.8-1.5,5.5-1.5 c1.65,0,3.35,0.3,4.75,1.05c0.1,0.05,0.15,0.05,0.25,0.05c0.25,0,0.5-0.25,0.5-0.5V6C22.4,5.55,21.75,5.25,21,5z M21,18.5 c-1.1-0.35-2.3-0.5-3.5-0.5c-1.7,0-4.15,0.65-5.5,1.5V8c1.35-0.85,3.8-1.5,5.5-1.5c1.2,0,2.4,0.15,3.5,0.5V18.5z"/><g><path d="M17.5,10.5c0.88,0,1.73,0.09,2.5,0.26V9.24C19.21,9.09,18.36,9,17.5,9c-1.7,0-3.24,0.29-4.5,0.83v1.66 C14.13,10.85,15.7,10.5,17.5,10.5z"/><path d="M13,12.49v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26V11.9c-0.79-0.15-1.64-0.24-2.5-0.24 C15.8,11.66,14.26,11.96,13,12.49z"/><path d="M17.5,14.33c-1.7,0-3.24,0.29-4.5,0.83v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26v-1.52 C19.21,14.41,18.36,14.33,17.5,14.33z"/></g></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><g/><g fill="#ffffff"><path d="M21,5c-1.11-0.35-2.33-0.5-3.5-0.5c-1.95,0-4.05,0.4-5.5,1.5c-1.45-1.1-3.55-1.5-5.5-1.5S2.45,4.9,1,6v14.65 c0,0.25,0.25,0.5,0.5,0.5c0.1,0,0.15-0.05,0.25-0.05C3.1,20.45,5.05,20,6.5,20c1.95,0,4.05,0.4,5.5,1.5c1.35-0.85,3.8-1.5,5.5-1.5 c1.65,0,3.35,0.3,4.75,1.05c0.1,0.05,0.15,0.05,0.25,0.05c0.25,0,0.5-0.25,0.5-0.5V6C22.4,5.55,21.75,5.25,21,5z M21,18.5 c-1.1-0.35-2.3-0.5-3.5-0.5c-1.7,0-4.15,0.65-5.5,1.5V8c1.35-0.85,3.8-1.5,5.5-1.5c1.2,0,2.4,0.15,3.5,0.5V18.5z"/><g><path d="M17.5,10.5c0.88,0,1.73,0.09,2.5,0.26V9.24C19.21,9.09,18.36,9,17.5,9c-1.7,0-3.24,0.29-4.5,0.83v1.66 C14.13,10.85,15.7,10.5,17.5,10.5z"/><path d="M13,12.49v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26V11.9c-0.79-0.15-1.64-0.24-2.5-0.24 C15.8,11.66,14.26,11.96,13,12.49z"/><path d="M17.5,14.33c-1.7,0-3.24,0.29-4.5,0.83v1.66c1.13-0.64,2.7-0.99,4.5-0.99c0.88,0,1.73,0.09,2.5,0.26v-1.52 C19.21,14.41,18.36,14.33,17.5,14.33z"/></g></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/><path d="M12,1L3,5v6c0,5.55,3.84,10.74,9,12c5.16-1.26,9-6.45,9-12V5L12,1L12,1z M11,7h2v2h-2V7z M11,11h2v6h-2V11z"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/><path d="M12,1L3,5v6c0,5.55,3.84,10.74,9,12c5.16-1.26,9-6.45,9-12V5L12,1L12,1z M11,7h2v2h-2V7z M11,11h2v6h-2V11z" fill="#164a8c"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><path d="M0,0h24v24H0V0z" fill="none"/><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z" fill="#ffffff"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24" y="0"/></g><g><g><polygon points="9.5,7.5 9.5,16.5 16.5,12"/><path d="M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18.01H4V5.99h16V18.01z"/></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#164a8c"><g><rect fill="none" height="24" width="24" y="0"/></g><g><g><polygon points="9.5,7.5 9.5,16.5 16.5,12"/><path d="M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18.01H4V5.99h16V18.01z"/></g></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M4 14h4v-4H4v4zm0 5h4v-4H4v4zM4 9h4V5H4v4zm5 5h12v-4H9v4zm0 5h12v-4H9v4zM9 5v4h12V5H9z" fill="#ffffff"/><path d="M0 0h24v24H0z" fill="none"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M4 14h4v-4H4v4zm0 5h4v-4H4v4zM4 9h4V5H4v4zm5 5h12v-4H9v4zm0 5h12v-4H9v4zM9 5v4h12V5H9z" fill="#164a8c"/><path d="M0 0h24v24H0z" fill="none"/></svg>
00 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
11 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="240" height="240" viewBox="0 0 320 320">
2 <path fill="#ffffff"
2 <path fill="#164a8c"
33 d="M 23 160
44 a 137 137 0 0 1 274 0
55 a 137 137 0 0 1 -274 0
+0
-1
resources/images/ios/material_phone_iphone.svg less more
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.5 1h-8C6.12 1 5 2.12 5 3.5v17C5 21.88 6.12 23 7.5 23h8c1.38 0 2.5-1.12 2.5-2.5v-17C18 2.12 16.88 1 15.5 1zm-4 21c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4.5-4H7V4h9v14z"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M440-200v-240H200v-80h240v-240h80v240h240v80H520v240h-80Z"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z" fill="#ffffff"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z" fill="#164a8c"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#FFFFFF"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#164a8c"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-6 16h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 11.9 13 12.5 13 14h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z" fill="#ffffff"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 h24v24H0z" fill="none"/><path d="M19 2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-6 16h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 11.9 13 12.5 13 14h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z" fill="#164a8c"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z" fill="#ffffff"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z" fill="#164a8c"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><path d="M0,0h24v24H0V0z" fill="none"/><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z" fill="#ffffff"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><path d="M0,0h24v24H0V0z" fill="none"/><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z" fill="#164a8c"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -2.223 90.952 90.952">
1 <g transform="translate(-314.267 -533.941)" fill="#164a8c">
2 <path d="M13406.908,22776.83H13376.5a3.8,3.8,0,0,1,0-7.6h8.231l1.27-3.8h-20.9c-2.228,0-3.438-.309-4.182-1.062s-1.038-1.965-1.038-4.2v-34.211c0-4.23,1.263-5.521,5.4-5.521h49.476a3.805,3.805,0,0,0,3.736,3,5.577,5.577,0,0,0,4.137-2.037c1.054.809,1.522,2.215,1.522,4.559v5.477h-5.728v-5.477h-52.932v34.211h43v5.266h-11.084l1.27,3.8h8.231a3.8,3.8,0,0,1,0,7.6Z"
3 transform="translate(-13045.613 -22168)" />
4 <path d="M28.562,7.135v1.81a1.815,1.815,0,0,0,1.81,1.81H41.231a1.815,1.815,0,0,0,1.81-1.81V7.135h3.62a1.815,1.815,0,0,1,1.81,1.81V48.76a1.815,1.815,0,0,1-1.81,1.81H24.943a1.815,1.815,0,0,1-1.81-1.81V8.945a1.815,1.815,0,0,1,1.81-1.81Zm-3.62-5.3c-5,0-7.076,2.107-7.076,7.107V48.76c0,5,2.076,7.1,7.076,7.1H46.66c5,0,7.031-2.1,7.031-7.1V8.945c0-5-2.032-7.107-7.031-7.107Z"
5 transform="translate(348.012 564.588)" />
6 <path d="M20.472,52.468a4.106,4.106,0,1,0,4.105,4.106A4.105,4.105,0,0,0,20.472,52.468Zm.058-10.263A18.452,18.452,0,0,0,8.31,46.826a2.129,2.129,0,0,0-.18,2.955,2.058,2.058,0,0,0,2.9.18,14.358,14.358,0,0,1,19,0,2.054,2.054,0,0,0,2.72-3.079A18.51,18.51,0,0,0,20.53,42.205ZM40.427,40A28.744,28.744,0,0,0,.635,40a2.053,2.053,0,0,0,2.842,2.963A24.176,24.176,0,0,1,20.53,36.105a24.609,24.609,0,0,1,17.049,6.857A2.075,2.075,0,0,0,39,43.533,2.054,2.054,0,0,0,40.427,40Z"
7 transform="translate(364.164 501.941)" />
8 </g>
9 </svg>
66 m 0 3 a 1 1 0 0 1 0 -2 h 9 a 1 1 0 0 1 0 2 z
77 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
88 m -9.64 -11.8 a 5 5 0 0 0 10 0 a 5 5 0 0 0 -10 0 z
9 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"/>
9 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" />
1010 </svg>
00 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
11 <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="240" height="240" viewBox="0 0 840 840" >
2 <g transform="translate(-235,-280) scale(1.2,1.2)" fill="#ffffff">
2 <g transform="translate(-235,-280) scale(1.2,1.2)" fill="#164a8c">
33 <path d="M 210 432 c0 -11 8 -26 18 -34 22 -18 293 -128 317 -128 24 0 295 110 318 128 9 8 17 23 17 34 0 17 -16 18 -335 18 -319 0 -335 -1 -335 -18 Z
44 M 320 445 H 770 V 840 a 50 50 0 0 1 -50 50 L 370 890 a 50 50 0 0 1 -50 -50 Z
55 M 546.5 505 a 168.33 168.33 0 0 0 0 336.66 a 168.33 168.33 0 0 0 0 -336.66 z
00 FROM dev-docker.governikus.de/ausweisapp2/ubuntu:swarm
11 MAINTAINER Governikus KG <support@ausweisapp.de>
22
3 ARG ANDROID_CMDLINE_TOOLS=8092744
4 ARG ANDROID_NDK_VERSION=21.4.7075529
5 ARG CMAKE=3.22.2
3 ARG ANDROID_CMDLINE_TOOLS=9477386
4 ARG ANDROID_NDK_VERSION=25.2.9519653
5 ARG CMAKE=3.26.3
66 ENV NAME=Android LABELS="Android" PACKAGES_DIR=/home/governikus/packages
77
88 ENV ANDROID_SDK_ROOT /opt/android-sdk
99 ENV ANDROID_NDK_ROOT $ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION
10
11 # Remove this later: https://github.com/openssl/openssl/pull/11206
12 ENV ANDROID_NDK $ANDROID_NDK_ROOT
1310
1411 RUN apt-get update && \
1512 apt-get -y install g++ make ccache ninja-build perl unzip gradle maven patch openjdk-11-jdk-headless && \
2118
2219 RUN mkdir -p /tmp/dl && cd /tmp/dl && wget -O sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_CMDLINE_TOOLS}_latest.zip && \
2320 unzip sdk.zip && \
24 yes | /tmp/dl/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "cmdline-tools;6.0" "build-tools;30.0.3" "platforms;android-33" "ndk;${ANDROID_NDK_VERSION}" && \
21 yes | /tmp/dl/cmdline-tools/bin/sdkmanager --sdk_root=$ANDROID_SDK_ROOT "cmdline-tools;9.0" "build-tools;33.0.2" "platforms;android-33" "ndk;${ANDROID_NDK_VERSION}" && \
2522 rm -rf /tmp/dl
2623
2724 USER governikus
3737 android:name="org.qtproject.qt.android.bindings.QtApplication"
3838 android:allowBackup="false"
3939 android:allowNativeHeapPointerTagging="false"
40 android:dataExtractionRules="@xml/data_extraction_rules"
4041 android:extractNativeLibs="true"
42 android:fullBackupContent="@xml/full_backup_content"
4143 android:hardwareAccelerated="true"
4244 android:icon="@mipmap/npa"
4345 android:label="@string/app_name"
3636 exclude 'META-INF/native-image/**'
3737 exclude 'META-INF/native/**'
3838 exclude 'META-INF/license/**'
39 exclude '**/libplugins_tls_qcertonlybackend_*.so'
40 exclude '**/libplugins_networkinformation_*.so'
41 exclude '**/libplugins_imageformats_qgif_*.so'
42 exclude '**/libplugins_imageformats_qicns_*.so'
43 exclude '**/libplugins_imageformats_qico_*.so'
44 exclude '**/libplugins_imageformats_qtga_*.so'
45 exclude '**/libplugins_imageformats_qtiff_*.so'
46 exclude '**/libplugins_imageformats_qwebp_*.so'
47 exclude '**/libplugins_imageformats_qwbmp_*.so'
3948
4049 jniLibs {
4150 useLegacyPackaging = true
0 android {
1 packagingOptions {
2 exclude '**/libplugins_imageformats_*.so'
3 }
4 }
0 <?xml version="1.0" encoding="utf-8"?>
1 <data-extraction-rules>
2 <cloud-backup>
3 <exclude domain="root" path="." />
4 <exclude domain="file" path="." />
5 <exclude domain="database" path="." />
6 <exclude domain="sharedpref" path="." />
7 <exclude domain="external" path="." />
8 </cloud-backup>
9 <device-transfer>
10 <exclude domain="root" path="." />
11 <exclude domain="file" path="." />
12 <exclude domain="database" path="." />
13 <exclude domain="sharedpref" path="." />
14 <exclude domain="external" path="." />
15 </device-transfer>
16 </data-extraction-rules>
0 <?xml version="1.0" encoding="utf-8"?>
1 <full-backup-content>
2 <exclude domain="root" path="." />
3 <exclude domain="file" path="." />
4 <exclude domain="database" path="." />
5 <exclude domain="sharedpref" path="." />
6 <exclude domain="external" path="." />
7 </full-backup-content>
00 <?xml version="1.0" encoding="UTF-8"?>
11 <lint>
2 <!-- Class is not registered in the manifest.
3
4 Activities, services and content providers should be registered in the
5 AndroidManifest.xml file using <activity>, <service> and <provider> tags.
6
7 If your activity is simply a parent class intended to be subclassed
8 by other "real" activities, make it an abstract class.
9
10 We can not make the classes abstract, because Qt provides
11 it and it should be possible to use it without subclassing.
12 -->
13 <issue id="Registered">
14 <ignore path="**/dist/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java" />
15 <ignore path="**/dist/src/android/java/src/org/qtproject/qt5/android/bindings/QtService.java" />
16 </issue>
17
182 <!-- Obsolete Gradle Dependency.
193
204 The used version is provided by Qt in the build.gradle. Its not
2610 <ignore path="build.gradle" />
2711 </issue>
2812
29 <!-- Obsolete custom lint check
30
31 Lint can be extended with custom checks: additional checks implemented by developers and libraries to for example
32 enforce specific API usages required by a library or a company coding style guideline.
33 The Lint APIs are not yet stable, so these checks may either cause a performance degradation, or stop working,
34 or provide wrong results.
35 This warning flags custom lint checks that are found to be using obsolete APIs and will need to be updated
36 to run in the current lint environment.
37 It may also flag issues found to be using a **newer** version of the API, meaning that you need to use a newer
38 version of lint (or Android Studio or Gradle plugin etc) to work with these checks.
39 -->
40 <issue id="ObsoleteLintCustomCheck">
41 <ignore path="**/appcompat-1.**/**/lint.jar" />
42 </issue>
43
4413 <!-- Unused resources.
4514
4615 Unused resources make applications larger and slow down builds.
4716
48 https://bugreports.qt.io/browse/QTBUG-72976
49
5017 Qt includes some resources like strings, which are seen by lint to be unused.
5118 -->
5219 <issue id="UnusedResources">
53 <ignore path="**/dist/src/android/java/res/layout/splash.xml" />
5420 <ignore path="**/libs.xml" />
5521 <ignore path="**/strings.xml" />
5622 </issue>
00 <?xml version="1.0" encoding="UTF-8"?>
11 <lint>
2 <!-- Class is not registered in the manifest.
3
4 Activities, services and content providers should be registered in the
5 AndroidManifest.xml file using <activity>, <service> and <provider> tags.
6
7 If your activity is simply a parent class intended to be subclassed
8 by other "real" activities, make it an abstract class.
9
10 We can not make the classes abstract, because Qt provides
11 it and it should be possible to use it without subclassing.
12 -->
13 <issue id="Registered">
14 <ignore path="**/dist/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java" />
15 <ignore path="**/dist/src/android/java/src/org/qtproject/qt5/android/bindings/QtService.java" />
16 </issue>
17
182 <!-- Obsolete Gradle Dependency.
193
204 The used version is provided by Qt in the build.gradle. Its not
2610 <ignore path="build.gradle" />
2711 </issue>
2812
29 <!-- Obsolete custom lint check
30
31 Lint can be extended with custom checks: additional checks implemented by developers and libraries to for example
32 enforce specific API usages required by a library or a company coding style guideline.
33 The Lint APIs are not yet stable, so these checks may either cause a performance degradation, or stop working,
34 or provide wrong results.
35 This warning flags custom lint checks that are found to be using obsolete APIs and will need to be updated
36 to run in the current lint environment.
37 It may also flag issues found to be using a **newer** version of the API, meaning that you need to use a newer
38 version of lint (or Android Studio or Gradle plugin etc) to work with these checks.
39 -->
40 <issue id="ObsoleteLintCustomCheck">
41 <ignore path="**/appcompat-1.**/**/lint.jar" />
42 </issue>
43
4413 <!-- Unused resources.
4514
4615 Unused resources make applications larger and slow down builds.
4716
48 https://bugreports.qt.io/browse/QTBUG-72976
49
5017 Qt includes some resources like strings, which are seen by lint to be unused.
5118 -->
5219 <issue id="UnusedResources">
53 <ignore path="**/dist/src/android/java/res/layout/splash.xml" />
5420 <ignore path="**/libs.xml" />
5521 <ignore path="**/strings.xml" />
56 </issue>
57
58 <!-- Unused Exported service does not require permission.
59
60 Exported services (services which either set exported=true or contain
61 an intent-filter and do not specify exported=false) should define a
62 permission that an entity must have in order to launch the service or
63 bind to it. Without this, any application can use this service.
64
65 We decided to ignore this warning because we do not want to limit the
66 access to the service. Any application should be able to use the
67 service without additional barriers.
68 -->
69 <issue id="ExportedService">
70 <ignore path="AndroidManifest.xml" />
7122 </issue>
7223
7324 <!-- Activity is set to be non resizeable
7930 We can ignore it as the AusweisApp2 still doesn't properly support multi-window environments.
8031 -->
8132 <issue id="NonResizeableActivity">
82 <ignore path="AndroidManifest.xml" />
83 </issue>
84
85 <!-- Missing registered class
86
87 If a class is referenced in the manifest or in a layout file, it must also exist in the project (or in one of
88 the libraries included by the project. This check helps uncover typos in registration names, or attempts to
89 rename or move classes without updating the XML references properly.
90
91 Somehow android lint isn't able to find the classes like the MainActivity, when checking the app.
92 We can just ignore it for now, as it will be pretty obvious, if the MainActivity is missing and nothing is shown.
93 -->
94 <issue id="MissingClass">
95 <ignore path="AndroidManifest.xml" />
96 </issue>
97
98 <!-- Missing data extraction rules
99
100 The attribute `android:allowBackup` is deprecated from Android 12 and higher and may be removed in
101 future versions. Consider adding the attribute `android:dataExtractionRules` specifying an `@xml`
102 resource which configures cloud backups and device transfers on Android 12 and higher.
103 Before Android 12, the attributes `android:allowBackup` and `android:fullBackupContent` were used
104 to configure all orms of backup, including cloud backups, device-to-device transfers and adb backup.
105
106 In Android 12 and higher, these attributes have been deprecated and will only apply to cloud backups.
107 You should instead use the attribute `android:dataExtractionRules`, specifying an `@xml` resource that
108 configures which files to back up, for cloud backups and for device-to-device transfers, separately.
109 If your `minSdkVersion` supports older versions, you'll still want to specify an
110 `android:fullBackupContent` resource if the default behavior is not right for your app.
111 -->
112 <issue id="DataExtractionRules">
11333 <ignore path="AndroidManifest.xml" />
11434 </issue>
11535
14767 <issue id="DiscouragedApi">
14868 <ignore path="**/QtLoader.java" />
14969 </issue>
150
151 <!-- Unused attribute
152
153 We are setting some flags that are only available in later api version, which get flagged by lint as unused.
154 -->
155 <issue id="UnusedAttribute">
156 <ignore path="AndroidManifest.xml" />
157 </issue>
15870 </lint>
11 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
22 <background android:drawable="@mipmap/npa_background"/>
33 <foreground android:drawable="@mipmap/npa_foreground"/>
4 <monochrome android:drawable="@mipmap/npa_monochrome" />
45 </adaptive-icon>
113113 let initialSize = plugin.initialWindowSize;
114114 ApplicationModel.scaleFactor = Math.min(width / initialSize.width, height / initialSize.height);
115115 }
116 function showDetachedLogViewIfPresent() {
117 if (d.detachedLogView !== null) {
118 d.detachedLogView.show();
119 }
120 }
116121 function showMainWindow() {
117122 d.suppressAbortWarning = false;
118123 if (active) {
186191 function onFireShowRequest(pModule) {
187192 d.showMainWindow();
188193 d.closeOpenDialogs();
194 d.showDetachedLogViewIfPresent();
189195 switch (pModule) {
190196 case UiModule.CURRENT:
191197 break;
235241
236242 onActivated: ApplicationModel.openOnlineHelp(menuBar.rightMostAction.helpTopic)
237243 }
244 Shortcut {
245 enabled: Qt.platform.os === "osx"
246 sequence: "Ctrl+W"
247
248 onActivated: close()
249 }
238250 Image {
239251 anchors.centerIn: parent
240252 fillMode: Image.PreserveAspectFit
413425 d.detachedLogView = null;
414426 }
415427
428 Shortcut {
429 enabled: Qt.platform.os === "osx"
430 sequence: "Ctrl+W"
431
432 onActivated: close()
433 }
416434 DetachedLogView {
417435 anchors.fill: parent
418436 focus: true
3030 Progress,
3131 AccessRights,
3232 Workflow,
33 WorkflowError,
3334 Password,
3435 PasswordInfo,
3536 CardPosition,
158159 return Workflow.WaitingFor.None;
159160 }
160161
162 onDeviceUnpaired: function (pDeviceName) {
163 deviceUnpairedView.deviceName = pDeviceName;
164 showWithPrecedingView(AuthView.SubViews.WorkflowError);
165 }
161166 onSettingsRequested: authView.showSettings()
167 }
168 ResultView {
169 id: deviceUnpairedView
170
171 property string deviceName
172
173 resultType: ResultView.Type.IsError
174 //: 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.
175 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)
176 visible: d.activeView === AuthView.SubViews.WorkflowError
177
178 onNextView: d.view = AuthView.SubViews.Workflow
162179 }
163180 EnterPasswordView {
164181 id: enterPasswordView
285302 header: AuthModel.errorHeader
286303 hintButtonText: AuthModel.statusHintActionText
287304 hintText: AuthModel.statusHintText
305 mailButtonVisible: AuthModel.errorIsMasked
288306 popupText: AuthModel.errorText
289307 //: INFO DESKTOP Error code (string) of current GlobalStatus code, shown as header of popup.
290308 popupTitle: qsTr("Error code: %1").arg(AuthModel.statusCodeString)
291309 resultType: AuthModel.resultString ? ResultView.Type.IsError : ResultView.Type.IsSuccess
292 supportButtonsVisible: AuthModel.errorIsMasked
293310 text: AuthModel.resultString
294311 visible: d.activeView === AuthView.SubViews.Result
295312
104104 id: detailsButton
105105 Accessible.description: qsTr("Show more information about the service provider")
106106 activeFocusOnTab: true
107 icon.source: "qrc:///images/info.svg"
107 icon.source: "qrc:///images/desktop/info_white.svg"
108108
109109 //: LABEL DESKTOP
110110 text: qsTr("Details about the provider")
1818 property alias dataText: dataPasswordText.text
1919 property var workflowModel: AuthModel
2020
21 signal rightsAccepted
22
2123 //: LABEL IOS_PHONE ANDROID_PHONE
2224 title: qsTr("Identify")
2325
118120 qsTr("PIN"))
119121 tintIcon: true
120122
121 onClicked: {
122 ChatModel.transferAccessRights();
123 workflowModel.continueWorkflow();
124 }
123 onClicked: rightsAccepted()
125124 }
126125 GText {
127126 id: dataPasswordText
137136
138137 //: LABEL IOS_PHONE ANDROID_PHONE
139138 title: qsTr("Transactional information")
140 visible: !!AuthModel.transactionInfo || (!writeData.visible && !readData.visible)
139 visible: !!workflowModel.transactionInfo || (!writeData.visible && !readData.visible)
141140
142141 anchors {
143142 left: parent.left
1818 property alias dataText: dataPasswordText.text
1919 property var workflowModel: AuthModel
2020
21 signal rightsAccepted
22
2123 //: LABEL ANDROID_TABLET IOS_TABLET
2224 title: qsTr("Identify")
2325
7981 qsTr("PIN"))
8082 tintIcon: true
8183
82 onClicked: {
83 ChatModel.transferAccessRights();
84 workflowModel.continueWorkflow();
85 }
84 onClicked: rightsAccepted()
8685
8786 anchors {
8887 right: parent.right
1313 import Governikus.Workflow 1.0
1414 import Governikus.Type.ApplicationModel 1.0
1515 import Governikus.Type.AuthModel 1.0
16 import Governikus.Type.ChatModel 1.0
1617 import Governikus.Type.LogModel 1.0
1718 import Governikus.Type.NumberModel 1.0
1819 import Governikus.Type.PasswordType 1.0
8081 Component {
8182 id: editRights
8283 EditRights {
84 onRightsAccepted: {
85 ChatModel.transferAccessRights();
86 AuthModel.continueWorkflow();
87 }
8388 }
8489 }
8590 Component {
2121 enum SubViews {
2222 Start,
2323 Workflow,
24 WorkflowError,
2425 Password,
2526 NoPassword,
2627 PasswordInfo,
143144 return Workflow.WaitingFor.None;
144145 }
145146
147 onDeviceUnpaired: function (pDeviceName) {
148 deviceUnpairedView.deviceName = pDeviceName;
149 showWithPrecedingView(ChangePinView.SubViews.WorkflowError);
150 }
146151 onSettingsRequested: baseItem.showSettings()
152 }
153 ResultView {
154 id: deviceUnpairedView
155
156 property string deviceName
157
158 resultType: ResultView.Type.IsError
159 //: 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.
160 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)
161 visible: d.activeView === ChangePinView.SubViews.WorkflowError
162
163 onNextView: d.view = ChangePinView.SubViews.Workflow
147164 }
148165 EnterPasswordView {
149166 id: enterPasswordView
237254 id: pinResult
238255 hintButtonText: ChangePinModel.statusHintActionText
239256 hintText: ChangePinModel.statusHintText
257 mailButtonVisible: ChangePinModel.errorIsMasked
240258 resultType: ChangePinModel.error ? ResultView.Type.IsError : ResultView.Type.IsSuccess
241 supportButtonsVisible: ChangePinModel.errorIsMasked
242259 text: ChangePinModel.resultString
243260 visible: d.activeView === ChangePinView.SubViews.Result
244261
199199 }
200200 if (passwordType === PasswordType.REMOTE_PIN) {
201201 //: INFO DESKTOP The pairing code needs to be supplied.
202 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).");
202 return qsTr("Enter the pairing code shown on your smartphone.");
203203 }
204204
205205 //: INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error.
6262 enabled: baseItem.deleteEnabled
6363 fontScale: 0.75
6464 text: "C"
65 visualPrivacy: SettingsModel.visualPrivacy
6566
6667 onClicked: baseItem.deletePressed()
6768 }
7980 enabled: baseItem.submitEnabled
8081 fontScale: 0.75
8182 text: "OK"
83 visualPrivacy: SettingsModel.visualPrivacy
8284
8385 onClicked: baseItem.submitPressed()
8486 }
5555 enabled: baseItem.deleteEnabled
5656 icon.source: "qrc:///images/mobile/material_backspace.svg"
5757 text: qsTr("Delete last digit")
58 visualPrivacy: SettingsModel.visualPrivacy
5859
5960 onClicked: baseItem.deletePressed()
6061 }
7374 enabled: baseItem.submitEnabled
7475 icon.source: "qrc:///images/material_check.svg"
7576 text: qsTr("Submit")
77 visualPrivacy: SettingsModel.visualPrivacy
7678
7779 onClicked: baseItem.submitPressed()
7880 }
1717 enabled: visible
1818 preventStealing: enabled
1919
20 onPositionChanged: {
20 onPositionChanged: mouse => {
2121 let currentVelocity = mouse.x - previousPosX;
2222 velocity = (velocity + currentVelocity) / 2.0;
2323 previousPosX = mouse.x;
3232 mouse.accepted = false;
3333 }
3434 }
35 onReleased: {
35 onReleased: mouse => {
3636 let swipeDistance = mouse.x - startPosX;
3737 if (swipeDistance > minSwipeDistance && velocity > minVelocity) {
3838 backGestureTriggered();
1010 property alias busy: busyIndicator.visible
1111 property alias contentBackgroundColor: content.color
1212 property alias source: image.source
13 property alias text: text.text
14 property alias textStyle: text.textStyle
13 property alias text: iconText.text
14 property alias textStyle: iconText.textStyle
1515
1616 border.color: borderEnabled ? Style.color.accent : Style.color.transparent
1717 border.width: height / 40
4747 visible: source.toString().length > 0
4848 }
4949 GText {
50 id: text
50 id: iconText
5151 Accessible.ignored: true
5252 anchors.centerIn: parent
5353 textStyle: Style.text.title_accent
33 pragma Singleton
44 import QtQuick 2.15
55 import Governikus.Type.ApplicationModel 1.0
6 import Governikus.Type.SettingsModel 1.0
67
78 QtObject {
8 function escapeHtml(str) {
9 return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
9 function escapeHtml(pStr) {
10 return String(pStr).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1011 }
1112 function helpTopicOf(pComponent, pDefaultHelpTopic) {
1213 if (pComponent && typeof (pComponent.helpTopic) !== "undefined") {
1516 return pDefaultHelpTopic;
1617 }
1718 }
18 function isSameDate(one, another) {
19 return one.getFullYear() === another.getFullYear() && one.getMonth() === another.getMonth() && one.getDate() === another.getDate();
19 function historyDateString(pDate) {
20 //: LABEL ALL_PLATFORMS
21 return (isToday(pDate) ? qsTr("today") :
22 //: LABEL ALL_PLATFORMS
23 isYesterday(pDate) ? qsTr("yesterday") :
24 // dddd is without translation because we want the long day name with every language
25 isThisWeek(pDate) ? pDate.toLocaleString(Qt.locale(SettingsModel.language), "dddd") :
26 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString
27 pDate.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy")));
2028 }
21 function isThisWeek(date) {
29 function isSameDate(pOne, pAnother) {
30 return pOne.getFullYear() === pAnother.getFullYear() && pOne.getMonth() === pAnother.getMonth() && pOne.getDate() === pAnother.getDate();
31 }
32 function isThisWeek(pDate) {
2233 var monday = new Date;
2334 monday.setDate(monday.getDate() - monday.getDay());
24 date.setDate(date.getDate() - date.getDay());
25 return isSameDate(monday, date);
35 pDate.setDate(pDate.getDate() - pDate.getDay());
36 return isSameDate(monday, pDate);
2637 }
27 function isToday(date) {
38 function isToday(pDate) {
2839 var today = new Date;
29 return isSameDate(today, date);
40 return isSameDate(today, pDate);
3041 }
31 function isYesterday(date) {
42 function isYesterday(pDate) {
3243 var yesterday = new Date;
3344 yesterday.setDate(yesterday.getDate() - 1);
34 return isSameDate(yesterday, date);
45 return isSameDate(yesterday, pDate);
3546 }
3647 function scrollPageDown(pFlickable) {
3748 if (pFlickable.height >= pFlickable.contentHeight) {
116116 }
117117 sectionDelegate: TabbedPaneDelegateIconAndThreeLineText {
118118 footerText: model ? model.purpose : ""
119 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"))) : "")
119 headerText: model ? Utils.historyDateString(model.dateTime) : ""
120120 iconPath: model ? model.providerIcon : ""
121121 sectionName: model ? model.subject : ""
122122 }
5454 if (!historyModelItem) {
5555 return "";
5656 }
57 //: LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString
5758 return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"));
5859 }
5960 textUppercase: Font.AllUppercase
99 ListItem {
1010 property var historyModelItem
1111
12 //: LABEL ANDROID IOS
1213 Accessible.description: qsTr("Click to view details of history entry.")
1314 //: LABEL ANDROID IOS
1415 footerText: historyModelItem.purpose !== "" ? historyModelItem.purpose : qsTr("Tap for more details")
15 //: LABEL ANDROID IOS
16 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")))
16 headerText: Utils.historyDateString(dateTime)
1717 height: 72
1818 icon: providerIcon !== "" ? providerIcon : (historyModelItem ? Category.imageSource(historyModelItem.providerCategory) : Category.imageSource("unknown"))
1919 text: subject
6161 if (!historyModelItem) {
6262 return "";
6363 }
64 //: LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString
6465 return historyModelItem.dateTime.toLocaleString(Qt.locale(), qsTr("dd.MM.yyyy"));
6566 }
6667 width: parent.width
3030 module: UiModule.PROVIDER
3131 }
3232 ListElement {
33 desc: QT_TR_NOOP("Remote")
34 image: "qrc:///images/mobile/platform_specific_phone.svg"
33 desc: QT_TR_NOOP("Card reader")
34 image: "qrc:///images/mobile/phone_card_reader.svg"
3535 module: UiModule.REMOTE_SERVICE
3636 }
3737 ListElement {
2727 GText {
2828 id: date
2929 font.capitalization: Font.AllUppercase
30 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")))
30 text: Utils.historyDateString(dateTime)
3131 textStyle: Style.text.normal
3232 }
3333 GridLayout {
2222 contentMarginRight: 0
2323 //: LABEL ANDROID IOS
2424 footerText: purposeText !== "" ? purposeText : qsTr("Touch for more details")
25
26 //: LABEL ANDROID IOS
27 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")))
25 headerText: Utils.historyDateString(dateTime)
2826 height: 72
2927 //: LABEL ANDROID IOS
3028 text: (!!providerName ? providerName : qsTr("Touch for more details"))
77 import Governikus.Style 1.0
88
99 MouseArea {
10 id: root
11
1012 property alias description: descriptionText.text
13 property bool highlightTitle: false
1114 property alias linkInactive: linkQualityItem.inactive
1215 property alias linkQuality: linkQualityItem.percent
16 property alias linkQualityVisible: linkQualityItem.visible
1317 property alias title: titleText.text
1418
1519 Accessible.name: qsTr("Device %1. %2.").arg(title).arg(description)
1620 Accessible.role: Accessible.ListItem
17 height: content.implicitHeight
18 width: content.implicitWidth
21 implicitHeight: content.implicitHeight
22 implicitWidth: content.implicitWidth
1923
2024 Accessible.onPressAction: clicked(null)
2125
3438 Layout.fillWidth: true
3539 elide: Text.ElideRight
3640 maximumLineCount: 1
37 textStyle: Style.text.normal_accent
41 textStyle: root.highlightTitle ? Style.text.normal_accent_highlight : Style.text.normal_accent
3842 }
3943 GText {
4044 id: descriptionText
4347 elide: Text.ElideRight
4448 maximumLineCount: 1
4549 textStyle: Style.text.hint_secondary
50 visible: text !== ""
4651 }
4752 }
4853 LinkQuality {
1212 GText {
1313 horizontalAlignment: Text.AlignHCenter
1414 //: INFO IOS Let user know to check the application settings for local network permission
15 text: qsTr("To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.")
15 text: qsTr("Ensure that access to the local network is allowed in your settings.")
1616 textStyle: Style.text.normal_secondary
1717 width: parent.width
1818 }
0 /**
1 * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany
2 */
3 import QtQuick 2.15
4 import QtQuick.Controls 2.15
5 import QtQuick.Layouts 1.15
6 import Governikus.Global 1.0
7 import Governikus.TitleBar 1.0
8 import Governikus.Style 1.0
9 import Governikus.View 1.0
10 import Governikus.Type.ApplicationModel 1.0
11
12 SectionPage {
13 property alias text: description.text
14
15 signal navActionClicked
16
17 hiddenNavbarPadding: true
18
19 //: LABEL ANDROID IOS
20 title: qsTr("Pairing Information")
21
22 content: ColumnLayout {
23 anchors.left: parent.left
24 anchors.margins: Constants.pane_padding
25 anchors.right: parent.right
26 spacing: Constants.component_spacing
27
28 Image {
29 Layout.alignment: Qt.AlignHCenter
30 Layout.preferredHeight: Style.dimens.medium_icon_size
31 Layout.topMargin: Constants.pane_padding
32 fillMode: Image.PreserveAspectFit
33 source: "qrc:///images/phone_to_pc.svg"
34 sourceSize.height: Style.dimens.medium_icon_size
35 }
36 GText {
37 id: description
38 Layout.alignment: Qt.AlignCenter
39 Layout.topMargin: Constants.component_spacing
40 //: LABEL ANDROID IOS
41 textStyle: Style.text.header_accent
42 }
43 Repeater {
44 model: [
45 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3
46 qsTr("Open %1 on your %2other device%3.").arg(Qt.application.name).arg("<b>").arg("</b>"),
47 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font.
48 qsTr("On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.").arg("<b>").arg("</b>"),
49 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3
50 qsTr("Choose this smartphone in the list to pair it.")]
51
52 RowLayout {
53 Layout.topMargin: Constants.component_spacing
54 spacing: Constants.text_spacing
55 width: parent.width
56
57 GText {
58 Accessible.ignored: true
59 Layout.alignment: Qt.AlignTop
60 Layout.preferredWidth: Style.dimens.small_icon_size
61 text: (index + 1) + "."
62 }
63 GText {
64 Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData)
65 Layout.alignment: Qt.AlignTop
66 Layout.fillWidth: true
67 text: modelData
68 }
69 }
70 }
71 RemoteServiceWifiInfo {
72 Layout.fillWidth: true
73 Layout.topMargin: Constants.component_spacing
74 }
75 }
76 navigationAction: NavigationAction {
77 id: navAction
78 action: NavigationAction.Action.Back
79
80 onClicked: navActionClicked()
81 }
82 }
0 /**
1 * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany
2 */
3 import QtQuick 2.15
4 import QtQuick.Layouts 1.15
5 import Governikus.Global 1.0
6 import Governikus.Style 1.0
7 import Governikus.Type.ApplicationModel 1.0
8
9 ColumnLayout {
10 Repeater {
11 model: [
12 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.
13 qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version),
14 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.
15 qsTr("Open %1 on your smartphone as card reader.").arg(Qt.application.name),
16 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font.
17 qsTr("On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.").arg("<b>").arg("</b>"),
18 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4
19 qsTr("Choose the smartphone in the list shown here to pair it.")]
20
21 RowLayout {
22 Layout.fillWidth: true
23 Layout.topMargin: Constants.component_spacing
24 spacing: Constants.text_spacing
25
26 GText {
27 Accessible.ignored: true
28 Layout.alignment: Qt.AlignTop
29 Layout.preferredWidth: Style.dimens.small_icon_size
30 text: (index + 1) + "."
31 }
32 GText {
33 Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData)
34 Layout.alignment: Qt.AlignTop
35 Layout.fillWidth: true
36 text: modelData
37 }
38 }
39 }
40 }
1616 sectionPageFlickable: contentItem
1717
1818 //: LABEL ANDROID IOS
19 title: qsTr("Remote service")
19 title: qsTr("Card reader")
2020
2121 navigationAction: NavigationAction {
2222 action: RemoteServiceModel.running ? NavigationAction.Action.Cancel : NavigationAction.Action.None
2727 Connections {
2828 function onFireIsRunningChanged() {
2929 setLockedAndHidden(RemoteServiceModel.running);
30 pairingButton.didPairInSaKSession = false;
31 }
32 function onFirePairingCompleted() {
33 pairingButton.didPairInSaKSession = true;
34 }
35 //: ERROR ANDROID IOS An error occurred while pairing the device.
30 }
3631 function onFirePairingFailed() {
32 //: ERROR ANDROID IOS An error occurred while pairing the device.
3733 ApplicationModel.showFeedback(qsTr("Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code."));
3834 }
3935
5450 when: RemoteServiceModel.running && RemoteServiceModel.isPairing
5551
5652 PropertyChanges {
53 target: knownDevices
54 visible: false
55 }
56 PropertyChanges {
5757 target: pairingCode
5858 visible: true
5959 }
6060 PropertyChanges {
61 target: wifiInfo
61 target: paringCodeLink
6262 visible: true
63 }
64 PropertyChanges {
65 target: networkPermissionText
66 visible: RemoteServiceModel.requiresLocalNetworkPermission
67 }
68 },
69 State {
70 name: "UNCONNECTED"
71 when: RemoteServiceModel.running && !RemoteServiceModel.connectedToPairedDevice
72
73 PropertyChanges {
74 target: pairingCode
75 visible: false
76 }
77 PropertyChanges {
78 target: wifiInfo
79 visible: true
80 }
81 PropertyChanges {
82 target: networkPermissionText
83 visible: RemoteServiceModel.requiresLocalNetworkPermission
8463 }
8564 },
8665 State {
8766 name: "CONNECTED_OR_STOPPED"
8867 when: !RemoteServiceModel.running || (RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice)
8968
90 PropertyChanges {
91 target: pairingCode
92 visible: false
93 }
9469 PropertyChanges {
9570 target: wifiInfo
9671 visible: false
12499 //: LABEL ANDROID IOS
125100 RemoteServiceModel.connectedToPairedDevice ? qsTr("Card access in progress") :
126101 //: LABEL ANDROID IOS
127 RemoteServiceModel.isPairing || RemoteServiceModel.running ? qsTr("Waiting for connection") :
128 //: LABEL ANDROID IOS
129 qsTr("Remote service ready")
102 RemoteServiceModel.isPairing ? qsTr("Waiting for pairing") :
103 //: LABEL ANDROID IOS
104 RemoteServiceModel.running ? qsTr("Waiting for connection") : ""
130105 textStyle: Style.text.header_accent
131106 }
132107 GText {
108 id: infoText
109
133110 readonly property string currentPin: RemoteServiceModel.psk
134111 //: INFO ANDROID IOS
135 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).")
136
137 Accessible.name: RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name) : text
112 readonly property string enterCodeString: qsTr("Enter the pairing code %1 in the %2 on your other device.")
113
114 Accessible.name: text
138115 Layout.fillWidth: true
139116 Layout.topMargin: Constants.text_spacing
140117 horizontalAlignment: Text.AlignHCenter
141 text: !RemoteServiceModel.runnable ? RemoteServiceModel.errorMessage : RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice ? RemoteServiceModel.connectionInfo : RemoteServiceModel.isPairing ? enterCodeString.arg(currentPin).arg(Qt.application.name) :
142118 //: INFO ANDROID IOS
143 RemoteServiceModel.running ? qsTr("Waiting for connection from a paired device...") :
144 //: INFO ANDROID IOS
145 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.")
119 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)
146120 textStyle: RemoteServiceModel.runnable ? Style.text.normal_secondary : Style.text.normal_warning
121
122 states: [
123 State {
124 when: !RemoteServiceModel.runnable
125
126 PropertyChanges {
127 target: infoText
128 text: RemoteServiceModel.errorMessage
129 }
130 },
131 State {
132 when: RemoteServiceModel.running && RemoteServiceModel.connectedToPairedDevice
133
134 PropertyChanges {
135 target: infoText
136 text: RemoteServiceModel.connectionInfo
137 }
138 },
139 State {
140 when: RemoteServiceModel.isPairing
141
142 PropertyChanges {
143 Accessible.name: enterCodeString.arg(currentPin.split("").join(" ")).arg(Qt.application.name)
144 target: infoText
145 text: enterCodeString.arg(currentPin).arg(Qt.application.name)
146 }
147 },
148 State {
149 when: !RemoteServiceModel.running && knownDeviceList.count > 0
150
151 PropertyChanges {
152 target: infoText
153 //: INFO ANDROID IOS
154 text: qsTr("Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.")
155 }
156 },
157 State {
158 when: RemoteServiceModel.running && knownDeviceList.count > 0
159
160 PropertyChanges {
161 target: infoText
162 //: INFO ANDROID IOS
163 text: qsTr("Paired devices may use this Smartphone as a card reader now.")
164 }
165 },
166 State {
167 when: RemoteServiceModel.running
168
169 PropertyChanges {
170 target: infoText
171 //: INFO ANDROID IOS
172 text: qsTr("Waiting for connection from a paired device...")
173 }
174 }
175 ]
176 }
177 ColumnLayout {
178 id: knownDevices
179 Layout.alignment: Qt.AlignLeft
180 Layout.fillWidth: true
181 Layout.topMargin: Constants.pane_padding
182 spacing: Constants.text_spacing
183 visible: RemoteServiceModel.runnable && knownDeviceList.count > 0
184
185 GText {
186 //: INFO ANDROID IOS
187 text: qsTr("Paired Devices")
188 textStyle: Style.text.header
189 }
190 Repeater {
191 id: knownDeviceList
192 model: RemoteServiceModel.allDevices
193
194 delegate: DevicesListDelegate {
195 highlightTitle: isLastAddedDevice
196 linkQualityVisible: false
197 title: remoteDeviceName
198 }
199 }
200 GButton {
201 //: LABEL ANDROID IOS
202 Accessible.name: qsTr("Start pairing of a new device")
203 Layout.alignment: Qt.AlignLeft
204 Layout.topMargin: knownDevices.spacing
205 buttonColor: Style.color.transparent
206 icon.source: "qrc:///images/material_add.svg"
207 padding: 0
208 //: LABEL ANDROID IOS
209 text: qsTr("Pair new device")
210 textStyle: Style.text.normal_accent_highlight
211 visible: !RemoteServiceModel.isPairing && !RemoteServiceModel.running
212
213 onClicked: RemoteServiceModel.setRunning(!RemoteServiceModel.running, !RemoteServiceModel.isPairing)
214 }
147215 }
148216 GText {
149217 id: pairingCode
160228 textStyle: Style.text.title_accent
161229 visible: false
162230 }
231 MoreInformationLink {
232 id: paringCodeLink
233 Layout.alignment: Qt.AlignCenter
234 Layout.topMargin: Constants.component_spacing
235 //: LABEL ANDROID IOS
236 text: qsTr("Where do I enter the pairing code?")
237 visible: false
238
239 onClicked: push(pairingCodeInfoView)
240
241 Component {
242 id: pairingCodeInfoView
243 PairingCodeInfoView {
244 text: paringCodeLink.text
245
246 onNavActionClicked: pop()
247 }
248 }
249 }
163250 GSpacer {
164251 Layout.fillHeight: true
165252 }
166 RowLayout {
253 RemoteServiceWifiInfo {
167254 id: wifiInfo
168255 Layout.fillWidth: true
169256 Layout.topMargin: Constants.component_spacing
170 spacing: Constants.text_spacing
171
172 TintableIcon {
173 source: "qrc:/images/info.svg"
174 sourceSize.width: Style.dimens.small_icon_size
175 tintColor: Style.text.normal_secondary.textColor
176 }
177 GText {
178 Layout.fillWidth: true
179
180 //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.
181 text: qsTr("Both of your devices have to be connected to the same WiFi.")
182 textStyle: Style.text.normal_secondary
183 }
184257 }
185258 LocalNetworkInfo {
186259 id: networkPermissionText
187260 Layout.bottomMargin: Constants.text_spacing
188261 Layout.fillWidth: true
189262 Layout.topMargin: Constants.component_spacing
190 visible: false
263 visible: RemoteServiceModel.requiresLocalNetworkPermission
264 }
265 GProgressBar {
266 id: progressBar
267 Layout.fillWidth: true
268 Layout.topMargin: Constants.component_spacing
269 value: RemoteServiceModel.percentage
270 visible: progressText.visible
271 }
272 GText {
273 id: progressText
274 Layout.alignment: Qt.AlignHCenter
275 Layout.topMargin: Constants.text_spacing
276 text: RemoteServiceModel.displayText
277 textStyle: Style.text.normal_secondary
278 visible: text !== ""
191279 }
192280 GButton {
193 id: startButton
194
195 readonly property int minButtonWidth: Math.max(Math.max(pairingButton.implicitWidth, startButton.implicitWidth), parent.width / 2)
196
281 id: pairConnectButton
197282 Layout.alignment: Qt.AlignHCenter
198 Layout.minimumWidth: startButton.minButtonWidth
199 Layout.topMargin: Constants.component_spacing
200 buttonColor: (!ApplicationModel.wifiEnabled || RemoteServiceModel.canEnableNfc) ? Style.color.button : (RemoteServiceModel.running ? Constants.red : Constants.green)
201 enabled: (RemoteServiceModel.canEnableNfc || RemoteServiceModel.runnable || RemoteServiceModel.running || !ApplicationModel.wifiEnabled) && !RemoteServiceModel.isStarting
202 //: LABEL ANDROID IOS
203 text: !ApplicationModel.wifiEnabled ? qsTr("Enable WiFi") :
204 //: LABEL ANDROID IOS
205 RemoteServiceModel.canEnableNfc ? qsTr("Enable NFC") :
206 //: LABEL ANDROID IOS
207 RemoteServiceModel.running ? qsTr("Stop remote service") :
208 //: LABEL ANDROID IOS
209 qsTr("Start remote service")
210
211 onClicked: {
212 if (!ApplicationModel.wifiEnabled) {
213 ApplicationModel.enableWifi();
214 } else if (RemoteServiceModel.canEnableNfc) {
215 ApplicationModel.showSettings(ApplicationModel.SETTING_NFC);
216 } else {
217 RemoteServiceModel.setRunning(!RemoteServiceModel.running);
218 }
219 }
220 }
221 GButton {
222 id: pairingButton
223
224 property bool didPairInSaKSession: false
225
226 Layout.alignment: Qt.AlignHCenter
227 Layout.minimumWidth: startButton.minButtonWidth
228 Layout.topMargin: Constants.component_spacing
229 enabled: RemoteServiceModel.runnable && !RemoteServiceModel.connectedToPairedDevice && !RemoteServiceModel.isStarting && !didPairInSaKSession
230
231 // Set opacity instead of visibility to hide button so it keeps its size
232 opacity: RemoteServiceModel.connectedToPairedDevice || didPairInSaKSession ? 0 : 1
233 text: RemoteServiceModel.isPairing ?
234 //: LABEL ANDROID IOS
235 qsTr("Stop pairing") :
236 //: LABEL ANDROID IOS
237 qsTr("Start pairing")
238 visible: RemoteServiceModel.runnable
283 Layout.topMargin: Constants.component_spacing
284 enabled: !RemoteServiceModel.isStarting
285 visible: text !== ""
286
287 states: [
288 State {
289 when: !ApplicationModel.wifiEnabled
290
291 PropertyChanges {
292 target: pairConnectButton
293 //: LABEL ANDROID IOS
294 text: qsTr("Enable WiFi")
295
296 onClicked: ApplicationModel.enableWifi()
297 }
298 },
299 State {
300 when: RemoteServiceModel.canEnableNfc
301
302 PropertyChanges {
303 target: pairConnectButton
304 //: LABEL ANDROID IOS
305 text: qsTr("Enable NFC")
306
307 onClicked: ApplicationModel.showSettings(ApplicationModel.SETTING_NFC)
308 }
309 },
310 State {
311 when: RemoteServiceModel.runnable && knownDeviceList.count > 0 && !RemoteServiceModel.isPairing && !RemoteServiceModel.running
312
313 PropertyChanges {
314 buttonColor: Constants.green
315 target: pairConnectButton
316 //: LABEL ANDROID IOS
317 text: qsTr("Allow connection")
318
319 onClicked: RemoteServiceModel.setRunning(true)
320 }
321 },
322 State {
323 when: RemoteServiceModel.runnable && knownDeviceList.count < 1 && !RemoteServiceModel.isPairing
324
325 PropertyChanges {
326 target: pairConnectButton
327 //: LABEL ANDROID IOS
328 text: qsTr("Pair device")
329
330 onClicked: RemoteServiceModel.setRunning(true, true)
331 }
332 },
333 State {
334 when: RemoteServiceModel.isPairing
335
336 PropertyChanges {
337 target: pairConnectButton
338 //: LABEL ANDROID IOS
339 text: qsTr("Cancel pairing")
340 visible: true
341
342 onClicked: RemoteServiceModel.setRunning(false, false)
343 }
344 }
345 ]
239346
240347 onClicked: RemoteServiceModel.setRunning(true, !RemoteServiceModel.isPairing)
241348 }
3232
3333 Column {
3434 spacing: Constants.component_spacing
35 visible: availablePairedDeviceList.count > 0
3536 width: parent.usableWidth
3637
3738 TitledSeparator {
4243 title: qsTr("Paired devices")
4344 width: parent.width
4445 }
45 GText {
46 Accessible.name: text
47 Accessible.role: Accessible.StaticText
48
49 //: LABEL ANDROID IOS
50 text: qsTr("No device is paired.")
51 textStyle: Style.text.normal_secondary
52 visible: !knownDeviceList.visible
53 width: parent.width
54 }
5546 ListView {
56 id: knownDeviceList
47 id: availablePairedDeviceList
5748 height: childrenRect.height
5849 interactive: false
59 model: RemoteServiceModel.knownDevices
50 model: RemoteServiceModel.availablePairedDevices
6051 spacing: Constants.component_spacing
61 visible: count > 0
52 width: parent.width
53
54 delegate: DevicesListDelegate {
55 //: LABEL ANDROID IOS
56 description: qsTr("Available")
57 linkInactive: !isNetworkVisible
58 linkQuality: linkQualityInPercent
59 title: remoteDeviceName
60 width: availablePairedDeviceList.width
61
62 onClicked: {
63 deleteDevicePopup.deviceId = deviceId;
64 deleteDevicePopup.deviceName = remoteDeviceName;
65 deleteDevicePopup.open();
66 }
67 }
68 }
69 }
70 Column {
71 spacing: Constants.component_spacing
72 visible: unavailablePairedDeviceList.count > 0
73 width: parent.usableWidth
74
75 TitledSeparator {
76 contentMarginBottom: 0
77 contentMarginLeft: 0
78 contentMarginRight: 0
79 //: LABEL ANDROID IOS
80 title: qsTr("Last connected")
81 width: parent.width
82 }
83 ListView {
84 id: unavailablePairedDeviceList
85 height: childrenRect.height
86 interactive: false
87 model: RemoteServiceModel.unavailablePairedDevices
88 spacing: Constants.component_spacing
6289 width: parent.width
6390
6491 delegate: DevicesListDelegate {
6794 linkInactive: !isNetworkVisible
6895 linkQuality: linkQualityInPercent
6996 title: remoteDeviceName
70 width: knownDeviceList.width
97 width: unavailablePairedDeviceList.width
7198
7299 onClicked: {
73100 deleteDevicePopup.deviceId = deviceId;
101128 contentMarginBottom: 0
102129 contentMarginLeft: 0
103130 contentMarginRight: 0
104
105 //: LABEL ANDROID IOS
106 title: qsTr("Available devices")
107 width: parent.width
108 }
109 GText {
110 text: ApplicationModel.wifiEnabled ?
111 //: INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network.
112 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.") :
113 //: INFO ANDROID IOS Wifi is not enabled and no new devices can be paired.
114 qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).")
115 textStyle: ApplicationModel.wifiEnabled ? Style.text.normal_secondary : Style.text.normal_warning
116 visible: !searchDeviceList.visible
117 width: parent.width
118 }
119 GButton {
120 anchors.horizontalCenter: parent.horizontalCenter
121
122 //: LABEL ANDROID IOS
123 text: qsTr("Enable WiFi")
124 visible: !ApplicationModel.wifiEnabled
125
126 onClicked: ApplicationModel.enableWifi()
127 }
128 LocalNetworkInfo {
129 topPadding: Constants.component_spacing
130 visible: RemoteServiceModel.requiresLocalNetworkPermission && !RemoteServiceModel.remoteReaderVisible
131 width: parent.width
132 }
133 ListView {
131 //: LABEL ANDROID IOS
132 title: qsTr("Add pairing")
133 width: parent.width
134 }
135 GListView {
134136 id: searchDeviceList
135137 height: childrenRect.height
136 interactive: false
137 model: RemoteServiceModel.availableRemoteDevices
138 model: RemoteServiceModel.availableDevicesInPairingMode
138139 spacing: Constants.component_spacing
139140 visible: ApplicationModel.wifiEnabled && count > 0
140141 width: parent.width
148149
149150 onClicked: {
150151 if (isSupported && RemoteServiceModel.rememberServer(deviceId)) {
151 informationPairingPopup.open();
152 d.oldLockedAndHiddenStatus = getLockedAndHidden();
153 setLockedAndHidden();
154 push(enterPinView);
152155 }
153156 }
154157 }
155158 }
156 }
157 }
158 ConfirmationPopup {
159 id: informationPairingPopup
160 style: ConfirmationPopup.PopupStyle.OkButton
161 //: INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone.
162 text: qsTr("Start the pairing mode on your smartphone if you haven't done it already.")
163 //: INFO ANDROID IOS
164 title: qsTr("Pairing mode")
165
166 onConfirmed: {
167 d.oldLockedAndHiddenStatus = getLockedAndHidden();
168 setLockedAndHidden();
169 push(enterPinView);
159 GText {
160 //: INFO ANDROID IOS Wifi is not enabled and no new devices can be paired.
161 text: qsTr("Please connect your WiFi to use another smartphone as card reader (SaC).")
162 textStyle: Style.text.normal_warning
163 visible: !ApplicationModel.wifiEnabled
164 width: parent.width
165 }
166 GButton {
167 anchors.horizontalCenter: parent.horizontalCenter
168
169 //: LABEL ANDROID IOS
170 text: qsTr("Enable WiFi")
171 visible: !ApplicationModel.wifiEnabled
172
173 onClicked: ApplicationModel.enableWifi()
174 }
175 LocalNetworkInfo {
176 topPadding: Constants.component_spacing
177 visible: RemoteServiceModel.requiresLocalNetworkPermission && !RemoteServiceModel.remoteReaderVisible
178 width: parent.width
179 }
180 PairingProcessInfo {
181 visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled
182 width: parent.width
183 }
184 RemoteServiceWifiInfo {
185 visible: !searchDeviceList.visible && ApplicationModel.wifiEnabled
186 width: parent.width
187 }
170188 }
171189 }
172190 PasswordInfoData {
0 import QtQuick 2.15
1 import QtQuick.Layouts 1.15
2 import Governikus.Global 1.0
3 import Governikus.Style 1.0
4
5 RowLayout {
6 spacing: Constants.text_spacing
7
8 TintableIcon {
9 source: "qrc:/images/info.svg"
10 sourceSize.width: Style.dimens.small_icon_size
11 tintColor: Style.text.normal_secondary.textColor
12 }
13 GText {
14 Layout.fillWidth: true
15
16 //: INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.
17 text: qsTr("Both devices have to be connected to the same WiFi.")
18 textStyle: Style.text.normal_secondary
19 }
20 }
22 */
33 import QtQuick 2.15
44 import QtQuick.Controls 2.15
5 import Governikus.AuthView 1.0
56 import Governikus.EnterPasswordView 1.0
67 import Governikus.PasswordInfoView 1.0
8 import Governikus.Style 1.0
79 import Governikus.TitleBar 1.0
810 import Governikus.View 1.0
11 import Governikus.Workflow 1.0
12 import Governikus.Type.ChatModel 1.0
913 import Governikus.Type.NumberModel 1.0
1014 import Governikus.Type.PasswordType 1.0
1115 import Governikus.Type.ReaderPlugIn 1.0
1216 import Governikus.Type.RemoteServiceModel 1.0
17 import Governikus.Type.SettingsModel 1.0
1318
1419 Controller {
1520 id: controller
21
22 readonly property bool enterPasswordShown: stackView.currentItem instanceof EnterPasswordView
23 readonly property bool workflowShown: stackView.currentItem instanceof GeneralWorkflow
24
25 function requestCard() {
26 if (RemoteServiceModel.hasCard && workflowShown) {
27 pop();
28 } else if (!RemoteServiceModel.hasCard && !workflowShown) {
29 push(generalWorkflow);
30 }
31 }
1632 function requestInput(pState) {
1733 if (RemoteServiceModel.isBasicReader && RemoteServiceModel.pinPadModeOn()) {
1834 push(enterPinView);
2238 }
2339
2440 Connections {
41 function onFireConnectedChanged() {
42 if (RemoteServiceModel.connectedToPairedDevice && !workflowShown) {
43 RemoteServiceModel.setInitialPluginType();
44 requestCard();
45 } else if (!RemoteServiceModel.connectedToPairedDevice && workflowShown) {
46 pop();
47 }
48 }
2549 function onFireCurrentStateChanged() {
2650 switch (RemoteServiceModel.currentState) {
2751 case "Initial":
3155 RemoteServiceModel.continueWorkflow();
3256 break;
3357 case "StateEnterPacePasswordIfd":
34 requestInput();
58 if (SettingsModel.showAccessRights) {
59 push(editRights);
60 } else {
61 requestInput();
62 }
63 break;
64 case "StateEstablishPaceChannelIfd":
65 case "StateChangePinIfd":
66 requestCard();
67 RemoteServiceModel.continueWorkflow();
3568 break;
3669 case "StateEnterNewPacePinIfd":
3770 requestInput();
4477 RemoteServiceModel.continueWorkflow();
4578 }
4679 }
80 function onFireHasCardChanged() {
81 if (!RemoteServiceModel.connectedToPairedDevice) {
82 return;
83 }
84 if (enterPasswordShown) {
85 return;
86 }
87 requestCard();
88 }
4789
4890 target: RemoteServiceModel
91 }
92 Component {
93 id: editRights
94 EditRights {
95 //: LABEL ANDROID IOS
96 actionText: qsTr("You are about to identify yourself towards the following provider using the device \"%1\":").arg(RemoteServiceModel.connectedClientName)
97 //: LABEL ANDROID IOS
98 title: qsTr("Card reader")
99 workflowModel: RemoteServiceModel
100
101 navigationAction: NavigationAction {
102 action: NavigationAction.Action.Cancel
103
104 onClicked: {
105 pop();
106 RemoteServiceModel.cancelPasswordRequest();
107 }
108 }
109
110 onRightsAccepted: {
111 ChatModel.transferAccessRights();
112 pop();
113 requestInput();
114 }
115 }
116 }
117 Component {
118 id: generalWorkflow
119 GeneralWorkflow {
120 titleBarColor: RemoteServiceModel.readerPlugInType === ReaderPlugIn.SMART ? Style.color.accent_smart : Style.color.accent
121 workflowModel: RemoteServiceModel
122 //: LABEL ANDROID IOS
123 workflowTitle: qsTr("Remote service")
124
125 navigationAction: NavigationAction {
126 action: NavigationAction.Action.Cancel
127
128 onClicked: {
129 RemoteServiceModel.setRunning(false);
130 }
131 }
132 }
49133 }
50134 PasswordInfoData {
51135 id: infoData
69153 id: passwordView
70154 enableTransportPinLink: RemoteServiceModel.enableTransportPinLink
71155 moreInformationText: infoData.linkText
156 //: LABEL ANDROID IOS
157 title: qsTr("Card reader")
72158
73159 navigationAction: NavigationAction {
74160 action: NavigationAction.Action.Cancel
84170 }
85171 onPasswordEntered: {
86172 pop();
173 RemoteServiceModel.startScanExplicitly();
87174 RemoteServiceModel.continueWorkflow();
88175 }
89176 onRequestPasswordInfo: push(passwordInfoView)
1010 SectionPage {
1111 id: rootPage
1212 //: LABEL ANDROID IOS
13 title: qsTr("Configure remote service")
13 title: qsTr("Manage pairings")
1414
1515 content: RemoteServiceViewRemote {
1616 width: rootPage.width
00 module RemoteServiceView
11
22 internal DevicesListDelegate DevicesListDelegate.qml
3 internal PairingCodeInfoView PairingCodeInfoView.qml
4 internal PairingProcessInfo PairingProcessInfo.qml
35 internal RemoteServiceController RemoteServiceController.qml
46 internal RemoteServiceViewRemote RemoteServiceViewRemote.qml
7 internal RemoteServiceWifiInfo RemoteServiceWifiInfo.qml
58
69 LinkQuality 1.0 LinkQuality.qml
710 LocalNetworkInfo 1.0 LocalNetworkInfo.qml
2424 property alias header: resultHeader.text
2525 property alias hintButtonText: hintItem.buttonText
2626 property alias hintText: hintItem.text
27 property alias mailButtonVisible: mailButton.visible
2728 property alias popupText: detailedResultPopup.text
2829 property alias popupTitle: detailedResultPopup.title
2930 property int resultType: ResultView.Type.IsSuccess
30 property alias supportButtonsVisible: supportButtonsLayout.visible
3131 property alias text: resultText.text
3232
3333 signal emailButtonPressed
8787 }
8888 }
8989 RowLayout {
90 id: supportButtonsLayout
9190 Layout.alignment: Qt.AlignHCenter
9291 Layout.fillWidth: true
9392 spacing: Constants.component_spacing
94 visible: false
93 visible: popupTitle !== "" || popupText !== ""
9594
9695 GButton {
96 id: mailButton
9797 icon.source: "qrc:///images/material_mail.svg"
9898 //: LABEL DESKTOP
9999 text: qsTr("Send email")
100100 tintIcon: true
101 visible: false
101102
102103 onClicked: baseItem.emailButtonPressed()
103104 }
126127 }
127128 }
128129 GButton {
129 icon.source: "qrc:/images/info.svg"
130 icon.source: "qrc:/images/desktop/info_white.svg"
130131 //: LABEL DESKTOP
131132 text: qsTr("See details")
132133 tintIcon: true
109109 pairingFailedView.errorMessage = pErrorMessage;
110110 d.view = ConnectSacView.SubView.PairingFailed;
111111 }
112 function onFirePairingSuccess(pDeviceName) {
113 ApplicationModel.showFeedback(qsTr("The device \"%1\" has been paired.").arg(pDeviceName));
112 function onFirePairingSuccess() {
114113 root.closeView();
115114 }
116115
4949 }
5050 GText {
5151 id: subtext
52 text: {
53 if (!isPaired) {
54 return qsTr("Click to pair");
55 }
56 return remoteDeviceStatus;
57 }
52 text: remoteDeviceStatus
5853 textStyle: Style.text.normal
5954 width: parent.width
6055 }
7469 source: "qrc:///images/material_delete.svg"
7570 sourceSize.height: iconHeight
7671 tintColor: Style.color.accent
77 visible: isPaired
72 visible: isPaired && !isPairing
7873
7974 MouseArea {
8075 id: trashMouse
9893 MouseArea {
9994 anchors.fill: parent
10095 cursorShape: Qt.PointingHandCursor
101 visible: !isPaired
96 visible: !trashMouse.visible
10297
10398 onClicked: pairDevice(deviceId)
10499 }
55 import Governikus.Global 1.0
66 import Governikus.Style 1.0
77 import Governikus.TitleBar 1.0
8 import Governikus.Type.ApplicationModel 1.0
89 import Governikus.Type.NumberModel 1.0
910 import Governikus.Type.RemoteServiceModel 1.0
1011 import Governikus.Type.ReaderScanEnabler 1.0
1617
1718 readonly property string helpTopic: "settingsRemoteReader"
1819
19 signal moreInformation
2020 signal pairDevice(string pDeviceId)
2121 signal unpairDevice(string pDeviceId)
2222
3131 anchors.fill: parent
3232 spacing: Constants.component_spacing
3333
34 GText {
35 activeFocusOnTab: true
36 text: qsTr("Paired remote devices")
37 textStyle: Style.text.header_accent
38 visible: knownDevices.count > 0
34 Column {
35 spacing: Constants.component_spacing
36 visible: availablePairedDevices.count > 0
3937 width: parent.width
4038
41 FocusFrame {
39 GText {
40 activeFocusOnTab: true
41 text: qsTr("Paired devices")
42 textStyle: Style.text.header_accent
43 width: parent.width
44
45 FocusFrame {
46 }
47 }
48 Repeater {
49 id: availablePairedDevices
50 model: RemoteServiceModel.availablePairedDevices
51
52 delegate: RemoteReaderDelegate {
53 width: parent.width
54
55 onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId)
56 }
4257 }
4358 }
4459 Column {
60 spacing: Constants.component_spacing
61 visible: unavailablePairedDevices.count > 0
4562 width: parent.width
4663
64 GText {
65 activeFocusOnTab: true
66 text: qsTr("Last connected")
67 textStyle: Style.text.header_accent
68 width: parent.width
69
70 FocusFrame {
71 }
72 }
4773 Repeater {
48 id: knownDevices
49 model: RemoteServiceModel.knownDevices
74 id: unavailablePairedDevices
75 model: RemoteServiceModel.unavailablePairedDevices
5076
5177 delegate: RemoteReaderDelegate {
52 height: implicitHeight + Constants.pane_padding
5378 width: parent.width
5479
5580 onUnpairDevice: pDeviceId => root.unpairDevice(pDeviceId)
5782 }
5883 }
5984 GSeparator {
60 visible: knownDevices.count > 0
85 visible: availablePairedDevices.count > 0 || unavailablePairedDevices.count > 0
6186 width: parent.width
6287 }
6388 GText {
6489 activeFocusOnTab: true
65 text: qsTr("Available remote devices")
90 text: qsTr("Add pairing")
6691 textStyle: Style.text.header_accent
6792 width: parent.width
6893
7297 GListView {
7398 id: availableDevices
7499 height: contentHeight
75 model: RemoteServiceModel.availableRemoteDevices
100 model: RemoteServiceModel.availableDevicesInPairingMode
76101 width: parent.width
77102
78103 delegate: RemoteReaderDelegate {
82107 onPairDevice: pDeviceId => root.pairDevice(pDeviceId)
83108 }
84109 }
85 GText {
86 activeFocusOnTab: true
87 text: RemoteServiceModel.availableRemoteDevices.emptyListDescriptionString
88 textStyle: Style.text.normal
110 Column {
111 spacing: Constants.text_spacing
89112 visible: availableDevices.count === 0
90113 width: parent.width
91114
92 FocusFrame {
115 Repeater {
116 model: [
117 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.
118 qsTr("Ensure that the %1 on your Smartphone as card reader has at least version %2.").arg(Qt.application.name).arg(Qt.application.version),
119 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.
120 qsTr("Open the %1 on your Smartphone as card reader.").arg(Qt.application.name),
121 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font
122 qsTr("On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.").arg("<b>").arg("</b>"),
123 //: LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4
124 qsTr("Choose the device in the list to pair it.")]
125
126 RowLayout {
127 spacing: Constants.component_spacing
128 width: parent.width
129
130 GText {
131 Accessible.ignored: true
132 Layout.alignment: Qt.AlignTop
133 text: (index + 1) + "."
134 }
135 GText {
136 Accessible.name: (index + 1) + ". " + ApplicationModel.stripHtmlTags(modelData)
137 Layout.alignment: Qt.AlignTop
138 Layout.fillWidth: true
139 activeFocusOnTab: true
140 text: modelData
141
142 FocusFrame {
143 }
144 }
145 }
93146 }
94147 }
95 GSeparator {
96 width: parent.width
97 }
98148 RowLayout {
99 id: hint
100149 spacing: Constants.text_spacing
150 visible: availableDevices.count === 0
101151 width: parent.width
102152
103153 TintableIcon {
106156 tintColor: Style.color.accent
107157 }
108158 GText {
109 id: hintText
110159 Layout.alignment: Qt.AlignVCenter
111160 Layout.fillWidth: true
112161 activeFocusOnTab: true
113 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.")
162 text: qsTr("Both devices have to be connected to the same WiFi.")
114163 textStyle: Style.text.hint
115164 verticalAlignment: Text.AlignBottom
116165 wrapMode: Text.WordWrap
119168 }
120169 }
121170 }
122 GButton {
123 //: LABEL DESKTOP
124 text: qsTr("More information")
125
126 onClicked: moreInformation()
127 }
128171 }
129172 }
8282 }
8383 GSeparator {
8484 Layout.fillWidth: true
85 visible: SettingsModel.autoUpdateAvailable
8586 }
8687 GText {
8788 activeFocusOnTab: true
8990 //: LABEL DESKTOP
9091 text: qsTr("Software updates")
9192 textStyle: Style.text.header_accent
93 visible: SettingsModel.autoUpdateAvailable
9294
9395 FocusFrame {
9496 }
9597 }
9698 GCheckBox {
9799 checked: SettingsModel.autoUpdateCheck
98 enabled: !SettingsModel.autoUpdateCheckSetByAdmin && SettingsModel.autoUpdateAvailable
100 enabled: !SettingsModel.autoUpdateCheckSetByAdmin
99101
100102 //: LABEL DESKTOP
101103 text: qsTr("Check at program start")
104 visible: SettingsModel.autoUpdateAvailable
102105
103106 onCheckedChanged: SettingsModel.autoUpdateCheck = checked
104107 }
108111
109112 Layout.fillWidth: true
110113 spacing: Constants.component_spacing
114 visible: SettingsModel.autoUpdateAvailable
111115
112116 GButton {
113 enabled: SettingsModel.autoUpdateAvailable
114117 text: (parent.updateAvailable ?
115118 //: LABEL DESKTOP
116119 qsTr("Show update") :
9696 height: Math.max(implicitHeight, tabbedPane.availableHeight)
9797 width: parent.width
9898
99 onMoreInformation: {
100 d.precedingView = d.view;
101 d.view = TabbedReaderView.SubView.ConnectSacView;
102 connectSacView.showPairingInformation();
103 updateTitleBarActions();
104 }
10599 onPairDevice: pDeviceId => {
106100 if (RemoteServiceModel.rememberServer(pDeviceId)) {
107101 d.view = SettingsView.SubView.ConnectSacView;
6565 height: Math.max(implicitHeight, tabbedPane.availableHeight)
6666 width: parent.width
6767
68 onMoreInformation: {
69 d.precedingView = d.view;
70 d.view = TabbedReaderView.SubView.ConnectSacView;
71 connectSacView.showPairingInformation();
72 updateTitleBarActions();
73 }
7468 onPairDevice: pDeviceId => {
7569 if (RemoteServiceModel.rememberServer(pDeviceId)) {
7670 d.view = TabbedReaderView.SubView.ConnectSacView;
135135
136136 onCheckedChanged: SettingsModel.pinPadMode = checked
137137 }
138 LabeledSwitch {
139 checked: SettingsModel.showAccessRights
140 //: LABEL ANDROID IOS
141 description: qsTr("Show requested rights on this device as well")
142 enabled: SettingsModel.pinPadMode
143
144 //: LABEL ANDROID IOS
145 title: qsTr("Show access rights")
146 width: parent.width
147
148 onCheckedChanged: SettingsModel.showAccessRights = checked
149 }
138150 MenuItem {
139151 //: LABEL ANDROID IOS
140 description: qsTr("Configure remote service for another device")
141
142 //: LABEL ANDROID IOS
143 title: qsTr("Remote card reader")
152 description: qsTr("Manage paired devices and add new devices")
153
154 //: LABEL ANDROID IOS
155 title: qsTr("Manage pairings")
144156 width: parent.width
145157
146158 onClicked: push(remoteServiceSettings)
395407 }
396408 }
397409 }
398 navigationAction: NavigationAction {
399 action: topLevelPage ? NavigationAction.Action.None : NavigationAction.Action.Back
400
401 onClicked: pop()
402 }
403410 }
1111 import Governikus.WhiteListClient 1.0
1212 import Governikus.Workflow 1.0
1313 import Governikus.Type.ConnectivityManager 1.0
14 import Governikus.Type.ChatModel 1.0
1415 import Governikus.Type.NumberModel 1.0
1516 import Governikus.Type.PasswordType 1.0
1617 import Governikus.Type.PersonalizationModel 1.0
268269 title: qsTr("Set up Smart-eID")
269270 titleBarColor: Style.color.accent_smart
270271 workflowModel: PersonalizationModel
272
273 onRightsAccepted: {
274 ChatModel.transferAccessRights();
275 PersonalizationModel.continueWorkflow();
276 }
271277 }
272278 }
273279 Component {
33 import QtQml 2.15
44 import Governikus.Global 1.0
55 import Governikus.Type.SettingsModel 1.0
6 import QtQuick.Window 2.15
67
78 BrandDimensions {
89 readonly property int button_radius: 6
910 readonly property int corner_radius: 10
10 readonly property int header_icon_size: Constants.is_tablet ? 240 : huge_icon_size
11 readonly property int header_icon_size: Constants.is_tablet ? Math.min(Screen.height / 5, 240) : huge_icon_size
1112 readonly property int high_contrast_item_border: 0
1213 readonly property int huge_icon_size: 160
1314 readonly property int icon_size: 48
3233 readonly property int tutorial_component_spacing: 40
3334 readonly property int tutorial_header_font_size: 26
3435 readonly property int tutorial_title_font_size: 60
36 readonly property int workflow_progress_indicator_size: 1.5 * header_icon_size
3537 }
9999 readonly property var normal_accent: TextStyle {
100100 textColor: Style.color.accent_text
101101 }
102 readonly property var normal_accent_highlight: TextStyle {
103 bold: true
104 textColor: Style.color.accent_text
105 }
102106 readonly property var normal_highlight: TextStyle {
103107 bold: true
104108 }
2323 GFlickableColumnLayout {
2424 anchors.fill: parent
2525 spacing: 0
26 topMargin: 0
2627
2728 GText {
2829 id: title
162162 id: settingsButton
163163 Accessible.description: qsTr("Open settings view of %1").arg(Qt.application.name)
164164 height: rightTitleBarActions.height
165 source: "qrc:///images/material_settings.svg"
165 source: "qrc:///images/desktop/material_settings_white.svg"
166166 text: qsTr("Settings")
167167 visible: rightMostAction.showSettings
168168
172172 id: helpButton
173173 Accessible.description: qsTr("Open online help of %1 in browser").arg(Qt.application.name)
174174 height: rightTitleBarActions.height
175 source: "qrc:///images/desktop/material_menu_book.svg"
175 source: "qrc:///images/desktop/material_menu_book_white.svg"
176176 text: qsTr("Open online help in browser")
177177 visible: rightMostAction.showHelp
178178
200200 horizontalAlignment: Text.AlignHCenter
201201
202202 //: LABEL ANDROID IOS
203 text: qsTr("Now choose \"Remote\" in the AusweisApp2 on your smartphone...")
203 text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...")
204204 textStyle: Style.text.tutorial_header
205205 width: parent.width * 0.9
206206
239239 animationsDisabled: true
240240
241241 //: LABEL ANDROID IOS
242 text: qsTr("Start pairing")
242 text: qsTr("Pair device")
243243
244244 Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction()
245245 Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction()
193193 horizontalAlignment: Text.AlignHCenter
194194
195195 //: LABEL ANDROID IOS
196 text: qsTr("Now choose \"Remote\" in the AusweisApp2 on your smartphone...")
196 text: qsTr("Now choose \"Card reader\" in the AusweisApp2 on your smartphone...")
197197 textStyle: Style.text.tutorial_header
198198 width: parent.width * 0.9
199199
232232 animationsDisabled: true
233233
234234 //: LABEL ANDROID IOS
235 text: qsTr("Start pairing")
235 text: qsTr("Pair device")
236236
237237 Accessible.onScrollDownAction: baseItem.Accessible.scrollDownAction()
238238 Accessible.onScrollUpAction: baseItem.Accessible.scrollUpAction()
342342 horizontalAlignment: Text.AlignHCenter
343343 text: (Constants.is_layout_ios ?
344344 //: LABEL IOS
345 qsTr("Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Configure remote service</b>.") :
345 qsTr("Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Manage pairings</b>.") :
346346 //: LABEL ANDROID
347347 qsTr("Now open the AusweisApp2 on your device <b>without</b> NFC and select <b>Smartphone as card reader</b>."))
348348 textStyle: Style.text.tutorial_header
2424 property color titleBarColor: Style.color.accent
2525 property real titleBarOpacity: 1
2626 property bool titleBarVisible: true
27 readonly property bool topLevelPage: StackView.index === 0
2827
2928 signal reset
3029
1818 property bool isPinChange: false
1919 property int waitingFor: 0
2020
21 signal deviceUnpaired(var pDeviceName)
2122 signal settingsRequested
2223
2324 onWaitingForChanged: if (visible)
3233 }
3334 Connections {
3435 function onFireCertificateRemoved(pDeviceName) {
35 //: 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.
36 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));
36 deviceUnpaired(pDeviceName);
3737 }
3838
3939 target: RemoteServiceModel
+0
-28
resources/qml/Governikus/Workflow/+mobile/BusyImageIndicator.qml less more
0 /**
1 * Copyright (c) 2015-2023 Governikus GmbH & Co. KG, Germany
2 */
3 import QtQuick 2.15
4 import QtQuick.Controls 2.15
5 import Governikus.Global 1.0
6
7 Item {
8 property string image
9 property alias running: busyIndicator.running
10
11 GBusyIndicator {
12 id: busyIndicator
13 anchors.centerIn: parent
14 factor: 1.2
15 height: img.height
16 running: false
17 width: height
18 }
19 Image {
20 id: img
21 anchors.centerIn: parent
22 fillMode: Image.PreserveAspectFit
23 smooth: true
24 source: image
25 width: parent.width
26 }
27 }
55 import Governikus.TechnologyInfo 1.0
66 import Governikus.TitleBar 1.0
77 import Governikus.Workflow 1.0
8 import Governikus.ResultView 1.0
89 import Governikus.View 1.0
910 import Governikus.Type.ReaderPlugIn 1.0
1011
2223 onClicked: workflowModel.cancelWorkflow()
2324 }
2425
25 NfcWorkflow {
26 visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC
27
28 onStartScanIfNecessary: workflowModel.startScanIfNecessary()
29
26 Item {
3027 anchors {
31 bottom: technologySwitch.top
28 bottom: technologySwitch.visible ? technologySwitch.top : parent.bottom
3229 left: parent.left
3330 right: parent.right
3431 top: parent.top
3532 }
36 }
37 SmartWorkflow {
38 visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART
39 workflowModel: baseItem.workflowModel
33 NfcWorkflow {
34 anchors.fill: parent
35 visible: workflowModel.readerPlugInType === ReaderPlugIn.NFC
4036
41 anchors {
42 bottom: technologySwitch.top
43 left: parent.left
44 right: parent.right
45 top: parent.top
37 onStartScanIfNecessary: workflowModel.startScanExplicitly()
4638 }
47 }
48 RemoteWorkflow {
49 visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC
39 SmartWorkflow {
40 anchors.fill: parent
41 visible: workflowModel.readerPlugInType === ReaderPlugIn.SMART
42 workflowModel: baseItem.workflowModel
43 }
44 RemoteWorkflow {
45 anchors.fill: parent
46 visible: workflowModel.readerPlugInType === ReaderPlugIn.REMOTE_IFD || workflowModel.readerPlugInType === ReaderPlugIn.PCSC
5047
51 anchors {
52 bottom: technologySwitch.top
53 left: parent.left
54 right: parent.right
55 top: parent.top
48 onDeviceUnpaired: function (pDeviceName) {
49 push(deviceUnpairedView, {
50 "deviceName": pDeviceName
51 });
52 }
53
54 Component {
55 id: deviceUnpairedView
56 ResultView {
57 property string deviceName
58
59 resultType: ResultView.Type.IsError
60 //: 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.
61 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)
62 title: workflowTitle
63
64 onCancelClicked: pop()
65 onContinueClicked: pop()
66 }
67 }
5668 }
57 }
58 SimulatorWorkflow {
59 visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR
60 workflowModel: baseItem.workflowModel
61
62 anchors {
63 bottom: technologySwitch.top
64 left: parent.left
65 right: parent.right
66 top: parent.top
69 SimulatorWorkflow {
70 anchors.fill: parent
71 visible: workflowModel.readerPlugInType === ReaderPlugIn.SIMULATOR
72 workflowModel: baseItem.workflowModel
6773 }
6874 }
6975 TechnologySwitch {
7076 id: technologySwitch
7177 selectedTechnology: workflowModel.readerPlugInType
7278 supportedTechnologies: workflowModel.supportedPlugInTypes
79 visible: workflowModel.supportedPlugInTypes.length > 1
7380
7481 onRequestPluginType: pReaderPlugInType => workflowModel.readerPlugInType = pReaderPlugInType
7582
1212 property real animateOutDuration: 0.2 * cardPositionModel.cyclingClock
1313 property var cardPosition: null
1414 property bool startPositionLeft: true
15
16 height: Style.dimens.workflow_progress_indicator_size
1517
1618 states: [
1719 State {
155157 anchors.centerIn: parent
156158 clip: true
157159 desaturate: true
158 height: Math.ceil(parent.height * 0.25) * 2
159160 opacity: tintEnabled ? 0.7 : 1.0
160161 source: "qrc:///images/mobile/phone_nfc.svg"
162 sourceSize.height: Style.dimens.header_icon_size
161163 z: 0
162164
163165 Image {
77 import Governikus.Type.ApplicationModel 1.0
88 import Governikus.Type.ReaderPlugIn 1.0
99 import Governikus.Type.NumberModel 1.0
10 import Governikus.Type.RemoteServiceModel 1.0
1011
1112 Item {
1213 id: baseItem
1314
15 readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE
1416 readonly property int nfcState: visible ? ApplicationModel.nfcState : ApplicationModel.NFC_UNAVAILABLE
1517
1618 signal startScanIfNecessary
2123 anchors.left: parent.left
2224 anchors.right: parent.right
2325 anchors.top: parent.top
24 height: baseItem.height / 2
2526 state: nfcState === ApplicationModel.NFC_READY ? "on" : "off"
2627 }
2728 TechnologyInfo {
5152 //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.
5253 qsTr("Please enable NFC in your system settings.");
5354 case ApplicationModel.NFC_INACTIVE:
54 //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.
55 //: INFO ANDROID IOS NFC is available and enabled but needs to be started.
5556 return qsTr("NFC scan is not running.") + "<br/>" +
56 //: INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.
57 //: INFO ANDROID IOS NFC is available and enabled but needs to be started.
5758 qsTr("Please start the NFC scan.");
5859 default:
5960 return "";
7576 }
7677 }
7778 titleText: {
79 if (isRemoteWorkflow && RemoteServiceModel.connectedClientName !== "") {
80 //: INFO ANDROID IOS %1 will be replaced with the name of the device.
81 return qsTr("The device \"%1\" wants to use this smartphone as card reader and connect to your id card.").arg(RemoteServiceModel.connectedClientName);
82 }
7883 switch (nfcState) {
7984 case ApplicationModel.NFC_UNAVAILABLE:
8085 //: INFO ANDROID IOS
+0
-54
resources/qml/Governikus/Workflow/+mobile/ProgressIndicator.qml less more
0 /**
1 * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany
2 */
3 import QtQuick 2.15
4 import Governikus.Global 1.0
5
6 Item {
7 id: baseItem
8
9 property alias imageIconSource: busyIcon.image
10 property alias imagePhoneSource: phone.source
11
12 TintableIcon {
13 id: phone
14 anchors.centerIn: parent
15 desaturate: true
16 height: parent.height * 0.5
17 opacity: tintEnabled ? 0.7 : 1.0
18 visible: baseItem.state === "off"
19 width: height
20 }
21 Item {
22 id: currentAction
23 anchors.bottom: pCircle.top
24 anchors.left: parent.left
25 anchors.margins: Constants.component_spacing
26 anchors.right: parent.right
27 anchors.top: parent.top
28
29 BusyImageIndicator {
30 id: busyIcon
31 anchors.centerIn: parent
32 height: Math.min(parent.height - 40, 2 * pCircle.height)
33 running: visible
34 visible: baseItem.state === "one"
35 width: height
36 }
37 CardReader {
38 anchors.centerIn: parent
39 cardAnimation: baseItem.state === "two"
40 height: parent.height
41 pinFieldAnimation: false
42 visible: baseItem.state === "two"
43 }
44 }
45 ProgressCircle {
46 id: pCircle
47 anchors.bottom: parent.bottom
48 anchors.left: parent.left
49 anchors.right: parent.right
50 state: baseItem.state
51 visible: baseItem.state === "one" || baseItem.state === "two"
52 }
53 }
0 /**
1 * Copyright (c) 2017-2023 Governikus GmbH & Co. KG, Germany
2 */
3 import QtQuick 2.15
4 import Governikus.Global 1.0
5 import Governikus.Style 1.0
6
7 Item {
8 id: baseItem
9
10 property bool foundSelectedReader: false
11
12 height: Style.dimens.workflow_progress_indicator_size
13
14 TintableIcon {
15 id: phone
16 anchors.centerIn: parent
17 desaturate: true
18 opacity: tintEnabled ? 0.7 : 1.0
19 source: "qrc:///images/mobile/phone_remote.svg"
20 sourceSize.height: Style.dimens.header_icon_size
21 visible: !baseItem.foundSelectedReader
22 }
23 Item {
24 id: currentAction
25 anchors.bottom: pCircle.top
26 anchors.left: parent.left
27 anchors.margins: Constants.component_spacing
28 anchors.right: parent.right
29 anchors.top: parent.top
30
31 CardReader {
32 anchors.centerIn: parent
33 height: parent.height
34 pinFieldAnimation: false
35 visible: baseItem.foundSelectedReader
36 }
37 }
38 ProgressCircle {
39 id: pCircle
40 anchors.bottom: parent.bottom
41 anchors.left: parent.left
42 anchors.right: parent.right
43 state: baseItem.foundSelectedReader ? "two" : "off"
44 visible: baseItem.foundSelectedReader
45 }
46 }
1717 property bool settingsPushed: remoteServiceSettings.visible
1818 property bool wifiEnabled: ApplicationModel.wifiEnabled
1919
20 signal deviceUnpaired(var pDeviceName)
21
2022 onFoundSelectedReaderChanged: {
2123 if (baseItem.settingsPushed && foundSelectedReader) {
2224 remoteServiceSettings.pop();
2527
2628 Connections {
2729 function onFireCertificateRemoved(pDeviceName) {
28 //: 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.
29 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));
30 deviceUnpaired(pDeviceName);
3031 }
3132
3233 target: RemoteServiceModel
3334 }
34 ProgressIndicator {
35 RemoteProgressIndicator {
3536 id: progressIndicator
3637 Accessible.ignored: true
3738 anchors.left: parent.left
3839 anchors.right: parent.right
3940 anchors.top: parent.top
40 height: parent.height / 2
41 imageIconSource: "qrc:///images/mobile/icon_remote.svg"
42 imagePhoneSource: "qrc:///images/mobile/phone_remote.svg"
43 state: foundSelectedReader ? "two" : "off"
41 foundSelectedReader: baseItem.foundSelectedReader
4442 }
4543 TechnologyInfo {
4644 id: techInfo
5048 return qsTr("Enable WiFi");
5149 } else if (!foundSelectedReader) {
5250 //: LABEL ANDROID IOS
53 return qsTr("Pair device");
51 return qsTr("Manage pairings");
5452 } else {
5553 return "";
5654 }
6159 return qsTr("To use the remote service WiFi has to be activated. Please activate WiFi in your device settings.");
6260 } else if (!foundSelectedReader) {
6361 //: INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.
64 return qsTr("No paired smartphone as card reader (SaC) with activated \"remote service\" available.");
62 return qsTr("Allow a connection on a paired smartphone or pair a new smartphone.");
6563 } else {
6664 return "";
6765 }
8684 return qsTr("Wifi disabled");
8785 } else if (!foundSelectedReader) {
8886 //: LABEL ANDROID IOS
89 return qsTr("Waiting for connection");
87 return qsTr("No smartphone as card reader connected");
9088 } else {
9189 //: LABEL ANDROID IOS
9290 return qsTr("Determine card");
33 import QtQuick 2.15
44 import Governikus.Global 1.0
55 import Governikus.TechnologyInfo 1.0
6 import Governikus.Style 1.0
67
78 Item {
89 id: baseItem
1112
1213 Item {
1314 id: progressIndicator
14 height: parent.height / 2
15 height: Style.dimens.workflow_progress_indicator_size
1516
1617 anchors {
1718 left: parent.left
2223 id: icon
2324 anchors.centerIn: parent
2425 desaturate: true
25 height: Math.ceil(parent.height * 0.25) * 2
2626 source: "qrc:///images/mobile/phone_simulator.svg"
27 sourceSize.height: Style.dimens.header_icon_size
2728 tintEnabled: false
2829 }
2930 }
22 */
33 import QtQuick 2.15
44 import Governikus.Global 1.0
5 import Governikus.Style 1.0
56
67 Item {
78 id: baseItem
89
910 property alias disabled: icon.tintEnabled
1011
12 height: Style.dimens.workflow_progress_indicator_size
13
1114 TintableIcon {
1215 id: icon
1316 anchors.centerIn: parent
1417 desaturate: true
15 height: Math.ceil(parent.height * 0.25) * 2
1618 opacity: tintEnabled ? 0.7 : 1.0
1719 source: "qrc:///images/mobile/phone_smart.svg"
20 sourceSize.height: Style.dimens.header_icon_size
1821 }
1922 }
33 import QtQuick 2.15
44 import Governikus.Global 1.0
55 import Governikus.TechnologyInfo 1.0
6 import Governikus.Type.ApplicationModel 1.0
67 import Governikus.Type.SmartModel 1.0
78 import Governikus.Type.NumberModel 1.0
89 import Governikus.Type.PersonalizationModel 1.0
1112 id: baseItem
1213
1314 readonly property bool canUseSmart: smartState === SmartModel.SMART_READY && isSmartCardAllowed && SmartModel.isScanRunning
15 readonly property bool isRemoteWorkflow: ApplicationModel.currentWorkflow === ApplicationModel.WORKFLOW_REMOTE_SERVICE
1416 readonly property bool isSmartCardAllowed: workflowModel.isSmartCardAllowed
1517 readonly property int smartState: SmartModel.smartState
1618 property var workflowModel
1921 id: progressIndicator
2022 Accessible.ignored: true
2123 disabled: !canUseSmart
22 height: parent.height / 2
2324
2425 anchors {
2526 left: parent.left
5455 }
5556 return "";
5657 default:
58 if (isRemoteWorkflow) {
59 //: LABEL ANDROID IOS
60 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.");
61 }
5762 //: LABEL ANDROID IOS
5863 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.");
5964 }
00 module Workflow
11
2 internal BusyImageIndicator BusyImageIndicator.qml
32 internal CardReader CardReader.qml
43 internal NfcProgressIndicator NfcProgressIndicator.qml
54 internal ProgressCircle ProgressCircle.qml
6 internal ProgressIndicator ProgressIndicator.qml
5 internal RemoteProgressIndicator RemoteProgressIndicator.qml
76 internal RemoteWorkflow RemoteWorkflow.qml
87 internal SmartProgressIndicator SmartProgressIndicator.qml
98 internal TextCircle TextCircle.qml
44 <name>DvcsAttributes</name>
55 <message>
66 <source>revision</source>
7 <translation>efee4b38a0c7</translation>
7 <translation>b9ade3b30f3d</translation>
88 </message>
99 </context>
1010 <context>
177177 <source>Do you know your six-digit ID card PIN?</source>
178178 <translation>Kennen Sie Ihre sechsstellige Karten-PIN?</translation>
179179 </message>
180 <message>
181 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
182 <extracomment>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.</extracomment>
183 <translation>Das Gerät &quot;%1&quot; wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden.</translation>
184 </message>
180185 </context>
181186 <context>
182187 <name>BaseConfirmationPopup</name>
495500 <extracomment>INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card.</extracomment>
496501 <translation>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.</translation>
497502 </message>
503 <message>
504 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
505 <extracomment>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.</extracomment>
506 <translation>Das Gerät &quot;%1&quot; wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden.</translation>
507 </message>
498508 </context>
499509 <context>
500510 <name>ChangePinViewContent</name>
984994 <translation>Das Gerät wird gekoppelt ...</translation>
985995 </message>
986996 <message>
987 <source>The device &quot;%1&quot; has been paired.</source>
988 <translation>Das Gerät &quot;%1&quot; wurde gekoppelt.</translation>
989 </message>
990 <message>
991997 <source>Pairing to &quot;%1&quot; failed:</source>
992998 <extracomment>ERROR DESKTOP An error occurred while pairing the device.</extracomment>
993999 <translation>Die Kopplung mit &quot;%1&quot; ist fehlgeschlagen:</translation>
14681474 <translation>Bitte wiederholen Sie die Eingabe Ihrer neuen sechsstelligen Karten-PIN.</translation>
14691475 </message>
14701476 <message>
1471 <source>Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC).</source>
1472 <extracomment>INFO DESKTOP The pairing code needs to be supplied.</extracomment>
1473 <translation>Starten Sie die Kopplung auf Ihrem Smartphone und geben Sie den dort angezeigten Kopplungscode ein um Ihr Smartphone als Kartenleser (SaK) zu verwenden.</translation>
1474 </message>
1475 <message>
14761477 <source>Unknown password type:</source>
14771478 <extracomment>INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error.</extracomment>
14781479 <translation>Unbekannter Passwort-Typ:</translation>
16111612 LABEL ANDROID IOS</extracomment>
16121613 <translation>Karten-PIN senden</translation>
16131614 </message>
1615 <message>
1616 <source>Enter the pairing code shown on your smartphone.</source>
1617 <extracomment>INFO DESKTOP The pairing code needs to be supplied.</extracomment>
1618 <translation>Geben Sie den Kopplungscode ein, der auf Ihrem Smartphone angezeigt wird.</translation>
1619 </message>
16141620 </context>
16151621 <context>
16161622 <name>GProgressBar</name>
16851691 <context>
16861692 <name>GeneralWorkflow</name>
16871693 <message>
1688 <source>The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
1689 <extracomment>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.</extracomment>
1690 <translation>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.</translation>
1691 </message>
1692 <message>
16931694 <source>Attempts</source>
16941695 <extracomment>LABEL DESKTOP</extracomment>
16951696 <translation>Versuche</translation>
17521753 <extracomment>INFO DESKTOP</extracomment>
17531754 <translation>Zu den Einstellungen</translation>
17541755 </message>
1756 <message>
1757 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
1758 <extracomment>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.</extracomment>
1759 <translation>Das Gerät &quot;%1&quot; wurde entkoppelt, da es nicht auf Verbindungsversuche reagiert hat. Koppeln Sie das Gerät erneut, um es wieder als Kartenleser zu verwenden.</translation>
1760 </message>
17551761 </context>
17561762 <context>
17571763 <name>Hint</name>
17641770 <name>HistoryListItem</name>
17651771 <message>
17661772 <source>Click to view details of history entry.</source>
1773 <extracomment>LABEL ANDROID IOS</extracomment>
17671774 <translation>Zeige Details des Verlaufseintrags.</translation>
1768 </message>
1769 <message>
1770 <source>today</source>
1771 <extracomment>LABEL ANDROID IOS</extracomment>
1772 <translation>heute</translation>
1773 </message>
1774 <message>
1775 <source>yesterday</source>
1776 <translation>gestern</translation>
1777 </message>
1778 <message>
1779 <source>dd.MM.yyyy</source>
1780 <translation>dd.MM.yyyy</translation>
17811775 </message>
17821776 <message>
17831777 <source>Tap for more details</source>
18591853 <translation>Im Verlauf suchen</translation>
18601854 </message>
18611855 <message>
1862 <source>today</source>
1863 <translation>heute</translation>
1864 </message>
1865 <message>
1866 <source>yesterday</source>
1867 <translation>gestern</translation>
1868 </message>
1869 <message>
1870 <source>dd.MM.yyyy</source>
1871 <translation>dd.MM.yyyy</translation>
1872 </message>
1873 <message>
18741856 <source>Clear history</source>
18751857 <extracomment>LABEL DESKTOP</extracomment>
18761858 <translation>Lösche Verlauf</translation>
19581940 </message>
19591941 <message>
19601942 <source>dd.MM.yyyy</source>
1943 <extracomment>LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString
1944 ----------
1945 LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
19611946 <translation>dd.MM.yyyy</translation>
19621947 </message>
19631948 <message>
20522037 <context>
20532038 <name>LocalNetworkInfo</name>
20542039 <message>
2055 <source>To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.</source>
2056 <extracomment>INFO IOS Let user know to check the application settings for local network permission</extracomment>
2057 <translation>Um Ihr Smartphone als Kartenleser (SaK) nutzen zu können, stellen Sie bitte sicher, dass der Zugriff auf das lokale Netzwerk erlaubt ist.</translation>
2058 </message>
2059 <message>
20602040 <source>Go to application settings</source>
20612041 <extracomment>INFO IOS Link to application settings</extracomment>
20622042 <translation>Zu den Anwendungseinstellungen</translation>
20632043 </message>
2044 <message>
2045 <source>Ensure that access to the local network is allowed in your settings.</source>
2046 <extracomment>INFO IOS Let user know to check the application settings for local network permission</extracomment>
2047 <translation>In den Einstellungen muss der Zugriff auf das lokale Netzwerk erlaubt sein.</translation>
2048 </message>
20642049 </context>
20652050 <context>
20662051 <name>LogTitleBarControls</name>
25762561 <translation>Anbieter</translation>
25772562 </message>
25782563 <message>
2579 <source>Remote</source>
2580 <translation>Fernzugriff</translation>
2581 </message>
2582 <message>
25832564 <source>Settings</source>
25842565 <translation>Einstellungen</translation>
25852566 </message>
25862567 <message>
25872568 <source>Help</source>
25882569 <translation>Hilfe</translation>
2570 </message>
2571 <message>
2572 <source>Card reader</source>
2573 <translation>Kartenleser</translation>
25892574 </message>
25902575 </context>
25912576 <context>
26222607 </message>
26232608 <message>
26242609 <source>NFC scan is not running.</source>
2625 <extracomment>INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.</extracomment>
2610 <extracomment>INFO ANDROID IOS NFC is available and enabled but needs to be started.</extracomment>
26262611 <translation>Der NFC-Scan ist nicht aktiv.</translation>
26272612 </message>
26282613 <message>
26292614 <source>Please start the NFC scan.</source>
2630 <extracomment>INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.</extracomment>
2615 <extracomment>INFO ANDROID IOS NFC is available and enabled but needs to be started.</extracomment>
26312616 <translation>Bitte starten Sie den NFC-Scan.</translation>
26322617 </message>
26332618 <message>
26652650 <extracomment>INFO ANDROID The ID card may be inserted, the authentication process may be started.</extracomment>
26662651 <translation>Bitte platzieren Sie Ihren Ausweis direkt an der Geräterückseite.&lt;br/&gt;&lt;br/&gt;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.</translation>
26672652 </message>
2653 <message>
2654 <source>The device &quot;%1&quot; wants to use this smartphone as card reader and connect to your id card.</source>
2655 <extracomment>INFO ANDROID IOS %1 will be replaced with the name of the device.</extracomment>
2656 <translation>Das Gerät &quot;%1&quot; möchte dieses Smartphone als Kartenleser nutzen und sich mit Ihrem Ausweis verbinden.</translation>
2657 </message>
26682658 </context>
26692659 <context>
26702660 <name>NumberField</name>
27272717 </message>
27282718 </context>
27292719 <context>
2720 <name>PairingCodeInfoView</name>
2721 <message>
2722 <source>Pairing Information</source>
2723 <extracomment>LABEL ANDROID IOS</extracomment>
2724 <translation>Informationen zur Kopplung</translation>
2725 </message>
2726 <message>
2727 <source>Open %1 on your %2other device%3.</source>
2728 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3</extracomment>
2729 <translation>Öffnen Sie auf Ihrem %2anderen Gerät%3 die %1.</translation>
2730 </message>
2731 <message>
2732 <source>On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.</source>
2733 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font.</extracomment>
2734 <translation>Gehen Sie dort in die %1Einstellungen%2 und dann zu %1Smartphone als Kartenleser%2 bzw. %1Kopplungen verwalten%2.</translation>
2735 </message>
2736 <message>
2737 <source>Choose this smartphone in the list to pair it.</source>
2738 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3</extracomment>
2739 <translation>Wählen Sie in der angezeigten Liste dieses Smartphone aus, um es zu koppeln.</translation>
2740 </message>
2741 </context>
2742 <context>
2743 <name>PairingProcessInfo</name>
2744 <message>
2745 <source>Open %1 on your smartphone as card reader.</source>
2746 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.</extracomment>
2747 <translation>Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser.</translation>
2748 </message>
2749 <message>
2750 <source>On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.</source>
2751 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font.</extracomment>
2752 <translation>Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2.</translation>
2753 </message>
2754 <message>
2755 <source>Choose the smartphone in the list shown here to pair it.</source>
2756 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4</extracomment>
2757 <translation>Klicken Sie zum Koppeln auf das hier angezeigte Gerät.</translation>
2758 </message>
2759 <message>
2760 <source>Ensure that the %1 on your Smartphone as card reader has at least version %2.</source>
2761 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.</extracomment>
2762 <translation>Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat.</translation>
2763 </message>
2764 </context>
2765 <context>
27302766 <name>PasswordInfoContent</name>
27312767 <message>
27322768 <source>More information</source>
33153351 <context>
33163352 <name>ProviderDetailHistoryItem</name>
33173353 <message>
3318 <source>today</source>
3319 <extracomment>LABEL ANDROID IOS</extracomment>
3320 <translation>heute</translation>
3321 </message>
3322 <message>
3323 <source>yesterday</source>
3324 <translation>gestern</translation>
3325 </message>
3326 <message>
3327 <source>dd.MM.yyyy</source>
3328 <translation>dd.MM.yyyy</translation>
3329 </message>
3330 <message>
33313354 <source>Service:</source>
33323355 <extracomment>LABEL DESKTOP</extracomment>
33333356 <translation>Dienst:</translation>
35903613 <translation>Drücken Sie die Leertaste um das Smartphone &quot;%1&quot; zu koppeln.</translation>
35913614 </message>
35923615 <message>
3593 <source>Click to pair</source>
3594 <translation>Klicken zum Koppeln</translation>
3595 </message>
3596 <message>
35973616 <source>Remove remote device</source>
35983617 <translation>Entferne das Gerät</translation>
35993618 </message>
36013620 <context>
36023621 <name>RemoteReaderView</name>
36033622 <message>
3604 <source>Paired remote devices</source>
3605 <translation>Gekoppelte Netzwerkgeräte</translation>
3606 </message>
3607 <message>
3608 <source>Available remote devices</source>
3609 <translation>Verfügbare Netzwerkgeräte</translation>
3610 </message>
3611 <message>
3612 <source>Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here.</source>
3613 <translation>Nur Geräte die bereits gekoppelt wurden, oder sich mit aktiviertem Fernzugriff im selben WLAN-Netz befinden, werden hier angezeigt.</translation>
3614 </message>
3615 <message>
3616 <source>More information</source>
3617 <extracomment>LABEL DESKTOP</extracomment>
3618 <translation>Mehr Informationen</translation>
3623 <source>Paired devices</source>
3624 <translation>Gekoppelte Geräte</translation>
3625 </message>
3626 <message>
3627 <source>Add pairing</source>
3628 <translation>Kopplung hinzufügen</translation>
3629 </message>
3630 <message>
3631 <source>Open the %1 on your Smartphone as card reader.</source>
3632 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.</extracomment>
3633 <translation>Öffnen Sie die %1 auf Ihrem Smartphone als Kartenleser.</translation>
3634 </message>
3635 <message>
3636 <source>Both devices have to be connected to the same WiFi.</source>
3637 <translation>Beide Geräte müssen mit demselben WLAN verbunden sein.</translation>
3638 </message>
3639 <message>
3640 <source>On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.</source>
3641 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font</extracomment>
3642 <translation>Wählen Sie dort unter %1Kartenleser%2 die Option %1Gerät koppeln%2 bzw. %1Neues Gerät koppeln%2.</translation>
3643 </message>
3644 <message>
3645 <source>Choose the device in the list to pair it.</source>
3646 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4</extracomment>
3647 <translation>Klicken Sie zum Koppeln auf das hier angezeigte Gerät.</translation>
3648 </message>
3649 <message>
3650 <source>Last connected</source>
3651 <translation>Zuletzt verbunden</translation>
3652 </message>
3653 <message>
3654 <source>Ensure that the %1 on your Smartphone as card reader has at least version %2.</source>
3655 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.</extracomment>
3656 <translation>Stellen Sie sicher, dass die %1 auf Ihrem Smartphone als Kartenleser mindestens die Version %2 hat.</translation>
3657 </message>
3658 </context>
3659 <context>
3660 <name>RemoteServiceController</name>
3661 <message>
3662 <source>You are about to identify yourself towards the following provider using the device &quot;%1&quot;:</source>
3663 <extracomment>LABEL ANDROID IOS</extracomment>
3664 <translation>Sie möchten sich mit dem Gerät %1 bei folgendem Anbieter ausweisen:</translation>
3665 </message>
3666 <message>
3667 <source>Card reader</source>
3668 <extracomment>LABEL ANDROID IOS</extracomment>
3669 <translation>Kartenleser</translation>
3670 </message>
3671 <message>
3672 <source>Remote service</source>
3673 <extracomment>LABEL ANDROID IOS</extracomment>
3674 <translation>Fernzugriff</translation>
36193675 </message>
36203676 </context>
36213677 <context>
36223678 <name>RemoteServiceSettings</name>
36233679 <message>
3624 <source>Configure remote service</source>
3625 <extracomment>LABEL ANDROID IOS</extracomment>
3626 <translation>Fernzugriff konfigurieren</translation>
3680 <source>Manage pairings</source>
3681 <extracomment>LABEL ANDROID IOS</extracomment>
3682 <translation>Kopplungen verwalten</translation>
36273683 </message>
36283684 </context>
36293685 <context>
36303686 <name>RemoteServiceView</name>
3631 <message>
3632 <source>Remote service</source>
3633 <extracomment>LABEL ANDROID IOS</extracomment>
3634 <translation>Fernzugriff</translation>
3635 </message>
36363687 <message>
36373688 <source>Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code.</source>
36383689 <extracomment>ERROR ANDROID IOS An error occurred while pairing the device.</extracomment>
36643715 <translation>Warte auf Verbindung</translation>
36653716 </message>
36663717 <message>
3667 <source>Remote service ready</source>
3668 <extracomment>LABEL ANDROID IOS</extracomment>
3669 <translation>Fernzugriff startbereit</translation>
3670 </message>
3671 <message>
36723718 <source>Waiting for connection from a paired device...</source>
36733719 <extracomment>INFO ANDROID IOS</extracomment>
36743720 <translation>Warte auf eine Verbindung eines gekoppelten Gerätes...</translation>
36753721 </message>
36763722 <message>
3677 <source>Start the remote access in order to make this smartphone visible and use it as a card reader (SaC).
3723 <source>Pairing code: &lt;b&gt;%1&lt;/b&gt;</source>
3724 <extracomment>LABEL ANDROID IOS</extracomment>
3725 <translation>Kopplungscode: &lt;b&gt;%1&lt;/b&gt;</translation>
3726 </message>
3727 <message>
3728 <source>Enable WiFi</source>
3729 <extracomment>LABEL ANDROID IOS</extracomment>
3730 <translation>WLAN aktivieren</translation>
3731 </message>
3732 <message>
3733 <source>Enable NFC</source>
3734 <extracomment>LABEL ANDROID IOS</extracomment>
3735 <translation>NFC aktivieren</translation>
3736 </message>
3737 <message>
3738 <source>Pair device</source>
3739 <extracomment>LABEL ANDROID IOS</extracomment>
3740 <translation>Gerät koppeln</translation>
3741 </message>
3742 <message>
3743 <source>Allow connection</source>
3744 <extracomment>LABEL ANDROID IOS</extracomment>
3745 <translation>Verbindung erlauben</translation>
3746 </message>
3747 <message>
3748 <source>You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.
36783749
3679 If you have not already paired a device, start the pairing now to set up this smartphone as a card reader.</source>
3750 To do this you first have to pair that device with this smartphone.</source>
36803751 <extracomment>INFO ANDROID IOS</extracomment>
3681 <translation>Starten Sie den Fernzugriff, um dieses Smartphone sichtbar und damit als Kartenleser (SaK) nutzbar zu machen.
3752 <translation>Sie können dieses Smartphone als Kartenleser für die %1 auf einem anderen Gerät, z.B. Ihrem Laptop, nutzen.
36823753
3683 Falls Sie noch kein Gerät gekoppelt haben, starten Sie jetzt die Kopplung, um dieses Smartphone als Kartenleser einzurichten.</translation>
3684 </message>
3685 <message>
3686 <source>Pairing code: &lt;b&gt;%1&lt;/b&gt;</source>
3687 <extracomment>LABEL ANDROID IOS</extracomment>
3688 <translation>Kopplungscode: &lt;b&gt;%1&lt;/b&gt;</translation>
3689 </message>
3690 <message>
3691 <source>Both of your devices have to be connected to the same WiFi.</source>
3692 <extracomment>INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.</extracomment>
3693 <translation>Ihre beiden Geräte müssen mit dem selben WLAN-Netz verbunden sein.</translation>
3694 </message>
3695 <message>
3696 <source>Enable WiFi</source>
3697 <extracomment>LABEL ANDROID IOS</extracomment>
3698 <translation>WLAN aktivieren</translation>
3699 </message>
3700 <message>
3701 <source>Enable NFC</source>
3702 <extracomment>LABEL ANDROID IOS</extracomment>
3703 <translation>NFC aktivieren</translation>
3704 </message>
3705 <message>
3706 <source>Stop remote service</source>
3707 <extracomment>LABEL ANDROID IOS</extracomment>
3708 <translation>Fernzugriff stoppen</translation>
3709 </message>
3710 <message>
3711 <source>Start remote service</source>
3712 <extracomment>LABEL ANDROID IOS</extracomment>
3713 <translation>Fernzugriff starten</translation>
3714 </message>
3715 <message>
3716 <source>Stop pairing</source>
3717 <extracomment>LABEL ANDROID IOS</extracomment>
3718 <translation>Kopplung stoppen</translation>
3719 </message>
3720 <message>
3721 <source>Start pairing</source>
3722 <extracomment>LABEL ANDROID IOS</extracomment>
3723 <translation>Kopplung starten</translation>
3724 </message>
3725 <message>
3726 <source>Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC).</source>
3754 Hierfür müssen Sie zuvor das entsprechende Gerät mit diesem Smartphone koppeln.</translation>
3755 </message>
3756 <message>
3757 <source>Card reader</source>
3758 <extracomment>LABEL ANDROID IOS</extracomment>
3759 <translation>Kartenleser</translation>
3760 </message>
3761 <message>
3762 <source>Paired Devices</source>
37273763 <extracomment>INFO ANDROID IOS</extracomment>
3728 <translation>Geben Sie den Code %1 in der %2 auf Ihrem anderen Gerät ein, um Ihr Smartphone als Kartenleser (SaK) zu verwenden.</translation>
3764 <translation>Gekoppelte Geräte</translation>
3765 </message>
3766 <message>
3767 <source>Pair new device</source>
3768 <extracomment>LABEL ANDROID IOS</extracomment>
3769 <translation>Neues Gerät koppeln</translation>
3770 </message>
3771 <message>
3772 <source>Waiting for pairing</source>
3773 <extracomment>LABEL ANDROID IOS</extracomment>
3774 <translation>Warte auf Kopplung</translation>
3775 </message>
3776 <message>
3777 <source>Start pairing of a new device</source>
3778 <extracomment>LABEL ANDROID IOS</extracomment>
3779 <translation>Kopplung mit einem neuen Gerät starten.</translation>
3780 </message>
3781 <message>
3782 <source>Where do I enter the pairing code?</source>
3783 <extracomment>LABEL ANDROID IOS</extracomment>
3784 <translation>Wo gebe ich den Kopplungscode ein?</translation>
3785 </message>
3786 <message>
3787 <source>Enter the pairing code %1 in the %2 on your other device.</source>
3788 <extracomment>INFO ANDROID IOS</extracomment>
3789 <translation>Geben Sie den Kopplungscode %1 in der %2 auf Ihrem anderen Gerät ein.</translation>
3790 </message>
3791 <message>
3792 <source>Cancel pairing</source>
3793 <extracomment>LABEL ANDROID IOS</extracomment>
3794 <translation>Kopplung abbrechen</translation>
3795 </message>
3796 <message>
3797 <source>Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.</source>
3798 <extracomment>INFO ANDROID IOS</extracomment>
3799 <translation>Erlauben Sie eine Verbindung mit gekoppelten Geräten, um dieses Smartphone als Kartenleser zu nutzen oder koppeln Sie weitere Geräte.</translation>
3800 </message>
3801 <message>
3802 <source>Paired devices may use this Smartphone as a card reader now.</source>
3803 <extracomment>INFO ANDROID IOS</extracomment>
3804 <translation>Gekoppelte Geräte können dieses Smartphone jetzt als Kartenleser nutzen.</translation>
37293805 </message>
37303806 </context>
37313807 <context>
37323808 <name>RemoteServiceViewRemote</name>
3733 <message>
3734 <source>Paired devices</source>
3735 <extracomment>LABEL ANDROID IOS</extracomment>
3736 <translation>Gekoppelte Geräte</translation>
3737 </message>
3738 <message>
3739 <source>No device is paired.</source>
3740 <extracomment>LABEL ANDROID IOS</extracomment>
3741 <translation>Kein Gerät gekoppelt.</translation>
3742 </message>
3743 <message>
3744 <source>Click to remove device</source>
3745 <extracomment>LABEL ANDROID IOS</extracomment>
3746 <translation>Klicken, um das Gerät zu entfernen</translation>
3747 </message>
37483809 <message>
37493810 <source>Remove pairing</source>
37503811 <extracomment>INFO ANDROID IOS</extracomment>
37613822 <translation>Entfernen</translation>
37623823 </message>
37633824 <message>
3764 <source>Available devices</source>
3765 <extracomment>LABEL ANDROID IOS</extracomment>
3766 <translation>Verfügbare Geräte</translation>
3767 </message>
3768 <message>
3769 <source>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.</source>
3770 <extracomment>INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network.</extracomment>
3771 <translation>Kein ungekoppeltes Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion &quot;Fernzugriff&quot; in der AusweisApp2 auf Ihrem Smartphone aktiviert ist und beide Geräte mit demselben WLAN verbunden sind.</translation>
3772 </message>
3773 <message>
37743825 <source>Please connect your WiFi to use another smartphone as card reader (SaC).</source>
37753826 <extracomment>INFO ANDROID IOS Wifi is not enabled and no new devices can be paired.</extracomment>
37763827 <translation>Bitte verbinden Sie sich mit Ihrem WLAN, um ein anderes Smartphone als Kartenleser (SaK) benutzen zu können.</translation>
37813832 <translation>WLAN aktivieren</translation>
37823833 </message>
37833834 <message>
3835 <source>Pairing code</source>
3836 <extracomment>LABEL ANDROID IOS</extracomment>
3837 <translation>Kopplungscode</translation>
3838 </message>
3839 <message>
3840 <source>Add pairing</source>
3841 <extracomment>LABEL ANDROID IOS</extracomment>
3842 <translation>Kopplung hinzufügen</translation>
3843 </message>
3844 <message>
3845 <source>Click to remove device</source>
3846 <extracomment>LABEL ANDROID IOS</extracomment>
3847 <translation>Klicken, um das Gerät zu entfernen</translation>
3848 </message>
3849 <message>
3850 <source>Last connected</source>
3851 <extracomment>LABEL ANDROID IOS</extracomment>
3852 <translation>Zuletzt verbunden</translation>
3853 </message>
3854 <message>
3855 <source>Available</source>
3856 <extracomment>LABEL ANDROID IOS</extracomment>
3857 <translation>Verfügbar</translation>
3858 </message>
3859 <message>
3860 <source>Paired devices</source>
3861 <extracomment>LABEL ANDROID IOS</extracomment>
3862 <translation>Gekoppelte Geräte</translation>
3863 </message>
3864 <message>
37843865 <source>Click to pair</source>
37853866 <extracomment>LABEL ANDROID IOS</extracomment>
37863867 <translation>Klicken zum Koppeln</translation>
37873868 </message>
3788 <message>
3789 <source>Pairing mode</source>
3790 <extracomment>INFO ANDROID IOS</extracomment>
3791 <translation>Kopplungsmodus</translation>
3792 </message>
3793 <message>
3794 <source>Start the pairing mode on your smartphone if you haven&apos;t done it already.</source>
3795 <extracomment>INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone.</extracomment>
3796 <translation>Starten Sie den Kopplungsmodus auf Ihrem Smartphone, falls noch nicht geschehen.</translation>
3797 </message>
3798 <message>
3799 <source>Pairing code</source>
3800 <extracomment>LABEL ANDROID IOS</extracomment>
3801 <translation>Kopplungscode</translation>
3869 </context>
3870 <context>
3871 <name>RemoteServiceWifiInfo</name>
3872 <message>
3873 <source>Both devices have to be connected to the same WiFi.</source>
3874 <extracomment>INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.</extracomment>
3875 <translation>Beide Geräte müssen mit demselben WLAN verbunden sein.</translation>
38023876 </message>
38033877 </context>
38043878 <context>
38053879 <name>RemoteWorkflow</name>
38063880 <message>
3807 <source>The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
3808 <extracomment>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.</extracomment>
3809 <translation>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.</translation>
3810 </message>
3811 <message>
38123881 <source>Enable WiFi</source>
38133882 <extracomment>LABEL ANDROID IOS</extracomment>
38143883 <translation>WLAN aktivieren</translation>
3815 </message>
3816 <message>
3817 <source>Pair device</source>
3818 <extracomment>LABEL ANDROID IOS</extracomment>
3819 <translation>Gerät koppeln</translation>
38203884 </message>
38213885 <message>
38223886 <source>To use the remote service WiFi has to be activated. Please activate WiFi in your device settings.</source>
38243888 <translation>Um den Fernzugriff zu nutzen, muss WLAN aktiviert werden. Bitte aktivieren Sie WLAN in Ihren Einstellungen.</translation>
38253889 </message>
38263890 <message>
3827 <source>No paired smartphone as card reader (SaC) with activated &quot;remote service&quot; available.</source>
3828 <extracomment>INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.</extracomment>
3829 <translation>Kein gekoppeltes Smartphone als Kartenleser mit aktiviertem &quot;Fernzugriff&quot; verfügbar.</translation>
3830 </message>
3831 <message>
38323891 <source>Wifi disabled</source>
38333892 <extracomment>LABEL ANDROID IOS</extracomment>
38343893 <translation>WLAN ist deaktiviert</translation>
3835 </message>
3836 <message>
3837 <source>Waiting for connection</source>
3838 <extracomment>LABEL ANDROID IOS</extracomment>
3839 <translation>Warte auf Verbindung</translation>
38403894 </message>
38413895 <message>
38423896 <source>Determine card</source>
38533907 <extracomment>INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted.</extracomment>
38543908 <translation>Verbunden mit %1. Bitte platzieren Sie das Smartphone mit der NFC-Schnittstelle auf Ihrem Ausweis.</translation>
38553909 </message>
3910 <message>
3911 <source>Manage pairings</source>
3912 <extracomment>LABEL ANDROID IOS</extracomment>
3913 <translation>Kopplungen verwalten</translation>
3914 </message>
3915 <message>
3916 <source>No smartphone as card reader connected</source>
3917 <extracomment>LABEL ANDROID IOS</extracomment>
3918 <translation>Kein Smartphone als Kartenleser verbunden</translation>
3919 </message>
3920 <message>
3921 <source>Allow a connection on a paired smartphone or pair a new smartphone.</source>
3922 <extracomment>INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.</extracomment>
3923 <translation>Erlauben Sie die Verbindung auf einem bereits gekoppelten Smartphone oder koppeln Sie ein neues Smartphone.</translation>
3924 </message>
38563925 </context>
38573926 <context>
38583927 <name>ResultErrorView</name>
42484317 <translation>PIN-Eingabe auf diesem Gerät</translation>
42494318 </message>
42504319 <message>
4251 <source>Remote card reader</source>
4252 <extracomment>LABEL ANDROID IOS</extracomment>
4253 <translation>Smartphone als Kartenleser</translation>
4254 </message>
4255 <message>
4256 <source>Configure remote service for another device</source>
4257 <extracomment>LABEL ANDROID IOS</extracomment>
4258 <translation>Ein anderes Gerät für den Fernzugriff konfigurieren</translation>
4259 </message>
4260 <message>
42614320 <source>Save history</source>
42624321 <extracomment>LABEL ANDROID IOS</extracomment>
42634322 <translation>Verlauf speichern</translation>
43734432 <source>15 days old Logfile</source>
43744433 <extracomment>LABEL ALL_PLATFORMS</extracomment>
43754434 <translation>15 Tage alte Protokolldatei</translation>
4435 </message>
4436 <message>
4437 <source>Show requested rights on this device as well</source>
4438 <extracomment>LABEL ANDROID IOS</extracomment>
4439 <translation>Angefragte Berechtigung auch auf diesem Gerät anzeigen</translation>
4440 </message>
4441 <message>
4442 <source>Show access rights</source>
4443 <extracomment>LABEL ANDROID IOS</extracomment>
4444 <translation>Berechtigungsanzeige</translation>
4445 </message>
4446 <message>
4447 <source>Manage paired devices and add new devices</source>
4448 <extracomment>LABEL ANDROID IOS</extracomment>
4449 <translation>Gekoppelte Geräte verwalten und neue Geräte hinzufügen</translation>
4450 </message>
4451 <message>
4452 <source>Manage pairings</source>
4453 <extracomment>LABEL ANDROID IOS</extracomment>
4454 <translation>Kopplungen verwalten</translation>
43764455 </message>
43774456 </context>
43784457 <context>
47574836 <source>Continue</source>
47584837 <translation>Weiter</translation>
47594838 </message>
4839 <message>
4840 <source>You have not yet set up a Smart-eID or it is no longer usable.
4841
4842 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.</source>
4843 <extracomment>LABEL ANDROID IOS</extracomment>
4844 <translation>Sie haben noch keine Smart-eID eingerichtet oder diese ist nicht mehr nutzbar.
4845
4846 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.</translation>
4847 </message>
47604848 </context>
47614849 <context>
47624850 <name>StoreFeedbackPopup</name>
53245412 <translation>Beide Geräte müssen im selben WLAN sein</translation>
53255413 </message>
53265414 <message>
5327 <source>Now choose &quot;Remote&quot; in the AusweisApp2 on your smartphone...</source>
5328 <extracomment>LABEL ANDROID IOS</extracomment>
5329 <translation>Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht &quot;Fernzugriff&quot;...</translation>
5415 <source>Now choose &quot;Card reader&quot; in the AusweisApp2 on your smartphone...</source>
5416 <extracomment>LABEL ANDROID IOS</extracomment>
5417 <translation>Öffnen Sie nun in der AusweisApp2 auf dem Smartphone die Ansicht &quot;Kartenleser&quot;...</translation>
53305418 </message>
53315419 <message>
53325420 <source>Now</source>
53345422 <translation>Jetzt</translation>
53355423 </message>
53365424 <message>
5337 <source>Start pairing</source>
5338 <extracomment>LABEL ANDROID IOS</extracomment>
5339 <translation>Kopplung starten</translation>
5425 <source>Pair device</source>
5426 <extracomment>LABEL ANDROID IOS</extracomment>
5427 <translation>Gerät koppeln</translation>
53405428 </message>
53415429 <message>
53425430 <source>Pairing code</source>
54825570 <translation>Beide Geräte müssen im selben WLAN sein</translation>
54835571 </message>
54845572 <message>
5485 <source>Now choose &quot;Remote&quot; in the AusweisApp2 on your smartphone...</source>
5486 <extracomment>LABEL ANDROID IOS</extracomment>
5487 <translation>Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich &quot;Fernzugriff&quot;...</translation>
5573 <source>Now choose &quot;Card reader&quot; in the AusweisApp2 on your smartphone...</source>
5574 <extracomment>LABEL ANDROID IOS</extracomment>
5575 <translation>Öffnen Sie nun in der AusweisApp2 auf dem Smartphone den Bereich &quot;Kartenleser&quot;...</translation>
54885576 </message>
54895577 <message>
54905578 <source>Now</source>
54925580 <translation>Jetzt</translation>
54935581 </message>
54945582 <message>
5495 <source>Start pairing</source>
5496 <extracomment>LABEL ANDROID IOS</extracomment>
5497 <translation>Kopplung starten</translation>
5583 <source>Pair device</source>
5584 <extracomment>LABEL ANDROID IOS</extracomment>
5585 <translation>Gerät koppeln</translation>
54985586 </message>
54995587 <message>
55005588 <source>Pairing code</source>
55125600 <translation>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.</translation>
55135601 </message>
55145602 <message>
5515 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Configure remote service&lt;/b&gt;.</source>
5603 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Manage pairings&lt;/b&gt;.</source>
55165604 <extracomment>LABEL IOS</extracomment>
5517 <translation>Öffnen Sie nun die AusweisApp2 auf dem Gerät &lt;b&gt;ohne&lt;/b&gt; NFC und wählen Sie &lt;b&gt;Fernzugriff konfigurieren&lt;/b&gt; aus.</translation>
5605 <translation>Öffnen Sie nun die AusweisApp2 auf dem Gerät &lt;b&gt;ohne&lt;/b&gt; NFC und wählen Sie &lt;b&gt;Kopplungen verwalten&lt;/b&gt; aus.</translation>
55185606 </message>
55195607 <message>
55205608 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Smartphone as card reader&lt;/b&gt;.</source>
59226010 <source>Checksum link:</source>
59236011 <extracomment>LABEL DESKTOP Link to download checksum to verify the downloaded update file.</extracomment>
59246012 <translation>Link zur Prüfsumme:</translation>
6013 </message>
6014 </context>
6015 <context>
6016 <name>Utils</name>
6017 <message>
6018 <source>today</source>
6019 <extracomment>LABEL ALL_PLATFORMS</extracomment>
6020 <translation>heute</translation>
6021 </message>
6022 <message>
6023 <source>yesterday</source>
6024 <extracomment>LABEL ALL_PLATFORMS</extracomment>
6025 <translation>gestern</translation>
6026 </message>
6027 <message>
6028 <source>dd.MM.yyyy</source>
6029 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
6030 <translation>dd.MM.yyyy</translation>
59256031 </message>
59266032 </context>
59276033 <context>
63176423 </message>
63186424 <message>
63196425 <source>d. MMMM yyyy, hh:mm:ss AP</source>
6320 <extracomment>LABEL DESKTOP Timestamp, formatted according to the selected language</extracomment>
6426 <extracomment>LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
63216427 <translation>d. MMMM yyyy, HH:mm:ss &apos;Uhr&apos;</translation>
63226428 </message>
63236429 <message>
65276633 </message>
65286634 <message>
65296635 <source>dd.MM.yyyy, hh:mm:ss</source>
6530 <extracomment>LABEL DESKTOP Timestamp</extracomment>
6636 <extracomment>LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
65316637 <translation>dd.MM.yyyy, hh:mm:ss</translation>
65326638 </message>
65336639 <message>
67926898 <translation>Die Authentisierung ist fehlgeschlagen.</translation>
67936899 </message>
67946900 <message>
6795 <source>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.</source>
6796 <extracomment>ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length.</extracomment>
6797 <translation>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.</translation>
6901 <source>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.</source>
6902 <extracomment>ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length.</extracomment>
6903 <translation>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.</translation>
67986904 </message>
67996905 <message>
68006906 <source>No certificate description available.</source>
70947200 <name>governikus::HistoryModelSearchFilter</name>
70957201 <message>
70967202 <source>dd.MM.yyyy</source>
7203 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
70977204 <translation>dd.MM.yyyy</translation>
70987205 </message>
70997206 </context>
71467253 </message>
71477254 <message>
71487255 <source>dd.MM.yyyy hh:mm:ss</source>
7256 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
71497257 <translation>dd.MM.yyyy hh:mm:ss</translation>
71507258 </message>
71517259 <message>
72057313 <name>governikus::NotificationModel</name>
72067314 <message>
72077315 <source>hh:mm:ss</source>
7316 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
72087317 <translation>HH:mm:ss</translation>
72097318 </message>
72107319 </context>
72987407 </message>
72997408 <message>
73007409 <source>dd.MM.yyyy hh:mm AP</source>
7301 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7410 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
73027411 <translation>dd.MM.yyyy HH:mm</translation>
73037412 </message>
73047413 <message>
73237432 </message>
73247433 <message>
73257434 <source>dd.MM.yyyy</source>
7326 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7435 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
73277436 <translation>dd.MM.yyyy</translation>
73287437 </message>
73297438 <message>
73307439 <source>hh:mm AP</source>
7331 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7440 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
73327441 <translation>HH:mm</translation>
73337442 </message>
73347443 <message>
74747583 </message>
74757584 <message>
74767585 <source>hh:mm:ss AP</source>
7586 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
74777587 <translation>HH:mm:ss</translation>
74787588 </message>
74797589 <message>
75307640 <translation>Gekoppelt, aber nicht unterstützt</translation>
75317641 </message>
75327642 <message>
7533 <source>Paired, but unavailable</source>
7534 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7535 <translation>Gekoppelt, aber nicht verfügbar</translation>
7536 </message>
7537 <message>
75387643 <source>Unsupported</source>
75397644 <extracomment>LABEL ALL_PLATFORMS</extracomment>
75407645 <translation>Nicht unterstützt</translation>
75467651 </message>
75477652 <message>
75487653 <source>dd.MM.yyyy hh:mm AP</source>
7654 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
75497655 <translation>dd.MM.yyyy HH:mm</translation>
75507656 </message>
75517657 <message>
75577663 <source>No smartphone as card reader (Sac) available. Please make sure to activate the &quot;remote service&quot; on your smartphone and to connect both devices to the same WiFi. See %1 for details of use.</source>
75587664 <extracomment>INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network.</extracomment>
75597665 <translation>Kein Smartphone als Kartenleser verfügbar. Bitte stellen Sie sicher, dass die Funktion &quot;Fernzugriff&quot; 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.</translation>
7666 </message>
7667 <message>
7668 <source>Unavailable</source>
7669 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7670 <translation>Nicht verfügbar</translation>
7671 </message>
7672 <message>
7673 <source>Click to pair</source>
7674 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7675 <translation>Klicken zum Koppeln</translation>
75607676 </message>
75617677 </context>
75627678 <context>
75897705
75907706 Bitte aktivieren Sie NFC, um Ihr Smartphone als Kartenleser (SaK) benutzen zu können.</translation>
75917707 </message>
7708 <message>
7709 <source>Pairing with %1 successful.</source>
7710 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7711 <translation>Die Kopplung mit %1 war erfolgreich.</translation>
7712 </message>
75927713 </context>
75937714 <context>
75947715 <name>governikus::RemoteServiceSettings</name>
76127733 </message>
76137734 <message>
76147735 <source>dd.MM.yyyy</source>
7736 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
76157737 <translation>dd.MM.yyyy</translation>
76167738 </message>
76177739 <message>
76187740 <source>xx.MM.yyyy</source>
7741 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day</extracomment>
76197742 <translation>xx.MM.yyyy</translation>
76207743 </message>
76217744 <message>
76227745 <source>xx.xx.yyyy</source>
7746 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month</extracomment>
76237747 <translation>xx.xx.yyyy</translation>
76247748 </message>
76257749 <message>
77607884 <source>Access denied.</source>
77617885 <extracomment>INFO IOS The current session was interrupted because of a wrong password.</extracomment>
77627886 <translation>Zugriff verweigert.</translation>
7887 </message>
7888 </context>
7889 <context>
7890 <name>governikus::StateEstablishPaceChannel</name>
7891 <message>
7892 <source>The secure channel is opened</source>
7893 <extracomment>INFO ALL_PLATFORMS First status message after the PIN was entered.</extracomment>
7894 <translation>Der sichere Kanal wird geöffnet</translation>
77637895 </message>
77647896 </context>
77657897 <context>
44 <name>DvcsAttributes</name>
55 <message>
66 <source>revision</source>
7 <translation>efee4b38a0c7</translation>
7 <translation>b9ade3b30f3d</translation>
88 </message>
99 </context>
1010 <context>
177177 <source>Do you know your six-digit ID card PIN?</source>
178178 <translation>Вы знаете 6-значный PIN-код идентификационной карты?</translation>
179179 </message>
180 <message>
181 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
182 <extracomment>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.</extracomment>
183 <translation>Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт.</translation>
184 </message>
180185 </context>
181186 <context>
182187 <name>BaseConfirmationPopup</name>
495500 <extracomment>INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card.</extracomment>
496501 <translation>Вы трижды ввели неправильный 6-значный PIN-код идентификационной карты, PIN-код идентификационной карты заблокирован. Для разблокировки введите 10-значный PUK-код.</translation>
497502 </message>
503 <message>
504 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
505 <extracomment>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.</extracomment>
506 <translation>Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт.</translation>
507 </message>
498508 </context>
499509 <context>
500510 <name>ChangePinViewContent</name>
504514 <translation>Какой у вас PIN-код?</translation>
505515 </message>
506516 <message>
517 <source>Six-digit PIN</source>
518 <extracomment>LABEL ALL_PLATFORMS</extracomment>
519 <translation>6-значный PIN-код</translation>
520 </message>
521 <message>
507522 <source>Set by yourself</source>
508523 <extracomment>LABEL ALL_PLATFORMS</extracomment>
509524 <translation>Создается пользователем самостоятельно</translation>
510525 </message>
511526 <message>
527 <source>Five-digit Transport PIN</source>
528 <extracomment>LABEL ALL_PLATFORMS</extracomment>
529 <translation>5-значный временный PIN-код</translation>
530 </message>
531 <message>
512532 <source>Received by mail in PIN letter</source>
513533 <extracomment>LABEL ALL_PLATFORMS</extracomment>
514534 <translation>Получен по почте в письме с PIN-кодом</translation>
522542 <source>Lost, forgotten, or never received it</source>
523543 <extracomment>LABEL ALL_PLATFORMS</extracomment>
524544 <translation>Утерян, забыт или не получен вовсе</translation>
525 </message>
526 <message>
527 <source>Six-digit PIN</source>
528 <extracomment>LABEL ALL_PLATFORMS</extracomment>
529 <translation type="unfinished">6-значный PIN-код</translation>
530 </message>
531 <message>
532 <source>Five-digit Transport PIN</source>
533 <extracomment>LABEL ALL_PLATFORMS</extracomment>
534 <translation type="unfinished">5-значный временный PIN-код</translation>
535545 </message>
536546 </context>
537547 <context>
664674 <message>
665675 <source>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.&lt;br&gt;&lt;br&gt;You can find smartphones compatible with the %1 on our website.</source>
666676 <extracomment>LABEL ANDROID IOS</extracomment>
667 <translation>В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы также можете использовать другой смартфон в качестве устройства чтения карт для онлайн-идентификации.&lt;br&gt;&lt;br&gt;Список совместимых с %1 смартфонов см. на нашем сайте.</translation>
677 <translation>В вашем мобильном устройстве нет интерфейса NFC. Он требуется для считывания идентификационной карты. Вы можете воспользоваться функцией eID на другом смартфоне, используемом в качестве устройства чтения карт.&lt;br&gt;&lt;br&gt;Список совместимых с %1 смартфонов см. на нашем сайте.</translation>
668678 </message>
669679 <message>
670680 <source>Open website</source>
694704 <message>
695705 <source>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.&lt;br&gt;&lt;br&gt;You can find smartphones compatible with the %1 on our website.</source>
696706 <extracomment>LABEL ANDROID IOS</extracomment>
697 <translation>Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. %1 не имеет какого-либо влияния на это ограничение.&lt;br&gt;&lt;br&gt;Список совместимых с %1 смартфонов см. на нашем сайте.</translation>
707 <translation>Интерфейс NFC вашего мобильного устройства не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение.&lt;br&gt;&lt;br&gt;Список совместимых с %1 смартфонов см. на нашем сайте.</translation>
698708 </message>
699709 <message>
700710 <source>ID card access failed</source>
724734 <message>
725735 <source>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.&lt;br&gt;&lt;br&gt;You may now try the function: &quot;See my personal data&quot;. There you can also use the CAN to unblock the ID card PIN.</source>
726736 <extracomment>LABEL ANDROID IOS</extracomment>
727 <translation>PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он расположен внизу справа на передней стороне идентификационной карты.&lt;br&gt;&lt;br&gt;Теперь проверьте работу функции. «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты.</translation>
737 <translation>PIN-код идентификационной карты введен неправильно два раза подряд. Поэтому перед следующей попыткой идентификации необходимо ввести 6-значный код доступа (CAN). Он указан внизу справа на передней стороне вашей идентификационной карты.&lt;br&gt;&lt;br&gt;Проверьте функцию: «Просмотреть персональные данные». Вы также можете использовать код CAN для разблокировки PIN-кода идентификационной карты.</translation>
728738 </message>
729739 <message>
730740 <source>Continue</source>
739749 <message>
740750 <source>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.&lt;br&gt;&lt;br&gt;You may now try the function: &quot;See my personal data&quot;. Have your PUK ready to unlock the ID card PIN.</source>
741751 <extracomment>LABEL ANDROID IOS</extracomment>
742 <translation>PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.&lt;br&gt;&lt;br&gt;Теперь проверьте работу функции. «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты.</translation>
752 <translation>PIN-код идентификационной карты введен неправильно трижды. Поэтому при следующем процессе аутентификации сначала необходимо ввести 10-значный PUK-код. Он указан в письме с PIN-кодом, которое вы получили после заказа идентификационной карты.&lt;br&gt;&lt;br&gt;Проверьте функцию: «Просмотреть персональные данные». Подготовьте PUK-код для разблокировки PIN-кода идентификационной карты.</translation>
743753 </message>
744754 </context>
745755 <context>
984994 <translation>Сопряжение устройства…</translation>
985995 </message>
986996 <message>
987 <source>The device &quot;%1&quot; has been paired.</source>
988 <translation>Устройство «%1» сопряжено.</translation>
989 </message>
990 <message>
991997 <source>Pairing to &quot;%1&quot; failed:</source>
992998 <extracomment>ERROR DESKTOP An error occurred while pairing the device.</extracomment>
993999 <translation>Сбой сопряжения «%1»:</translation>
14681474 <translation>Подтвердите новый 6-значный PIN-код идентификационной карты.</translation>
14691475 </message>
14701476 <message>
1471 <source>Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC).</source>
1472 <extracomment>INFO DESKTOP The pairing code needs to be supplied.</extracomment>
1473 <translation>Запустите сопряжение на смартфоне и введите указанный в смартфоне код сопряжения для использования смартфона в качестве устройства чтения карт (SaC).</translation>
1474 </message>
1475 <message>
14761477 <source>Unknown password type:</source>
14771478 <extracomment>INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error.</extracomment>
14781479 <translation>Неизвестный тип пароля:</translation>
16111612 LABEL ANDROID IOS</extracomment>
16121613 <translation>Отправить PIN-код идентификационной карты</translation>
16131614 </message>
1615 <message>
1616 <source>Enter the pairing code shown on your smartphone.</source>
1617 <extracomment>INFO DESKTOP The pairing code needs to be supplied.</extracomment>
1618 <translation>Введите указанный в смартфоне код сопряжения.</translation>
1619 </message>
16141620 </context>
16151621 <context>
16161622 <name>GProgressBar</name>
16851691 <context>
16861692 <name>GeneralWorkflow</name>
16871693 <message>
1688 <source>The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
1689 <extracomment>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.</extracomment>
1690 <translation>Сопряжение устройства %1 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт.</translation>
1691 </message>
1692 <message>
16931694 <source>Attempts</source>
16941695 <extracomment>LABEL DESKTOP</extracomment>
16951696 <translation>Попытки</translation>
17521753 <extracomment>INFO DESKTOP</extracomment>
17531754 <translation>Перейти к настройкам устройства чтения карт</translation>
17541755 </message>
1756 <message>
1757 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
1758 <extracomment>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.</extracomment>
1759 <translation>Сопряжение устройства «%1» не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт.</translation>
1760 </message>
17551761 </context>
17561762 <context>
17571763 <name>Hint</name>
17641770 <name>HistoryListItem</name>
17651771 <message>
17661772 <source>Click to view details of history entry.</source>
1773 <extracomment>LABEL ANDROID IOS</extracomment>
17671774 <translation>Щелкните, чтобы просмотреть подробную информацию о записи журнала.</translation>
1768 </message>
1769 <message>
1770 <source>today</source>
1771 <extracomment>LABEL ANDROID IOS</extracomment>
1772 <translation>сегодня</translation>
1773 </message>
1774 <message>
1775 <source>yesterday</source>
1776 <translation>вчера</translation>
1777 </message>
1778 <message>
1779 <source>dd.MM.yyyy</source>
1780 <translation>дд.ММ.гггг</translation>
17811775 </message>
17821776 <message>
17831777 <source>Tap for more details</source>
18591853 <translation>Поиск в журнале</translation>
18601854 </message>
18611855 <message>
1862 <source>today</source>
1863 <translation>сегодня</translation>
1864 </message>
1865 <message>
1866 <source>yesterday</source>
1867 <translation>вчера</translation>
1868 </message>
1869 <message>
1870 <source>dd.MM.yyyy</source>
1871 <translation>дд.ММ.гггг</translation>
1872 </message>
1873 <message>
18741856 <source>Clear history</source>
18751857 <extracomment>LABEL DESKTOP</extracomment>
18761858 <translation>Очистить журнал</translation>
19581940 </message>
19591941 <message>
19601942 <source>dd.MM.yyyy</source>
1961 <translation>дд.ММ.гггг</translation>
1943 <extracomment>LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString
1944 ----------
1945 LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
1946 <translation>dd.MM.yyyy</translation>
19621947 </message>
19631948 <message>
19641949 <source>Write access (update)</source>
20522037 <context>
20532038 <name>LocalNetworkInfo</name>
20542039 <message>
2055 <source>To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.</source>
2056 <extracomment>INFO IOS Let user know to check the application settings for local network permission</extracomment>
2057 <translation>Чтобы использовать смартфон в качестве устройства чтения карт (SaC), убедитесь в наличии доступа к локальной сети.</translation>
2058 </message>
2059 <message>
20602040 <source>Go to application settings</source>
20612041 <extracomment>INFO IOS Link to application settings</extracomment>
20622042 <translation>Перейти к настройкам приложения</translation>
20632043 </message>
2044 <message>
2045 <source>Ensure that access to the local network is allowed in your settings.</source>
2046 <extracomment>INFO IOS Let user know to check the application settings for local network permission</extracomment>
2047 <translation>Убедитесь в наличии доступа к локальной сети.</translation>
2048 </message>
20642049 </context>
20652050 <context>
20662051 <name>LogTitleBarControls</name>
21632148 <translation>Фильтр</translation>
21642149 </message>
21652150 <message>
2151 <source>Level</source>
2152 <extracomment>LABEL ANDROID IOS</extracomment>
2153 <translation>Уровень</translation>
2154 </message>
2155 <message>
2156 <source>Category</source>
2157 <extracomment>LABEL ANDROID IOS</extracomment>
2158 <translation>Категория</translation>
2159 </message>
2160 <message>
21662161 <source>Currently there are no log entries matching your filter.</source>
21672162 <extracomment>INFO ANDROID IOS No log entries, placeholder text.</extracomment>
21682163 <translation>В настоящее время отсутствуют записи журнала, соответствующие вашему фильтру.</translation>
21692164 </message>
2170 <message>
2171 <source>Level</source>
2172 <extracomment>LABEL ANDROID IOS</extracomment>
2173 <translation type="unfinished">Уровень</translation>
2174 </message>
2175 <message>
2176 <source>Category</source>
2177 <extracomment>LABEL ANDROID IOS</extracomment>
2178 <translation type="unfinished">Категория</translation>
2179 </message>
21802165 </context>
21812166 <context>
21822167 <name>MainView</name>
25762561 <translation>Провайдер</translation>
25772562 </message>
25782563 <message>
2579 <source>Remote</source>
2580 <translation>Удаленный доступ</translation>
2581 </message>
2582 <message>
25832564 <source>Settings</source>
25842565 <translation>Настройки</translation>
25852566 </message>
25862567 <message>
25872568 <source>Help</source>
25882569 <translation>Справка</translation>
2570 </message>
2571 <message>
2572 <source>Card reader</source>
2573 <translation>Устройство чтения карт</translation>
25892574 </message>
25902575 </context>
25912576 <context>
26222607 </message>
26232608 <message>
26242609 <source>NFC scan is not running.</source>
2625 <extracomment>INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.</extracomment>
2610 <extracomment>INFO ANDROID IOS NFC is available and enabled but needs to be started.</extracomment>
26262611 <translation>NFC-сканирование не выполняется.</translation>
26272612 </message>
26282613 <message>
26292614 <source>Please start the NFC scan.</source>
2630 <extracomment>INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.</extracomment>
2615 <extracomment>INFO ANDROID IOS NFC is available and enabled but needs to be started.</extracomment>
26312616 <translation>Запустите NFC-сканирование.</translation>
26322617 </message>
26332618 <message>
26652650 <extracomment>INFO ANDROID The ID card may be inserted, the authentication process may be started.</extracomment>
26662651 <translation>Расположите идентификационную карту непосредственно на задней стороне устройства.&lt;br/&gt;&lt;br/&gt;Точное положение идентификационной карты зависит от устройства. Возможное положение показано в анимации. Удерживайте идентификационную карту в одном положении несколько секунд, прежде чем поменять положение, и не смещайте ее после установки соединения.</translation>
26672652 </message>
2653 <message>
2654 <source>The device &quot;%1&quot; wants to use this smartphone as card reader and connect to your id card.</source>
2655 <extracomment>INFO ANDROID IOS %1 will be replaced with the name of the device.</extracomment>
2656 <translation>Устройство «%1» планирует использовать данный смартфон в качестве устройства чтения карт и установить соединение с вашей идентификационной картой.</translation>
2657 </message>
26682658 </context>
26692659 <context>
26702660 <name>NumberField</name>
27272717 </message>
27282718 </context>
27292719 <context>
2720 <name>PairingCodeInfoView</name>
2721 <message>
2722 <source>Pairing Information</source>
2723 <extracomment>LABEL ANDROID IOS</extracomment>
2724 <translation>Информация о сопряжении</translation>
2725 </message>
2726 <message>
2727 <source>Open %1 on your %2other device%3.</source>
2728 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3</extracomment>
2729 <translation>Откройте %1 в другом %2вашем устройстве%3.</translation>
2730 </message>
2731 <message>
2732 <source>On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.</source>
2733 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font.</extracomment>
2734 <translation>В данном устройстве перейдите в меню %1Настройки%2, а затем %1Смартфон в качестве устройства чтения карт%2 и в соответствующее меню %1Управлять сопряжениями%2.</translation>
2735 </message>
2736 <message>
2737 <source>Choose this smartphone in the list to pair it.</source>
2738 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3</extracomment>
2739 <translation>Чтобы выполнить сопряжение, выберите данный смартфон в списке.</translation>
2740 </message>
2741 </context>
2742 <context>
2743 <name>PairingProcessInfo</name>
2744 <message>
2745 <source>Open %1 on your smartphone as card reader.</source>
2746 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.</extracomment>
2747 <translation>Откройте %1 в вашем смартфоне в качестве устройства чтения карт.</translation>
2748 </message>
2749 <message>
2750 <source>On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.</source>
2751 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font.</extracomment>
2752 <translation>В данном устройстве выберите %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и соответствующее меню %1Выполнить сопряжение нового устройства%2.</translation>
2753 </message>
2754 <message>
2755 <source>Choose the smartphone in the list shown here to pair it.</source>
2756 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4</extracomment>
2757 <translation>Чтобы выполнить сопряжение, выберите смартфон в приведенном списке.</translation>
2758 </message>
2759 <message>
2760 <source>Ensure that the %1 on your Smartphone as card reader has at least version %2.</source>
2761 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.</extracomment>
2762 <translation>Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2.</translation>
2763 </message>
2764 </context>
2765 <context>
27302766 <name>PasswordInfoContent</name>
27312767 <message>
27322768 <source>More information</source>
27472783 <translation>Информация о PIN-коде</translation>
27482784 </message>
27492785 <message>
2786 <source>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.</source>
2787 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;what is the card pin?&apos;</extracomment>
2788 <translation>PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID.</translation>
2789 </message>
2790 <message>
27502791 <source>Where can I find the card PIN?</source>
27512792 <extracomment>LABEL ALL_PLATFORMS</extracomment>
27522793 <translation>Где найти PIN-код карты?</translation>
27532794 </message>
27542795 <message>
2796 <source>You set the card PIN either directly when you picked up your ID card at the citizens&apos; 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.</source>
2797 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the card PIN?&apos;</extracomment>
2798 <translation>Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID.</translation>
2799 </message>
2800 <message>
27552801 <source>How do I choose a secure PIN?</source>
27562802 <extracomment>LABEL ALL_PLATFORMS</extracomment>
27572803 <translation>Как выбрать безопасный PIN-код?</translation>
2804 </message>
2805 <message>
2806 <source>For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither &quot;123456&quot;, nor your date of birth, nor any other numbers printed on your ID card.</source>
2807 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 1/3</extracomment>
2808 <translation>Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, «123456», дату своего рождения или любые другие цифры с идентификационной карты).</translation>
2809 </message>
2810 <message>
2811 <source>You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN.</source>
2812 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 2/3</extracomment>
2813 <translation>Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код.</translation>
27582814 </message>
27592815 <message>
27602816 <source>Keep your PIN secret and change it if another person becomes aware of it.</source>
27722828 <translation>Информация о временном PIN-коде</translation>
27732829 </message>
27742830 <message>
2831 <source>The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card.</source>
2832 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 1/3</extracomment>
2833 <translation>5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту.</translation>
2834 </message>
2835 <message>
2836 <source>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.</source>
2837 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 2/3</extracomment>
2838 <translation>Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода.</translation>
2839 </message>
2840 <message>
27752841 <source>Once you have set a card PIN, the Transport PIN loses its validity.</source>
27762842 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 3/3</extracomment>
27772843 <translation>После создания PIN-кода карты временный PIN-код перестает действовать.</translation>
28022868 <translation>Информация о PUK-коде</translation>
28032869 </message>
28042870 <message>
2871 <source>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.</source>
2872 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where do I find the PUK?&apos;</extracomment>
2873 <translation>PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту.</translation>
2874 </message>
2875 <message>
28052876 <source>Why is the PUK required?</source>
28062877 <extracomment>LABEL ALL_PLATFORMS</extracomment>
28072878 <translation>Для чего необходим PUK-код?</translation>
28572928 <translation>Где найти CAN-код?</translation>
28582929 </message>
28592930 <message>
2931 <source>The CAN is a six-digit number that can be found on the bottom right of the front of the ID card.</source>
2932 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the CAN?&apos;</extracomment>
2933 <translation>CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты.</translation>
2934 </message>
2935 <message>
28602936 <source>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).</source>
28612937 <extracomment>INFO ALL_PLATFORMS Description text of CAN-allowed authentication</extracomment>
28622938 <translation>Код доступа (CAN) предоставляет доступ к сохраненным на идентификационной карте данным. CAN — это 6-значный номер, указанный на идентификационной карте спереди. Он расположен внизу справа рядом со сроком действия (выделен красным цветом).</translation>
28892965 <translation>Знаете ли вы свой PIN-код?</translation>
28902966 </message>
28912967 <message>
2968 <source>You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN?</source>
2969 <extracomment>INFO ALL_PLATFORMS</extracomment>
2970 <translation>Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код?</translation>
2971 </message>
2972 <message>
28922973 <source>You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it?</source>
28932974 <extracomment>INFO ALL_PLATFORMS</extracomment>
28942975 <translation>Вы установили PIN-код карты при получении идентификационной карты или позже самостоятельно, но не можете его вспомнить?</translation>
29042985 <translation>Типы PIN-кодов</translation>
29052986 </message>
29062987 <message>
2988 <source>Your ID card comes with a five-digit &apos;Transport PIN&apos; which you need to replace with a six-digit PIN that you choose yourself.</source>
2989 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 1/6</extracomment>
2990 <translation>К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить на 6-значным PIN-кодом (его вы выберете сами).</translation>
2991 </message>
2992 <message>
2993 <source>Five-digit Transport PIN</source>
2994 <extracomment>LABEL ALL_PLATFORMS</extracomment>
2995 <translation>5-значный временный PIN-код</translation>
2996 </message>
2997 <message>
2998 <source>The five-digit Transport PIN was sent to you by post after you applied for your ID card.</source>
2999 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 2/6</extracomment>
3000 <translation>5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту.</translation>
3001 </message>
3002 <message>
3003 <source>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.</source>
3004 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 3/6</extracomment>
3005 <translation>Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами.</translation>
3006 </message>
3007 <message>
3008 <source>Six-digit PIN</source>
3009 <extracomment>LABEL ALL_PLATFORMS</extracomment>
3010 <translation>6-значный PIN-код</translation>
3011 </message>
3012 <message>
3013 <source>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.</source>
3014 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 4/6</extracomment>
3015 <translation>Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код.</translation>
3016 </message>
3017 <message>
29073018 <source>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.</source>
29083019 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 5/6</extracomment>
29093020 <translation>Этот PIN-код позволяет в режиме онлайн подтвердить то, что идентификационная карта принадлежит именно вам. Никто не сможет использовать вашу идентификационную карту в режиме онлайн без этого PIN-кода.</translation>
29103021 </message>
29113022 <message>
3023 <source>You can change your six-digit PIN at any time in AusweisApp2.</source>
3024 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 6/6</extracomment>
3025 <translation>Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2.</translation>
3026 </message>
3027 <message>
29123028 <source>You can use the PIN Reset Service to request a new card PIN free of charge.</source>
29133029 <extracomment>LABEL ALL_PLATFORMS</extracomment>
29143030 <translation>Вы можете воспользоваться службой сброса PIN-кода, чтобы бесплатно запросить новый PIN-код карты.</translation>
29233039 <extracomment>LABEL ALL_PLATFORMS Hint text for PIN but it is unknown.</extracomment>
29243040 <translation>Если вы забыли PIN-код карты, вы можете бесплатно запросить новый PIN-код, воспользовавшись службой сброса PIN-кода.</translation>
29253041 </message>
2926 <message>
2927 <source>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.</source>
2928 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;what is the card pin?&apos;</extracomment>
2929 <translation type="unfinished">PIN-код карты — это 6-значный PIN-код, который пользователь создает самостоятельно. Этот PIN-код необходим, если планируется использовать функцию eID.</translation>
2930 </message>
2931 <message>
2932 <source>You set the card PIN either directly when you picked up your ID card at the citizens&apos; 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.</source>
2933 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the card PIN?&apos;</extracomment>
2934 <translation type="unfinished">Вы устанавливаете PIN-код карты либо непосредственно при получении идентификационной карты в ведомстве по делам граждан (Bürgeramt), либо позже в AusweisApp2, используя для этого 5-значный временный PIN-код. Только установив 6-значный PIN-код по своему выбору, вы можете использовать функцию eID.</translation>
2935 </message>
2936 <message>
2937 <source>For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither &quot;123456&quot;, nor your date of birth, nor any other numbers printed on your ID card.</source>
2938 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 1/3</extracomment>
2939 <translation type="unfinished">Не выбирайте для 6-значного PIN-кода комбинации, которые легко отгадать (например, 123456, дату своего рождения или любые другие цифры с идентификационной карты).</translation>
2940 </message>
2941 <message>
2942 <source>You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN.</source>
2943 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 2/3</extracomment>
2944 <translation type="unfinished">Изменить 6-значный PIN-код можно в любое время и неограниченное количество раз, если вы знаете свой действительный PIN-код.</translation>
2945 </message>
2946 <message>
2947 <source>The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card.</source>
2948 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 1/3</extracomment>
2949 <translation type="unfinished">5-значный временный PIN-код был отправлен вам в письме с PIN-кодом по почте после того, как вы заказали идентификационную карту.</translation>
2950 </message>
2951 <message>
2952 <source>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.</source>
2953 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 2/3</extracomment>
2954 <translation type="unfinished">Если при получении идентификационной карты вы не установили 6-значный PIN-код карты, это можно сделать с помощью временного PIN-кода.</translation>
2955 </message>
2956 <message>
2957 <source>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.</source>
2958 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where do I find the PUK?&apos;</extracomment>
2959 <translation type="unfinished">PUK-код — это 10-значный номер, который можно найти в письме с PIN-кодом, отправленном вам по почте после того, как вы заказали идентификационную карту.</translation>
2960 </message>
2961 <message>
2962 <source>The CAN is a six-digit number that can be found on the bottom right of the front of the ID card.</source>
2963 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the CAN?&apos;</extracomment>
2964 <translation type="unfinished">CAN-код — это 6-значный номер, указанный в нижнем правом углу на передней стороне идентификационной карты.</translation>
2965 </message>
2966 <message>
2967 <source>Your ID card comes with a five-digit &apos;Transport PIN&apos; which you need to replace with a six-digit PIN that you choose yourself.</source>
2968 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 1/6</extracomment>
2969 <translation type="unfinished">К вашей идентификационной карте прилагается 5-значный временный PIN-код, который необходимо заменить 6-значным PIN-кодом (его вы выберете сами).</translation>
2970 </message>
2971 <message>
2972 <source>Five-digit Transport PIN</source>
2973 <extracomment>LABEL ALL_PLATFORMS</extracomment>
2974 <translation type="unfinished">5-значный временный PIN-код</translation>
2975 </message>
2976 <message>
2977 <source>The five-digit Transport PIN was sent to you by post after you applied for your ID card.</source>
2978 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 2/6</extracomment>
2979 <translation type="unfinished">5-значный временный PIN-код был отправлен вам по почте после того, как вы заказали идентификационную карту.</translation>
2980 </message>
2981 <message>
2982 <source>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.</source>
2983 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 3/6</extracomment>
2984 <translation type="unfinished">Этот PIN-код можно использовать только один раз. Настроив функцию eID, вы замените этот 5-значный PIN-код 6-значным PIN-кодом, который выберете сами.</translation>
2985 </message>
2986 <message>
2987 <source>Six-digit PIN</source>
2988 <extracomment>LABEL ALL_PLATFORMS</extracomment>
2989 <translation type="unfinished">6-значный PIN-код</translation>
2990 </message>
2991 <message>
2992 <source>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.</source>
2993 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 4/6</extracomment>
2994 <translation type="unfinished">Это номер, который вы выбираете сами при настройке функции eID в первый раз. Он заменяет 5-значный временный PIN-код.</translation>
2995 </message>
2996 <message>
2997 <source>You can change your six-digit PIN at any time in AusweisApp2.</source>
2998 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 6/6</extracomment>
2999 <translation type="unfinished">Вы можете изменить свой 6-значный PIN-код в любое время в AusweisApp2.</translation>
3000 </message>
3001 <message>
3002 <source>You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN?</source>
3003 <extracomment>INFO ALL_PLATFORMS</extracomment>
3004 <translation type="unfinished">Вы еще не установили 6-значный PIN-код карты и не можете найти письмо с PIN-кодом, где указан временный PIN-код?</translation>
3005 </message>
30063042 </context>
30073043 <context>
30083044 <name>PersonalizationController</name>
33153351 <context>
33163352 <name>ProviderDetailHistoryItem</name>
33173353 <message>
3318 <source>today</source>
3319 <extracomment>LABEL ANDROID IOS</extracomment>
3320 <translation>сегодня</translation>
3321 </message>
3322 <message>
3323 <source>yesterday</source>
3324 <translation>вчера</translation>
3325 </message>
3326 <message>
3327 <source>dd.MM.yyyy</source>
3328 <translation>дд.ММ.гггг</translation>
3329 </message>
3330 <message>
33313354 <source>Service:</source>
33323355 <extracomment>LABEL DESKTOP</extracomment>
33333356 <translation>Служба:</translation>
33863409 <message>
33873410 <source>See details under &quot;more...&quot;</source>
33883411 <extracomment>LABEL DESKTOP</extracomment>
3389 <translation>Подробнее см. в пункте «Дополнительные сведения»</translation>
3412 <translation>Подробнее см. в пункте «Дополнительные сведения».</translation>
33903413 </message>
33913414 </context>
33923415 <context>
35903613 <translation>Нажмите пробел для сопряжения смартфона «%1».</translation>
35913614 </message>
35923615 <message>
3593 <source>Click to pair</source>
3594 <translation>Нажмите для сопряжения</translation>
3595 </message>
3596 <message>
35973616 <source>Remove remote device</source>
35983617 <translation>Удалить дистанционное устройство</translation>
35993618 </message>
36013620 <context>
36023621 <name>RemoteReaderView</name>
36033622 <message>
3604 <source>Paired remote devices</source>
3605 <translation>Сопряженные дистанционные устройства</translation>
3606 </message>
3607 <message>
3608 <source>Available remote devices</source>
3609 <translation>Доступные дистанционные устройства</translation>
3610 </message>
3611 <message>
3612 <source>Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here.</source>
3613 <translation>Здесь отображаются только уже сопряженные или подключенные к той же сети Wi-Fi устройства с активированной удаленной службой.</translation>
3614 </message>
3615 <message>
3616 <source>More information</source>
3617 <extracomment>LABEL DESKTOP</extracomment>
3618 <translation>Дополнительные сведения</translation>
3623 <source>Paired devices</source>
3624 <translation>Сопряженные устройства</translation>
3625 </message>
3626 <message>
3627 <source>Add pairing</source>
3628 <translation>Добавить сопряжение</translation>
3629 </message>
3630 <message>
3631 <source>Open the %1 on your Smartphone as card reader.</source>
3632 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.</extracomment>
3633 <translation>Откройте %1 в вашем смартфоне в качестве устройства чтения карт.</translation>
3634 </message>
3635 <message>
3636 <source>Both devices have to be connected to the same WiFi.</source>
3637 <translation>Оба устройства должны быть подключены к одной сети Wi-Fi.</translation>
3638 </message>
3639 <message>
3640 <source>On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.</source>
3641 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font</extracomment>
3642 <translation>В данном устройстве перейдите в меню %1Устройство чтения карт%2, а затем %1Выполнить сопряжение устройства%2 и в соответствующее меню %1Выполнить сопряжение нового устройства%2.</translation>
3643 </message>
3644 <message>
3645 <source>Choose the device in the list to pair it.</source>
3646 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4</extracomment>
3647 <translation>Чтобы выполнить сопряжение, выберите устройство в списке.</translation>
3648 </message>
3649 <message>
3650 <source>Last connected</source>
3651 <translation>Последние подключенные</translation>
3652 </message>
3653 <message>
3654 <source>Ensure that the %1 on your Smartphone as card reader has at least version %2.</source>
3655 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.</extracomment>
3656 <translation>Убедитесь, что программа %1, установленная на смартфоне в качестве устройства чтения карт, имеет версию не ниже %2.</translation>
3657 </message>
3658 </context>
3659 <context>
3660 <name>RemoteServiceController</name>
3661 <message>
3662 <source>You are about to identify yourself towards the following provider using the device &quot;%1&quot;:</source>
3663 <extracomment>LABEL ANDROID IOS</extracomment>
3664 <translation>Вы собираетесь пройти самоидентификацию для следующего провайдера, используя устройство «%1»:</translation>
3665 </message>
3666 <message>
3667 <source>Card reader</source>
3668 <extracomment>LABEL ANDROID IOS</extracomment>
3669 <translation>Устройство чтения карт</translation>
3670 </message>
3671 <message>
3672 <source>Remote service</source>
3673 <extracomment>LABEL ANDROID IOS</extracomment>
3674 <translation>Удаленная служба</translation>
36193675 </message>
36203676 </context>
36213677 <context>
36223678 <name>RemoteServiceSettings</name>
36233679 <message>
3624 <source>Configure remote service</source>
3625 <extracomment>LABEL ANDROID IOS</extracomment>
3626 <translation>Сконфигурировать удаленную службу</translation>
3680 <source>Manage pairings</source>
3681 <extracomment>LABEL ANDROID IOS</extracomment>
3682 <translation>Управление сопряжениями</translation>
36273683 </message>
36283684 </context>
36293685 <context>
36303686 <name>RemoteServiceView</name>
3631 <message>
3632 <source>Remote service</source>
3633 <extracomment>LABEL ANDROID IOS</extracomment>
3634 <translation>Удаленная служба</translation>
3635 </message>
36363687 <message>
36373688 <source>Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code.</source>
36383689 <extracomment>ERROR ANDROID IOS An error occurred while pairing the device.</extracomment>
36643715 <translation>Ожидание соединения</translation>
36653716 </message>
36663717 <message>
3667 <source>Remote service ready</source>
3668 <extracomment>LABEL ANDROID IOS</extracomment>
3669 <translation>Удаленная служба готова к работе</translation>
3670 </message>
3671 <message>
36723718 <source>Waiting for connection from a paired device...</source>
36733719 <extracomment>INFO ANDROID IOS</extracomment>
36743720 <translation>Ожидание соединения сопряженного устройства…</translation>
36753721 </message>
36763722 <message>
3677 <source>Start the remote access in order to make this smartphone visible and use it as a card reader (SaC).
3723 <source>Pairing code: &lt;b&gt;%1&lt;/b&gt;</source>
3724 <extracomment>LABEL ANDROID IOS</extracomment>
3725 <translation>Код сопряжения: &lt;b&gt;%1&lt;/b&gt;</translation>
3726 </message>
3727 <message>
3728 <source>Enable WiFi</source>
3729 <extracomment>LABEL ANDROID IOS</extracomment>
3730 <translation>Активировать Wi-Fi</translation>
3731 </message>
3732 <message>
3733 <source>Enable NFC</source>
3734 <extracomment>LABEL ANDROID IOS</extracomment>
3735 <translation>Активировать NFC</translation>
3736 </message>
3737 <message>
3738 <source>Pair device</source>
3739 <extracomment>LABEL ANDROID IOS</extracomment>
3740 <translation>Выполнить сопряжение устройства</translation>
3741 </message>
3742 <message>
3743 <source>Allow connection</source>
3744 <extracomment>LABEL ANDROID IOS</extracomment>
3745 <translation>Разрешить подключение</translation>
3746 </message>
3747 <message>
3748 <source>You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.
36783749
3679 If you have not already paired a device, start the pairing now to set up this smartphone as a card reader.</source>
3750 To do this you first have to pair that device with this smartphone.</source>
36803751 <extracomment>INFO ANDROID IOS</extracomment>
3681 <translation>Запустите удаленный доступ, чтобы смартфон стал видимым и его можно было использовать как устройство чтения карт (SaC).
3752 <translation>Можно использовать данный смартфон в качестве устройства чтения карт для %1 в других устройствах, например в ноутбуке.
36823753
3683 Если сопряженных устройств еще нет, запустите сопряжение, чтобы настроить смартфон как устройство чтения карт.</translation>
3684 </message>
3685 <message>
3686 <source>Pairing code: &lt;b&gt;%1&lt;/b&gt;</source>
3687 <extracomment>LABEL ANDROID IOS</extracomment>
3688 <translation>Код сопряжения: &lt;b&gt;%1&lt;/b&gt;</translation>
3689 </message>
3690 <message>
3691 <source>Both of your devices have to be connected to the same WiFi.</source>
3692 <extracomment>INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.</extracomment>
3693 <translation>Оба устройства должны быть подключены к одной сети Wi-Fi.</translation>
3694 </message>
3695 <message>
3696 <source>Enable WiFi</source>
3697 <extracomment>LABEL ANDROID IOS</extracomment>
3698 <translation>Активировать Wi-Fi</translation>
3699 </message>
3700 <message>
3701 <source>Enable NFC</source>
3702 <extracomment>LABEL ANDROID IOS</extracomment>
3703 <translation>Активировать NFC</translation>
3704 </message>
3705 <message>
3706 <source>Stop remote service</source>
3707 <extracomment>LABEL ANDROID IOS</extracomment>
3708 <translation>Остановить удаленную службу</translation>
3709 </message>
3710 <message>
3711 <source>Start remote service</source>
3712 <extracomment>LABEL ANDROID IOS</extracomment>
3713 <translation>Запустить удаленную службу</translation>
3714 </message>
3715 <message>
3716 <source>Stop pairing</source>
3717 <extracomment>LABEL ANDROID IOS</extracomment>
3718 <translation>Остановить сопряжение</translation>
3719 </message>
3720 <message>
3721 <source>Start pairing</source>
3722 <extracomment>LABEL ANDROID IOS</extracomment>
3723 <translation>Запустить сопряжение</translation>
3724 </message>
3725 <message>
3726 <source>Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC).</source>
3754 Для этого сначала следует выполнить сопряжение данного устройства с этим смартфоном.</translation>
3755 </message>
3756 <message>
3757 <source>Card reader</source>
3758 <extracomment>LABEL ANDROID IOS</extracomment>
3759 <translation>Устройство чтения карт</translation>
3760 </message>
3761 <message>
3762 <source>Paired Devices</source>
37273763 <extracomment>INFO ANDROID IOS</extracomment>
3728 <translation>Введите код %1 в %2 на другом вашем устройстве, чтобы использовать смартфон в качестве устройства чтения карт (SaC).</translation>
3764 <translation>Сопряженные устройства</translation>
3765 </message>
3766 <message>
3767 <source>Pair new device</source>
3768 <extracomment>LABEL ANDROID IOS</extracomment>
3769 <translation>Выполнить сопряжение нового устройства</translation>
3770 </message>
3771 <message>
3772 <source>Waiting for pairing</source>
3773 <extracomment>LABEL ANDROID IOS</extracomment>
3774 <translation>Ожидание сопряжения</translation>
3775 </message>
3776 <message>
3777 <source>Start pairing of a new device</source>
3778 <extracomment>LABEL ANDROID IOS</extracomment>
3779 <translation>Начать сопряжение нового устройства</translation>
3780 </message>
3781 <message>
3782 <source>Where do I enter the pairing code?</source>
3783 <extracomment>LABEL ANDROID IOS</extracomment>
3784 <translation>Где следует вводить код сопряжения?</translation>
3785 </message>
3786 <message>
3787 <source>Enter the pairing code %1 in the %2 on your other device.</source>
3788 <extracomment>INFO ANDROID IOS</extracomment>
3789 <translation>Введите код сопряжения %1 в поле %2 в другом вашем устройстве.</translation>
3790 </message>
3791 <message>
3792 <source>Cancel pairing</source>
3793 <extracomment>LABEL ANDROID IOS</extracomment>
3794 <translation>Отменить сопряжение</translation>
3795 </message>
3796 <message>
3797 <source>Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.</source>
3798 <extracomment>INFO ANDROID IOS</extracomment>
3799 <translation>Разрешите подключение к сопряженным устройствам, чтобы использовать этот смартфон в качестве устройства чтения карт, а также для сопряжения с другим устройством.</translation>
3800 </message>
3801 <message>
3802 <source>Paired devices may use this Smartphone as a card reader now.</source>
3803 <extracomment>INFO ANDROID IOS</extracomment>
3804 <translation>Теперь сопряженные устройства могут использовать этот смартфон в качестве устройства чтения карт.</translation>
37293805 </message>
37303806 </context>
37313807 <context>
37323808 <name>RemoteServiceViewRemote</name>
3733 <message>
3734 <source>Paired devices</source>
3735 <extracomment>LABEL ANDROID IOS</extracomment>
3736 <translation>Сопряженные устройства</translation>
3737 </message>
3738 <message>
3739 <source>No device is paired.</source>
3740 <extracomment>LABEL ANDROID IOS</extracomment>
3741 <translation>Нет сопряженных устройств.</translation>
3742 </message>
3743 <message>
3744 <source>Click to remove device</source>
3745 <extracomment>LABEL ANDROID IOS</extracomment>
3746 <translation>Нажмите для удаления устройства</translation>
3747 </message>
37483809 <message>
37493810 <source>Remove pairing</source>
37503811 <extracomment>INFO ANDROID IOS</extracomment>
37613822 <translation>Удалить</translation>
37623823 </message>
37633824 <message>
3764 <source>Available devices</source>
3765 <extracomment>LABEL ANDROID IOS</extracomment>
3766 <translation>Доступные устройства</translation>
3767 </message>
3768 <message>
3769 <source>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.</source>
3770 <extracomment>INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network.</extracomment>
3771 <translation>Нет доступных сопряженных смартфонов, используемых как устройство чтения карт (SaC). Убедитесь в том, что смартфон активирован в AusweisApp2 на другом устройстве в качестве устройства чтения карт (SaC) и оба устройства подключены к одной сети Wi-Fi.</translation>
3772 </message>
3773 <message>
37743825 <source>Please connect your WiFi to use another smartphone as card reader (SaC).</source>
37753826 <extracomment>INFO ANDROID IOS Wifi is not enabled and no new devices can be paired.</extracomment>
37763827 <translation>Подключитесь к сети Wi-Fi, чтобы использовать другой смартфон в качестве устройства чтения карт (SaC).</translation>
37813832 <translation>Активировать Wi-Fi</translation>
37823833 </message>
37833834 <message>
3835 <source>Pairing code</source>
3836 <extracomment>LABEL ANDROID IOS</extracomment>
3837 <translation>Код сопряжения</translation>
3838 </message>
3839 <message>
3840 <source>Add pairing</source>
3841 <extracomment>LABEL ANDROID IOS</extracomment>
3842 <translation>Добавить сопряжение</translation>
3843 </message>
3844 <message>
3845 <source>Click to remove device</source>
3846 <extracomment>LABEL ANDROID IOS</extracomment>
3847 <translation>Нажмите для удаления устройства</translation>
3848 </message>
3849 <message>
3850 <source>Last connected</source>
3851 <extracomment>LABEL ANDROID IOS</extracomment>
3852 <translation>Последние подключенные</translation>
3853 </message>
3854 <message>
3855 <source>Available</source>
3856 <extracomment>LABEL ANDROID IOS</extracomment>
3857 <translation>Доступно</translation>
3858 </message>
3859 <message>
3860 <source>Paired devices</source>
3861 <extracomment>LABEL ANDROID IOS</extracomment>
3862 <translation>Сопряженные устройства</translation>
3863 </message>
3864 <message>
37843865 <source>Click to pair</source>
37853866 <extracomment>LABEL ANDROID IOS</extracomment>
37863867 <translation>Нажмите для сопряжения</translation>
37873868 </message>
3788 <message>
3789 <source>Pairing mode</source>
3790 <extracomment>INFO ANDROID IOS</extracomment>
3791 <translation>Режим сопряжения</translation>
3792 </message>
3793 <message>
3794 <source>Start the pairing mode on your smartphone if you haven&apos;t done it already.</source>
3795 <extracomment>INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone.</extracomment>
3796 <translation>Запустите режим сопряжения на смартфоне, если вы еще не сделали это.</translation>
3797 </message>
3798 <message>
3799 <source>Pairing code</source>
3800 <extracomment>LABEL ANDROID IOS</extracomment>
3801 <translation>Код сопряжения</translation>
3869 </context>
3870 <context>
3871 <name>RemoteServiceWifiInfo</name>
3872 <message>
3873 <source>Both devices have to be connected to the same WiFi.</source>
3874 <extracomment>INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.</extracomment>
3875 <translation>Оба устройства должны быть подключены к одной сети Wi-Fi.</translation>
38023876 </message>
38033877 </context>
38043878 <context>
38053879 <name>RemoteWorkflow</name>
38063880 <message>
3807 <source>The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
3808 <extracomment>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.</extracomment>
3809 <translation>Сопряжение устройства %1 не было выполнено, поскольку оно не отвечало на попытки соединения. Снова выполните сопряжение устройства для его использования в качестве устройства чтения карт.</translation>
3810 </message>
3811 <message>
38123881 <source>Enable WiFi</source>
38133882 <extracomment>LABEL ANDROID IOS</extracomment>
38143883 <translation>Активировать Wi-Fi</translation>
3815 </message>
3816 <message>
3817 <source>Pair device</source>
3818 <extracomment>LABEL ANDROID IOS</extracomment>
3819 <translation>Выполнить сопряжение устройства</translation>
38203884 </message>
38213885 <message>
38223886 <source>To use the remote service WiFi has to be activated. Please activate WiFi in your device settings.</source>
38243888 <translation>Для использования удаленной службы необходимо активировать Wi-Fi. Активируйте Wi-Fi в настройках устройства.</translation>
38253889 </message>
38263890 <message>
3827 <source>No paired smartphone as card reader (SaC) with activated &quot;remote service&quot; available.</source>
3828 <extracomment>INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.</extracomment>
3829 <translation>Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC), с активированной удаленной службой.</translation>
3830 </message>
3831 <message>
38323891 <source>Wifi disabled</source>
38333892 <extracomment>LABEL ANDROID IOS</extracomment>
38343893 <translation>Wi-Fi деактивирован</translation>
3835 </message>
3836 <message>
3837 <source>Waiting for connection</source>
3838 <extracomment>LABEL ANDROID IOS</extracomment>
3839 <translation>Ожидание соединения</translation>
38403894 </message>
38413895 <message>
38423896 <source>Determine card</source>
38533907 <extracomment>INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted.</extracomment>
38543908 <translation>Подключено к %1. Разместите интерфейс NFC смартфона на идентификационной карте.</translation>
38553909 </message>
3910 <message>
3911 <source>Manage pairings</source>
3912 <extracomment>LABEL ANDROID IOS</extracomment>
3913 <translation>Управление сопряжениями</translation>
3914 </message>
3915 <message>
3916 <source>No smartphone as card reader connected</source>
3917 <extracomment>LABEL ANDROID IOS</extracomment>
3918 <translation>Смартфон в качестве устройства чтения карт не подключен</translation>
3919 </message>
3920 <message>
3921 <source>Allow a connection on a paired smartphone or pair a new smartphone.</source>
3922 <extracomment>INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.</extracomment>
3923 <translation>Разрешите подключение к сопряженному смартфону или выполните сопряжение нового смартфона.</translation>
3924 </message>
38563925 </context>
38573926 <context>
38583927 <name>ResultErrorView</name>
42484317 <translation>Ввести PIN-код на этом устройстве</translation>
42494318 </message>
42504319 <message>
4251 <source>Remote card reader</source>
4252 <extracomment>LABEL ANDROID IOS</extracomment>
4253 <translation>Удаленное устройство чтения карт</translation>
4254 </message>
4255 <message>
4256 <source>Configure remote service for another device</source>
4257 <extracomment>LABEL ANDROID IOS</extracomment>
4258 <translation>Сконфигурировать удаленную службу для другого устройства</translation>
4259 </message>
4260 <message>
42614320 <source>Save history</source>
42624321 <extracomment>LABEL ANDROID IOS</extracomment>
42634322 <translation>Сохранить журнал</translation>
43734432 <source>15 days old Logfile</source>
43744433 <extracomment>LABEL ALL_PLATFORMS</extracomment>
43754434 <translation>Файл журнала, созданный 15 дней назад</translation>
4435 </message>
4436 <message>
4437 <source>Show requested rights on this device as well</source>
4438 <extracomment>LABEL ANDROID IOS</extracomment>
4439 <translation>Показывать запрошенные права также и в этом устройстве</translation>
4440 </message>
4441 <message>
4442 <source>Show access rights</source>
4443 <extracomment>LABEL ANDROID IOS</extracomment>
4444 <translation>Показывать права доступа</translation>
4445 </message>
4446 <message>
4447 <source>Manage paired devices and add new devices</source>
4448 <extracomment>LABEL ANDROID IOS</extracomment>
4449 <translation>Управление сопряженными устройствами и добавление новых устройств</translation>
4450 </message>
4451 <message>
4452 <source>Manage pairings</source>
4453 <extracomment>LABEL ANDROID IOS</extracomment>
4454 <translation>Управление сопряжениями</translation>
43764455 </message>
43774456 </context>
43784457 <context>
47574836 <source>Continue</source>
47584837 <translation>Продолжить</translation>
47594838 </message>
4839 <message>
4840 <source>You have not yet set up a Smart-eID or it is no longer usable.
4841
4842 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.</source>
4843 <extracomment>LABEL ANDROID IOS</extracomment>
4844 <translation>Вы еще не создали электронную идентификационную карту Smart-eID, или же она более не пригодна для использования.
4845
4846 Для продолжения используйте вашу идентификационную карту, выбрав интерфейс NFC. Если вы хотите создать новую электронную идентификационную карту Smart-eID, отмените текущий процесс и запустите настройку Smart-eID на начальном экране.</translation>
4847 </message>
47604848 </context>
47614849 <context>
47624850 <name>StoreFeedbackPopup</name>
50145102 </message>
50155103 <message>
50165104 <source>App on Android smartphone &lt;b&gt;with&lt;/b&gt; NFC chip as card reader</source>
5017 <translation>Приложение на смартфоне с ОС Android &lt;b&gt;с&lt;/b&gt; чипсетом NFC в качестве устройства чтения карт</translation>
5105 <translation>Приложение на смартфоне &lt;b&gt;с&lt;/b&gt; ОС Android с чипсетом NFC в качестве устройства чтения карт</translation>
50185106 </message>
50195107 <message>
50205108 <source>Smartphone as card reader tutorial</source>
51575245 <message>
51585246 <source>You can read our &lt;b&gt;FAQs&lt;/b&gt; or &lt;b&gt;write&lt;/b&gt; to us...</source>
51595247 <extracomment>LABEL ANDROID IOS</extracomment>
5160 <translation>Прочитайте раздел &lt;b&gt;Часто задаваемые вопросы&lt;/b&gt; или &lt;b&gt;напишите&lt;/b&gt; нам…</translation>
5248 <translation>Прочитайте раздел «Часто задаваемые вопросы» или &lt;b&gt;напишите&lt;/b&gt; нам…</translation>
51615249 </message>
51625250 <message>
51635251 <source>or</source>
52035291 <message>
52045292 <source>App on Android smartphone &lt;b&gt;with&lt;/b&gt; NFC chip as card reader</source>
52055293 <extracomment>LABEL ANDROID</extracomment>
5206 <translation>Приложение на смартфоне с ОС Android &lt;b&gt;с&lt;/b&gt; чипсетом NFC в качестве устройства чтения карт</translation>
5294 <translation>Приложение на смартфоне &lt;b&gt;с&lt;/b&gt; ОС Android с чипсетом NFC в качестве устройства чтения карт</translation>
52075295 </message>
52085296 <message>
52095297 <source>Click link on the website of the provider.</source>
53245412 <translation>Оба устройства должны быть подключены к одной сети Wi-Fi.</translation>
53255413 </message>
53265414 <message>
5327 <source>Now choose &quot;Remote&quot; in the AusweisApp2 on your smartphone...</source>
5328 <extracomment>LABEL ANDROID IOS</extracomment>
5329 <translation>Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне…</translation>
5415 <source>Now choose &quot;Card reader&quot; in the AusweisApp2 on your smartphone...</source>
5416 <extracomment>LABEL ANDROID IOS</extracomment>
5417 <translation>Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне…</translation>
53305418 </message>
53315419 <message>
53325420 <source>Now</source>
53345422 <translation>сейчас</translation>
53355423 </message>
53365424 <message>
5337 <source>Start pairing</source>
5338 <extracomment>LABEL ANDROID IOS</extracomment>
5339 <translation>Запустить сопряжение</translation>
5425 <source>Pair device</source>
5426 <extracomment>LABEL ANDROID IOS</extracomment>
5427 <translation>Выполнить сопряжение устройства</translation>
53405428 </message>
53415429 <message>
53425430 <source>Pairing code</source>
53615449 <message>
53625450 <source>Select the &lt;b&gt;Smartphone as card reader&lt;/b&gt; tab.</source>
53635451 <extracomment>LABEL ANDROID IOS</extracomment>
5364 <translation>Выберите вкладку &lt;b&gt;Смартфон в качестве устройства чтения карт&lt;/b&gt;.</translation>
5452 <translation>Выберите вкладку «Смартфон в качестве устройства чтения карт».</translation>
53655453 </message>
53665454 <message>
53675455 <source>Select smartphone from list</source>
54825570 <translation>Оба устройства должны быть подключены к одной сети Wi-Fi.</translation>
54835571 </message>
54845572 <message>
5485 <source>Now choose &quot;Remote&quot; in the AusweisApp2 on your smartphone...</source>
5486 <extracomment>LABEL ANDROID IOS</extracomment>
5487 <translation>Далее выберите «Удаленный доступ» в AusweisApp2 на смартфоне…</translation>
5573 <source>Now choose &quot;Card reader&quot; in the AusweisApp2 on your smartphone...</source>
5574 <extracomment>LABEL ANDROID IOS</extracomment>
5575 <translation>Далее выберите «Устройство чтения карт» в AusweisApp2 на смартфоне…</translation>
54885576 </message>
54895577 <message>
54905578 <source>Now</source>
54925580 <translation>сейчас</translation>
54935581 </message>
54945582 <message>
5495 <source>Start pairing</source>
5496 <extracomment>LABEL ANDROID IOS</extracomment>
5497 <translation>Запустить сопряжение</translation>
5583 <source>Pair device</source>
5584 <extracomment>LABEL ANDROID IOS</extracomment>
5585 <translation>Выполнить сопряжение устройства</translation>
54985586 </message>
54995587 <message>
55005588 <source>Pairing code</source>
55125600 <translation>При первом использовании смартфона в качестве устройства чтения карт (SaC) iOS запрашивает разрешение на доступ к локальной сети. Разрешение необходимо, чтобы обнаружить ваш SaC и подключиться к нему. После первого запроса вы всегда можете отменить разрешение в настройках iOS для этого приложения.</translation>
55135601 </message>
55145602 <message>
5515 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Configure remote service&lt;/b&gt;.</source>
5603 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Manage pairings&lt;/b&gt;.</source>
55165604 <extracomment>LABEL IOS</extracomment>
5517 <translation>Откройте AusweisApp2 на вашем устройстве &lt;b&gt;без&lt;/b&gt; NFC и выберите &lt;b&gt;Сконфигурировать удаленную службу&lt;/b&gt;.</translation>
5605 <translation>Теперь откройте приложение AusweisApp2 в своем устройстве &lt;b&gt;без&lt;/b&gt; NFC и выберите меню «Управление сопряжениями».</translation>
55185606 </message>
55195607 <message>
55205608 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Smartphone as card reader&lt;/b&gt;.</source>
55215609 <extracomment>LABEL ANDROID</extracomment>
5522 <translation>Откройте AusweisApp2 на вашем устройстве &lt;b&gt;без&lt;/b&gt; NFC и выберите &lt;b&gt;Смартфон в качестве устройства чтения карт&lt;/b&gt;.</translation>
5610 <translation>Откройте AusweisApp2 на вашем устройстве &lt;b&gt;без&lt;/b&gt; NFC и выберите «Смартфон в качестве устройства чтения карт».</translation>
55235611 </message>
55245612 <message>
55255613 <source>Now select &lt;b&gt;Settings&lt;/b&gt;.</source>
55265614 <extracomment>LABEL ANDROID IOS</extracomment>
5527 <translation>Далее выберите &lt;b&gt;Настройки&lt;/b&gt;.</translation>
5615 <translation>Далее выберите «Настройки».</translation>
55285616 </message>
55295617 <message>
55305618 <source>Choose smartphone from list</source>
56805768 <message>
56815769 <source>On every authentication you get displayed &lt;b&gt;who&lt;/b&gt; wants to access &lt;b&gt;which&lt;/b&gt; data</source>
56825770 <extracomment>LABEL ANDROID IOS</extracomment>
5683 <translation>При каждой аутентификации отображается, &lt;b&gt;кто&lt;/b&gt; и к &lt;b&gt;каким&lt;/b&gt; данным запрашивает доступ,</translation>
5771 <translation>При каждой аутентификации отображается, &lt;b&gt;кто&lt;/b&gt; и к &lt;b&gt;каким&lt;/b&gt; данным запрашивает доступ.</translation>
56845772 </message>
56855773 <message>
56865774 <source>and you consent to the request with your six-digit PIN.</source>
59226010 <source>Checksum link:</source>
59236011 <extracomment>LABEL DESKTOP Link to download checksum to verify the downloaded update file.</extracomment>
59246012 <translation>Ссылка для контрольной суммы:</translation>
6013 </message>
6014 </context>
6015 <context>
6016 <name>Utils</name>
6017 <message>
6018 <source>today</source>
6019 <extracomment>LABEL ALL_PLATFORMS</extracomment>
6020 <translation>сегодня</translation>
6021 </message>
6022 <message>
6023 <source>yesterday</source>
6024 <extracomment>LABEL ALL_PLATFORMS</extracomment>
6025 <translation>вчера</translation>
6026 </message>
6027 <message>
6028 <source>dd.MM.yyyy</source>
6029 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
6030 <translation>dd.MM.yyyy</translation>
59256031 </message>
59266032 </context>
59276033 <context>
63176423 </message>
63186424 <message>
63196425 <source>d. MMMM yyyy, hh:mm:ss AP</source>
6320 <extracomment>LABEL DESKTOP Timestamp, formatted according to the selected language</extracomment>
6426 <extracomment>LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
63216427 <translation>d MMMM yyyy г., hh:mm:ss</translation>
63226428 </message>
63236429 <message>
65276633 </message>
65286634 <message>
65296635 <source>dd.MM.yyyy, hh:mm:ss</source>
6530 <extracomment>LABEL DESKTOP Timestamp</extracomment>
6531 <translation>дд.ММ.гггг, чч:мм:сс</translation>
6636 <extracomment>LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
6637 <translation>dd.MM.yyyy, hh:mm:ss</translation>
65326638 </message>
65336639 <message>
65346640 <source>Last connection: %1</source>
67926898 <translation>Сбой аутентификации.</translation>
67936899 </message>
67946900 <message>
6795 <source>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.</source>
6796 <extracomment>ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length.</extracomment>
6797 <translation>Ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение.</translation>
6901 <source>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.</source>
6902 <extracomment>ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length.</extracomment>
6903 <translation>Размер данных, отправленных на идентификационную карту, не был принят. Либо данные неверны, либо ваше устройство чтения карт не поддерживает связь по протоколу с расширенной длиной и не может использоваться для считывания идентификационной карты. К сожалению, %1 не влияет на это ограничение.</translation>
67986904 </message>
67996905 <message>
68006906 <source>No certificate description available.</source>
70947200 <name>governikus::HistoryModelSearchFilter</name>
70957201 <message>
70967202 <source>dd.MM.yyyy</source>
7097 <translation>дд.ММ.гггг</translation>
7203 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
7204 <translation>dd.MM.yyyy</translation>
70987205 </message>
70997206 </context>
71007207 <context>
71467253 </message>
71477254 <message>
71487255 <source>dd.MM.yyyy hh:mm:ss</source>
7256 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
71497257 <translation>dd.MM.yyyy, hh:mm:ss</translation>
71507258 </message>
71517259 <message>
72057313 <name>governikus::NotificationModel</name>
72067314 <message>
72077315 <source>hh:mm:ss</source>
7208 <translation>чч:мм:сс</translation>
7316 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
7317 <translation>hh:mm:ss</translation>
72097318 </message>
72107319 </context>
72117320 <context>
72767385 <message>
72777386 <source>AusweisApp2 is a product of Governikus GmbH &amp; Co. KG - on behalf of the Federal Office for Information Security.</source>
72787387 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7279 <translation>AusweisApp2 является продуктом компании Governikus GmbH &amp; Co. KG — по заказу Федерального управления по информационной безопасности.</translation>
7388 <translation>AusweisApp2 является продуктом компании Governikus GmbH Co. KG — по заказу Федерального управления по информационной безопасности.</translation>
72807389 </message>
72817390 <message>
72827391 <source>For further information, please see %1</source>
72987407 </message>
72997408 <message>
73007409 <source>dd.MM.yyyy hh:mm AP</source>
7301 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7410 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
73027411 <translation>dd.MM.yyyy hh:mm</translation>
73037412 </message>
73047413 <message>
73237432 </message>
73247433 <message>
73257434 <source>dd.MM.yyyy</source>
7326 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7327 <translation>дд.ММ.гггг</translation>
7435 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
7436 <translation>dd.MM.yyyy</translation>
73287437 </message>
73297438 <message>
73307439 <source>hh:mm AP</source>
7331 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7440 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
73327441 <translation>hh:mm</translation>
73337442 </message>
73347443 <message>
74747583 </message>
74757584 <message>
74767585 <source>hh:mm:ss AP</source>
7586 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
74777587 <translation>hh:mm:ss</translation>
74787588 </message>
74797589 <message>
75307640 <translation>Сопряжено, но не поддерживается</translation>
75317641 </message>
75327642 <message>
7533 <source>Paired, but unavailable</source>
7534 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7535 <translation>Сопряжено, но недоступно</translation>
7536 </message>
7537 <message>
75387643 <source>Unsupported</source>
75397644 <extracomment>LABEL ALL_PLATFORMS</extracomment>
75407645 <translation>Не поддерживается</translation>
75467651 </message>
75477652 <message>
75487653 <source>dd.MM.yyyy hh:mm AP</source>
7654 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
75497655 <translation>dd.MM.yyyy hh:mm</translation>
75507656 </message>
75517657 <message>
75577663 <source>No smartphone as card reader (Sac) available. Please make sure to activate the &quot;remote service&quot; on your smartphone and to connect both devices to the same WiFi. See %1 for details of use.</source>
75587664 <extracomment>INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network.</extracomment>
75597665 <translation>Нет доступных смартфонов, используемых в качестве устройства чтения карт (SaC). Убедитесь в том, что удаленная служба активирована на вашем смартфоне и оба устройства подключены к одной сети Wi-Fi. Подробную информацию об использовании см. здесь: %1.</translation>
7666 </message>
7667 <message>
7668 <source>Unavailable</source>
7669 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7670 <translation>Недоступно</translation>
7671 </message>
7672 <message>
7673 <source>Click to pair</source>
7674 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7675 <translation>Нажмите для сопряжения</translation>
75607676 </message>
75617677 </context>
75627678 <context>
75897705
75907706 Активируйте NFC, чтобы использовать смартфон в качестве устройства чтения карт (SaC).</translation>
75917707 </message>
7708 <message>
7709 <source>Pairing with %1 successful.</source>
7710 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7711 <translation>Сопряжение с %1 выполнено успешно.</translation>
7712 </message>
75927713 </context>
75937714 <context>
75947715 <name>governikus::RemoteServiceSettings</name>
76127733 </message>
76137734 <message>
76147735 <source>dd.MM.yyyy</source>
7615 <translation>дд.ММ.гггг</translation>
7736 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
7737 <translation>dd.MM.yyyy</translation>
76167738 </message>
76177739 <message>
76187740 <source>xx.MM.yyyy</source>
7619 <translation>хх.ММ.гггг</translation>
7741 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day</extracomment>
7742 <translation>xx.MM.yyyy</translation>
76207743 </message>
76217744 <message>
76227745 <source>xx.xx.yyyy</source>
7623 <translation>хх.хх.гггг</translation>
7746 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month</extracomment>
7747 <translation>xx.xx.yyyy</translation>
76247748 </message>
76257749 <message>
76267750 <source>Family name</source>
77607884 <source>Access denied.</source>
77617885 <extracomment>INFO IOS The current session was interrupted because of a wrong password.</extracomment>
77627886 <translation>Доступ отклонен.</translation>
7887 </message>
7888 </context>
7889 <context>
7890 <name>governikus::StateEstablishPaceChannel</name>
7891 <message>
7892 <source>The secure channel is opened</source>
7893 <extracomment>INFO ALL_PLATFORMS First status message after the PIN was entered.</extracomment>
7894 <translation>Защищенный канал открыт</translation>
77637895 </message>
77647896 </context>
77657897 <context>
80958227 <message>
80968228 <source>The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface.</source>
80978229 <extracomment>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.</extracomment>
8098 <translation type="unfinished">Программа по-прежнему доступна через значок на панели задач. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс.</translation>
8230 <translation>Программа по-прежнему доступна через значок в строке меню. Нажмите на символ %1, чтобы снова открыть пользовательский интерфейс.</translation>
80998231 </message>
81008232 </context>
81018233 </TS>
44 <name>DvcsAttributes</name>
55 <message>
66 <source>revision</source>
7 <translation>efee4b38a0c7</translation>
7 <translation>b9ade3b30f3d</translation>
88 </message>
99 </context>
1010 <context>
177177 <source>Do you know your six-digit ID card PIN?</source>
178178 <translation>Ви знаєте шестизначний PIN-код своєї ID-картки?</translation>
179179 </message>
180 <message>
181 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
182 <extracomment>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.</extracomment>
183 <translation>Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток.</translation>
184 </message>
180185 </context>
181186 <context>
182187 <name>BaseConfirmationPopup</name>
495500 <extracomment>INFO ANDROID IOS The ID card PIN (including the CAN) was entered wrongfully three times, the PUK is required to unlock the ID card.</extracomment>
496501 <translation>Ви тричі ввели неправильний шестизначний PIN-код ID-картки. Тепер PIN-код вашої ID-картки заблоковано. Щоб видалити блокування, потрібно спочатку ввести десятизначний PUK-код.</translation>
497502 </message>
503 <message>
504 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
505 <extracomment>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.</extracomment>
506 <translation>Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток.</translation>
507 </message>
498508 </context>
499509 <context>
500510 <name>ChangePinViewContent</name>
504514 <translation>Якого типу ваш PIN-код?</translation>
505515 </message>
506516 <message>
517 <source>Six-digit PIN</source>
518 <extracomment>LABEL ALL_PLATFORMS</extracomment>
519 <translation>Шестизначний PIN-код</translation>
520 </message>
521 <message>
507522 <source>Set by yourself</source>
508523 <extracomment>LABEL ALL_PLATFORMS</extracomment>
509524 <translation>Встановлений вами самостійно</translation>
510525 </message>
511526 <message>
527 <source>Five-digit Transport PIN</source>
528 <extracomment>LABEL ALL_PLATFORMS</extracomment>
529 <translation>П’ятизначний транспортний PIN-код</translation>
530 </message>
531 <message>
512532 <source>Received by mail in PIN letter</source>
513533 <extracomment>LABEL ALL_PLATFORMS</extracomment>
514534 <translation>Отриманий поштою в листі з PIN-кодом</translation>
522542 <source>Lost, forgotten, or never received it</source>
523543 <extracomment>LABEL ALL_PLATFORMS</extracomment>
524544 <translation>Загубили, забули або ніколи його не отримували</translation>
525 </message>
526 <message>
527 <source>Six-digit PIN</source>
528 <extracomment>LABEL ALL_PLATFORMS</extracomment>
529 <translation type="unfinished">6-значний PIN-код</translation>
530 </message>
531 <message>
532 <source>Five-digit Transport PIN</source>
533 <extracomment>LABEL ALL_PLATFORMS</extracomment>
534 <translation type="unfinished">5-значний транспортний PIN-код</translation>
535545 </message>
536546 </context>
537547 <context>
664674 <message>
665675 <source>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.&lt;br&gt;&lt;br&gt;You can find smartphones compatible with the %1 on our website.</source>
666676 <extracomment>LABEL ANDROID IOS</extracomment>
667 <translation>Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію онлайн-ідентифікації.&lt;br&gt;&lt;br&gt;Ви можете знайти смартфони, сумісні з %1, на нашому сайті.</translation>
677 <translation>Ваш мобільний пристрій не має інтерфейсу NFC. Він потрібен для читання ID-картки. Однак ви можете використовувати окремий смартфон як пристрій читання карток, щоб застосовувати функцію eID.&lt;br&gt;&lt;br&gt;Ви можете знайти смартфони, сумісні з %1, на нашому сайті.</translation>
668678 </message>
669679 <message>
670680 <source>Open website</source>
694704 <message>
695705 <source>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.&lt;br&gt;&lt;br&gt;You can find smartphones compatible with the %1 on our website.</source>
696706 <extracomment>LABEL ANDROID IOS</extracomment>
697 <translation>Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не впливає на це обмеження.&lt;br&gt;&lt;br&gt;Ви можете знайти смартфони, сумісні з %1, на нашому сайті.</translation>
707 <translation>Інтерфейс NFC вашого мобільного пристрою не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження.&lt;br&gt;&lt;br&gt;Ви можете знайти смартфони, сумісні з %1, на нашому сайті.</translation>
698708 </message>
699709 <message>
700710 <source>ID card access failed</source>
984994 <translation>Створення пари з пристроєм…</translation>
985995 </message>
986996 <message>
987 <source>The device &quot;%1&quot; has been paired.</source>
988 <translation>Пару з пристроєм «%1» створено.</translation>
989 </message>
990 <message>
991997 <source>Pairing to &quot;%1&quot; failed:</source>
992998 <extracomment>ERROR DESKTOP An error occurred while pairing the device.</extracomment>
993999 <translation>Не вдалося створити пару з пристроєм «%1»:</translation>
14681474 <translation>Підтвердьте новий шестизначний PIN-код ID-картки.</translation>
14691475 </message>
14701476 <message>
1471 <source>Start the pairing on your smartphone and enter the pairing code shown there in order to use your smartphone as a card reader (SaC).</source>
1472 <extracomment>INFO DESKTOP The pairing code needs to be supplied.</extracomment>
1473 <translation>Щоб використовувати смартфон як пристрій читання карток (SaC), почніть на ньому створення пари та введіть показаний на його екрані код створення пари.</translation>
1474 </message>
1475 <message>
14761477 <source>Unknown password type:</source>
14771478 <extracomment>INFO DESKTOP Error message during PIN/CAN/PUK input procedure, the requested password type is unknown; internal error.</extracomment>
14781479 <translation>Невідомий тип пароля:</translation>
16111612 LABEL ANDROID IOS</extracomment>
16121613 <translation>Надіслати PIN-код ID-картки</translation>
16131614 </message>
1615 <message>
1616 <source>Enter the pairing code shown on your smartphone.</source>
1617 <extracomment>INFO DESKTOP The pairing code needs to be supplied.</extracomment>
1618 <translation>Введіть код створення пари, який відображається на вашому смартфоні.</translation>
1619 </message>
16141620 </context>
16151621 <context>
16161622 <name>GProgressBar</name>
16851691 <context>
16861692 <name>GeneralWorkflow</name>
16871693 <message>
1688 <source>The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
1689 <extracomment>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.</extracomment>
1690 <translation>Пару з пристроєм %1 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток.</translation>
1691 </message>
1692 <message>
16931694 <source>Attempts</source>
16941695 <extracomment>LABEL DESKTOP</extracomment>
16951696 <translation>Спроби</translation>
17521753 <extracomment>INFO DESKTOP</extracomment>
17531754 <translation>Перейти до параметрів пристрою читання</translation>
17541755 </message>
1756 <message>
1757 <source>The device &quot;%1&quot; was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
1758 <extracomment>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.</extracomment>
1759 <translation>Пару з пристроєм «%1» було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток.</translation>
1760 </message>
17551761 </context>
17561762 <context>
17571763 <name>Hint</name>
17641770 <name>HistoryListItem</name>
17651771 <message>
17661772 <source>Click to view details of history entry.</source>
1773 <extracomment>LABEL ANDROID IOS</extracomment>
17671774 <translation>Натисніть, щоб переглянути відомості про запис в історії.</translation>
1768 </message>
1769 <message>
1770 <source>today</source>
1771 <extracomment>LABEL ANDROID IOS</extracomment>
1772 <translation>сьогодні</translation>
1773 </message>
1774 <message>
1775 <source>yesterday</source>
1776 <translation>вчора</translation>
1777 </message>
1778 <message>
1779 <source>dd.MM.yyyy</source>
1780 <translation>дд.ММ.рррр</translation>
17811775 </message>
17821776 <message>
17831777 <source>Tap for more details</source>
18591853 <translation>Пошук в історії</translation>
18601854 </message>
18611855 <message>
1862 <source>today</source>
1863 <translation>сьогодні</translation>
1864 </message>
1865 <message>
1866 <source>yesterday</source>
1867 <translation>вчора</translation>
1868 </message>
1869 <message>
1870 <source>dd.MM.yyyy</source>
1871 <translation>дд.ММ.рррр</translation>
1872 </message>
1873 <message>
18741856 <source>Clear history</source>
18751857 <extracomment>LABEL DESKTOP</extracomment>
18761858 <translation>Очистити історію</translation>
19581940 </message>
19591941 <message>
19601942 <source>dd.MM.yyyy</source>
1961 <translation>дд.ММ.рррр</translation>
1943 <extracomment>LABEL DESKTOP Date format according to https://doc.qt.io/qt/qdate.html#toString
1944 ----------
1945 LABEL ANDROID IOS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
1946 <translation>dd.MM.yyyy</translation>
19621947 </message>
19631948 <message>
19641949 <source>Write access (update)</source>
20522037 <context>
20532038 <name>LocalNetworkInfo</name>
20542039 <message>
2055 <source>To be able to use your smartphone as card reader (SaC), please make sure that access to the local network is allowed.</source>
2056 <extracomment>INFO IOS Let user know to check the application settings for local network permission</extracomment>
2057 <translation>Щоб мати можливість використовувати свій смартфон як пристрій читання карток (SaC), переконайтеся, що доступ до локальної мережі дозволено.</translation>
2058 </message>
2059 <message>
20602040 <source>Go to application settings</source>
20612041 <extracomment>INFO IOS Link to application settings</extracomment>
20622042 <translation>Перейти до параметрів програми</translation>
20632043 </message>
2044 <message>
2045 <source>Ensure that access to the local network is allowed in your settings.</source>
2046 <extracomment>INFO IOS Let user know to check the application settings for local network permission</extracomment>
2047 <translation>Переконайтеся, що доступ до локальної мережі дозволено.</translation>
2048 </message>
20642049 </context>
20652050 <context>
20662051 <name>LogTitleBarControls</name>
21632148 <translation>Фільтр</translation>
21642149 </message>
21652150 <message>
2151 <source>Level</source>
2152 <extracomment>LABEL ANDROID IOS</extracomment>
2153 <translation>Рівень</translation>
2154 </message>
2155 <message>
2156 <source>Category</source>
2157 <extracomment>LABEL ANDROID IOS</extracomment>
2158 <translation>Категорія</translation>
2159 </message>
2160 <message>
21662161 <source>Currently there are no log entries matching your filter.</source>
21672162 <extracomment>INFO ANDROID IOS No log entries, placeholder text.</extracomment>
21682163 <translation>Наразі немає жодних записів журналу, що відповідають цьому фільтру.</translation>
21692164 </message>
2170 <message>
2171 <source>Level</source>
2172 <extracomment>LABEL ANDROID IOS</extracomment>
2173 <translation type="unfinished">Рівень</translation>
2174 </message>
2175 <message>
2176 <source>Category</source>
2177 <extracomment>LABEL ANDROID IOS</extracomment>
2178 <translation type="unfinished">Категорію</translation>
2179 </message>
21802165 </context>
21812166 <context>
21822167 <name>MainView</name>
25762561 <translation>Постачальник</translation>
25772562 </message>
25782563 <message>
2579 <source>Remote</source>
2580 <translation>Віддалений доступ</translation>
2581 </message>
2582 <message>
25832564 <source>Settings</source>
25842565 <translation>Параметри</translation>
25852566 </message>
25862567 <message>
25872568 <source>Help</source>
25882569 <translation>Довідка</translation>
2570 </message>
2571 <message>
2572 <source>Card reader</source>
2573 <translation>Пристрій читання карток</translation>
25892574 </message>
25902575 </context>
25912576 <context>
26222607 </message>
26232608 <message>
26242609 <source>NFC scan is not running.</source>
2625 <extracomment>INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.</extracomment>
2610 <extracomment>INFO ANDROID IOS NFC is available and enabled but needs to be started.</extracomment>
26262611 <translation>Сканування NFC не виконується.</translation>
26272612 </message>
26282613 <message>
26292614 <source>Please start the NFC scan.</source>
2630 <extracomment>INFO ANDROID IOS NFC is available but needs to be activated in the settings of the smartphone.</extracomment>
2615 <extracomment>INFO ANDROID IOS NFC is available and enabled but needs to be started.</extracomment>
26312616 <translation>Почніть сканування NFC.</translation>
26322617 </message>
26332618 <message>
26652650 <extracomment>INFO ANDROID The ID card may be inserted, the authentication process may be started.</extracomment>
26662651 <translation>Покладіть ID-картку безпосередньо на задній бік пристрою.&lt;br/&gt;&lt;br/&gt;Точне положення ID-картки залежить від пристрою. На анімації показано можливі положення. Утримуйте ID-картку в одному положенні кілька секунд, перш ніж спробувати інше, і не переміщайте її після встановлення контакту.</translation>
26672652 </message>
2653 <message>
2654 <source>The device &quot;%1&quot; wants to use this smartphone as card reader and connect to your id card.</source>
2655 <extracomment>INFO ANDROID IOS %1 will be replaced with the name of the device.</extracomment>
2656 <translation>Пристрій «%1» намагається використовувати цей смартфон як пристрій читання карток і встановити з’єднання з вашою ID-карткою.</translation>
2657 </message>
26682658 </context>
26692659 <context>
26702660 <name>NumberField</name>
27272717 </message>
27282718 </context>
27292719 <context>
2720 <name>PairingCodeInfoView</name>
2721 <message>
2722 <source>Pairing Information</source>
2723 <extracomment>LABEL ANDROID IOS</extracomment>
2724 <translation>Інформація про створення пари</translation>
2725 </message>
2726 <message>
2727 <source>Open %1 on your %2other device%3.</source>
2728 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 3</extracomment>
2729 <translation>Відкрийте %1 на своєму %2іншому пристрої%3.</translation>
2730 </message>
2731 <message>
2732 <source>On that device go to %1Settings%2 and then %1Smartphone as card reader%2 resp. %1Manage pairings%2.</source>
2733 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 3. %1 and %2 are surrounding tags for bold font.</extracomment>
2734 <translation>Перейдіть на тому пристрої до розділу %1Параметри%2, а тоді виберіть %1Смартфон як пристрій читання карток%2 і %1Керування створенням пари%2.</translation>
2735 </message>
2736 <message>
2737 <source>Choose this smartphone in the list to pair it.</source>
2738 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 3</extracomment>
2739 <translation>Виберіть цей смартфон у переліку, щоб створити з ним пару.</translation>
2740 </message>
2741 </context>
2742 <context>
2743 <name>PairingProcessInfo</name>
2744 <message>
2745 <source>Open %1 on your smartphone as card reader.</source>
2746 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.</extracomment>
2747 <translation>Відкрийте %1 на своєму смартфоні як пристрій читання карток.</translation>
2748 </message>
2749 <message>
2750 <source>On that device choose %1Card reader%2 and then %1Pair device%2 resp. %1Pair new device%2.</source>
2751 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font.</extracomment>
2752 <translation>Виберіть на тому пристрої %1Пристрій читання карток%2, а тоді — %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2.</translation>
2753 </message>
2754 <message>
2755 <source>Choose the smartphone in the list shown here to pair it.</source>
2756 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4</extracomment>
2757 <translation>У наведеному тут переліку виберіть смартфон, щоб створити з ним пару.</translation>
2758 </message>
2759 <message>
2760 <source>Ensure that the %1 on your Smartphone as card reader has at least version %2.</source>
2761 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.</extracomment>
2762 <translation>Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2.</translation>
2763 </message>
2764 </context>
2765 <context>
27302766 <name>PasswordInfoContent</name>
27312767 <message>
27322768 <source>More information</source>
27472783 <translation>Інформація про PIN-код</translation>
27482784 </message>
27492785 <message>
2786 <source>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.</source>
2787 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;what is the card pin?&apos;</extracomment>
2788 <translation>PIN-код картки – це шестизначний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID.</translation>
2789 </message>
2790 <message>
27502791 <source>Where can I find the card PIN?</source>
27512792 <extracomment>LABEL ALL_PLATFORMS</extracomment>
27522793 <translation>Де я можу дізнатися PIN-код картки?</translation>
27532794 </message>
27542795 <message>
2796 <source>You set the card PIN either directly when you picked up your ID card at the citizens&apos; 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.</source>
2797 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the card PIN?&apos;</extracomment>
2798 <translation>Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою п’ятизначного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення шестизначного PIN-коду.</translation>
2799 </message>
2800 <message>
27552801 <source>How do I choose a secure PIN?</source>
27562802 <extracomment>LABEL ALL_PLATFORMS</extracomment>
27572803 <translation>Як вибрати безпечний PIN-код?</translation>
2804 </message>
2805 <message>
2806 <source>For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither &quot;123456&quot;, nor your date of birth, nor any other numbers printed on your ID card.</source>
2807 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 1/3</extracomment>
2808 <translation>Для свого шестизначного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці.</translation>
2809 </message>
2810 <message>
2811 <source>You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN.</source>
2812 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 2/3</extracomment>
2813 <translation>Ви можете змінювати свій шестизначний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код.</translation>
27582814 </message>
27592815 <message>
27602816 <source>Keep your PIN secret and change it if another person becomes aware of it.</source>
27722828 <translation>Інформація про транспортний PIN-код</translation>
27732829 </message>
27742830 <message>
2831 <source>The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card.</source>
2832 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 1/3</extracomment>
2833 <translation>П’ятизначний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки.</translation>
2834 </message>
2835 <message>
2836 <source>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.</source>
2837 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 2/3</extracomment>
2838 <translation>Якщо ви не встановили самостійно обраний шестизначний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду.</translation>
2839 </message>
2840 <message>
27752841 <source>Once you have set a card PIN, the Transport PIN loses its validity.</source>
27762842 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 3/3</extracomment>
27772843 <translation>Після встановлення PIN-коду картки транспортний PIN-код втрачає чинність.</translation>
28022868 <translation>Інформація про PUK-код</translation>
28032869 </message>
28042870 <message>
2871 <source>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.</source>
2872 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where do I find the PUK?&apos;</extracomment>
2873 <translation>PUK-код – це десятизначний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки.</translation>
2874 </message>
2875 <message>
28052876 <source>Why is the PUK required?</source>
28062877 <extracomment>LABEL ALL_PLATFORMS</extracomment>
28072878 <translation>Навіщо потрібен PUK-код?</translation>
28572928 <translation>Де я можу дізнатися CAN-код картки?</translation>
28582929 </message>
28592930 <message>
2931 <source>The CAN is a six-digit number that can be found on the bottom right of the front of the ID card.</source>
2932 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the CAN?&apos;</extracomment>
2933 <translation>CAN-код – це шестизначний номер, який можна знайти в нижній правій частині лицьового боку ID-картки.</translation>
2934 </message>
2935 <message>
28602936 <source>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).</source>
28612937 <extracomment>INFO ALL_PLATFORMS Description text of CAN-allowed authentication</extracomment>
28622938 <translation>Номер доступу до картки (CAN) дає змогу отримати доступ до вихідних даних ID-картки. CAN – це шестизначний номер, який можна знайти на лицьовій стороні ID-картки. Він розташований унизу праворуч від терміну дії (позначено червоним).</translation>
28892965 <translation>Ви не знаєте свій PIN-код?</translation>
28902966 </message>
28912967 <message>
2968 <source>You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN?</source>
2969 <extracomment>INFO ALL_PLATFORMS</extracomment>
2970 <translation>Ви ще не встановили шестизначний PIN-код картки й не можете знайти лист із транспортним PIN-кодом?</translation>
2971 </message>
2972 <message>
28922973 <source>You set a card PIN when picking up your ID card or later by yourself, but you can no longer remember it?</source>
28932974 <extracomment>INFO ALL_PLATFORMS</extracomment>
28942975 <translation>Ви встановили PIN-код картки під час отримання ID-картки або пізніше самостійно, але вже не пам’ятаєте його?</translation>
29042985 <translation>Типи PIN-кодів</translation>
29052986 </message>
29062987 <message>
2988 <source>Your ID card comes with a five-digit &apos;Transport PIN&apos; which you need to replace with a six-digit PIN that you choose yourself.</source>
2989 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 1/6</extracomment>
2990 <translation>До вашої ID-картки додається п’ятизначний « PIN-код», який вам потрібно змінити на шестизначний PIN-код, який ви обираєте самостійно.</translation>
2991 </message>
2992 <message>
2993 <source>Five-digit Transport PIN</source>
2994 <extracomment>LABEL ALL_PLATFORMS</extracomment>
2995 <translation>П’ятизначний транспортний PIN-код</translation>
2996 </message>
2997 <message>
2998 <source>The five-digit Transport PIN was sent to you by post after you applied for your ID card.</source>
2999 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 2/6</extracomment>
3000 <translation>П’ятизначний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки.</translation>
3001 </message>
3002 <message>
3003 <source>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.</source>
3004 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 3/6</extracomment>
3005 <translation>Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей п’ятизначний PIN-код на шестизначний PIN-код, який ви оберете самостійно.</translation>
3006 </message>
3007 <message>
3008 <source>Six-digit PIN</source>
3009 <extracomment>LABEL ALL_PLATFORMS</extracomment>
3010 <translation>Шестизначний PIN-код</translation>
3011 </message>
3012 <message>
3013 <source>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.</source>
3014 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 4/6</extracomment>
3015 <translation>Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш п’ятизначний транспортний PIN-код.</translation>
3016 </message>
3017 <message>
29073018 <source>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.</source>
29083019 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 5/6</extracomment>
29093020 <translation>Цей PIN-код дозволяє вам підтверджувати онлайн, що ID-картка належить саме вам. Без цього PIN-коду ніхто не зможе скористатися вашою ID-карткою в Інтернеті.</translation>
29103021 </message>
29113022 <message>
3023 <source>You can change your six-digit PIN at any time in AusweisApp2.</source>
3024 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 6/6</extracomment>
3025 <translation>Ви можете в будь-який момент змінити свій шестизначний PIN-код у додатку AusweisApp2.</translation>
3026 </message>
3027 <message>
29123028 <source>You can use the PIN Reset Service to request a new card PIN free of charge.</source>
29133029 <extracomment>LABEL ALL_PLATFORMS</extracomment>
29143030 <translation>Ви можете скористатися службою скидання PIN-коду, щоб безкоштовно надіслати запит на новий PIN-код картки.</translation>
29233039 <extracomment>LABEL ALL_PLATFORMS Hint text for PIN but it is unknown.</extracomment>
29243040 <translation>Якщо ви забули PIN-код картки, ви можете безкоштовно надіслати запит на новий PIN-код, скориставшись службою скидання PIN-коду.</translation>
29253041 </message>
2926 <message>
2927 <source>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.</source>
2928 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;what is the card pin?&apos;</extracomment>
2929 <translation type="unfinished">PIN-код картки – це 6-значний PIN-код, який ви встановлюєте самостійно. Цей PIN-код обов’язковий, якщо ви хочете використовувати функцію eID.</translation>
2930 </message>
2931 <message>
2932 <source>You set the card PIN either directly when you picked up your ID card at the citizens&apos; 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.</source>
2933 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the card PIN?&apos;</extracomment>
2934 <translation type="unfinished">Ви встановлюєте PIN-код картки безпосередньо під час отримання ID-картки у відділі обслуговування громадян (Bürgeramt) або пізніше в додатку AusweisApp2 за допомогою 5-значного транспортного PIN-коду. Використовувати функцію eID можна лише після самостійного встановлення 6-значного PIN-коду.</translation>
2935 </message>
2936 <message>
2937 <source>For your six-digit PIN, choose a combination of numbers that cannot be guessed - i.e. neither &quot;123456&quot;, nor your date of birth, nor any other numbers printed on your ID card.</source>
2938 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 1/3</extracomment>
2939 <translation type="unfinished">Для свого 6-значного PIN-коду виберіть комбінацію цифр, яку неможливо вгадати. Наприклад, не використовуйте ані послідовність цифр «123456», ані дату народження, ані жодні інші числа, надруковані на вашій ID-картці.</translation>
2940 </message>
2941 <message>
2942 <source>You can change your six-digit PIN at any time and an unlimited number of times as long as you know your valid PIN.</source>
2943 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;How do I choose a secure PIN?&apos; paragraph 2/3</extracomment>
2944 <translation type="unfinished">Ви можете змінювати свій 6-значний PIN-код у будь-який час і необмежену кількість разів, якщо ви знаєте свій дійсний PIN-код.</translation>
2945 </message>
2946 <message>
2947 <source>The five-digit Transport PIN was sent to you in the PIN letter by mail after you applied for your ID card.</source>
2948 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 1/3</extracomment>
2949 <translation type="unfinished">5-значний транспортний PIN-код був надісланий вам у листі з PIN-кодом поштою після того, як ви подали заяву на отримання ID-картки.</translation>
2950 </message>
2951 <message>
2952 <source>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.</source>
2953 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;What is the Transport PIN?&apos; paragraph 2/3</extracomment>
2954 <translation type="unfinished">Якщо ви не встановили самостійно обраний 6-значний PIN-код картки, коли забирали ID-картку, ви можете зробити це за допомогою транспортного PIN-коду.</translation>
2955 </message>
2956 <message>
2957 <source>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.</source>
2958 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where do I find the PUK?&apos;</extracomment>
2959 <translation type="unfinished">PUK-код – це 10-значний номер, який ви можете знайти в листі з PIN-кодом, надісланому вам поштою після того, як ви подали заяву на отримання ID-картки.</translation>
2960 </message>
2961 <message>
2962 <source>The CAN is a six-digit number that can be found on the bottom right of the front of the ID card.</source>
2963 <extracomment>INFO ALL_PLATFORMS Answer to the question &apos;Where can I find the CAN?&apos;</extracomment>
2964 <translation type="unfinished">CAN-код – це 6-значний номер, який можна знайти в нижній правій частині лицьового боку ID-картки.</translation>
2965 </message>
2966 <message>
2967 <source>Your ID card comes with a five-digit &apos;Transport PIN&apos; which you need to replace with a six-digit PIN that you choose yourself.</source>
2968 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 1/6</extracomment>
2969 <translation type="unfinished">До вашої ID-картки додається 5-значний «транспортний PIN-код», який вам потрібно змінити на 6-значний PIN-код, який ви обираєте самостійно.</translation>
2970 </message>
2971 <message>
2972 <source>Five-digit Transport PIN</source>
2973 <extracomment>LABEL ALL_PLATFORMS</extracomment>
2974 <translation type="unfinished">5-значний транспортний PIN-код</translation>
2975 </message>
2976 <message>
2977 <source>The five-digit Transport PIN was sent to you by post after you applied for your ID card.</source>
2978 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 2/6</extracomment>
2979 <translation type="unfinished">5-значний транспортний PIN-код був надісланий вам у листі поштою після того, як ви подали заяву на отримання ID-картки.</translation>
2980 </message>
2981 <message>
2982 <source>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.</source>
2983 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 3/6</extracomment>
2984 <translation type="unfinished">Цей PIN-код можна використати лише один раз. Коли ви налаштуєте функцію eID, ви заміните цей 5-значний PIN-код на 6-значний PIN-код, який ви оберете самостійно.</translation>
2985 </message>
2986 <message>
2987 <source>Six-digit PIN</source>
2988 <extracomment>LABEL ALL_PLATFORMS</extracomment>
2989 <translation type="unfinished">6-значний PIN-код</translation>
2990 </message>
2991 <message>
2992 <source>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.</source>
2993 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 4/6</extracomment>
2994 <translation type="unfinished">Це код, який ви обираєте самостійно, коли вперше налаштовуєте функцію eID. Він замінює ваш 5-значний транспортний PIN-код.</translation>
2995 </message>
2996 <message>
2997 <source>You can change your six-digit PIN at any time in AusweisApp2.</source>
2998 <extracomment>INFO ALL_PLATFORMS Description text explaining the PINs 6/6</extracomment>
2999 <translation type="unfinished">Ви можете в будь-який момент змінити свій 6-значний PIN-код у додатку AusweisApp2.</translation>
3000 </message>
3001 <message>
3002 <source>You have not yet set a six-digit card PIN and cannot find the PIN letter with the Transport PIN?</source>
3003 <extracomment>INFO ALL_PLATFORMS</extracomment>
3004 <translation type="unfinished">Ви ще не встановили 6-значний PIN-код картки й не можете знайти лист із транспортним PIN-кодом?</translation>
3005 </message>
30063042 </context>
30073043 <context>
30083044 <name>PersonalizationController</name>
33153351 <context>
33163352 <name>ProviderDetailHistoryItem</name>
33173353 <message>
3318 <source>today</source>
3319 <extracomment>LABEL ANDROID IOS</extracomment>
3320 <translation>сьогодні</translation>
3321 </message>
3322 <message>
3323 <source>yesterday</source>
3324 <translation>вчора</translation>
3325 </message>
3326 <message>
3327 <source>dd.MM.yyyy</source>
3328 <translation>дд.ММ.рррр</translation>
3329 </message>
3330 <message>
33313354 <source>Service:</source>
33323355 <extracomment>LABEL DESKTOP</extracomment>
33333356 <translation>Служба:</translation>
35903613 <translation>Натисніть пробіл, щоб створити пару зі смартфоном «%1».</translation>
35913614 </message>
35923615 <message>
3593 <source>Click to pair</source>
3594 <translation>Натисніть, щоб створити пару</translation>
3595 </message>
3596 <message>
35973616 <source>Remove remote device</source>
35983617 <translation>Видаліть віддалений пристрій</translation>
35993618 </message>
36013620 <context>
36023621 <name>RemoteReaderView</name>
36033622 <message>
3604 <source>Paired remote devices</source>
3605 <translation>З’єднані віддалені пристрої</translation>
3606 </message>
3607 <message>
3608 <source>Available remote devices</source>
3609 <translation>Доступні віддалені пристрої</translation>
3610 </message>
3611 <message>
3612 <source>Only devices that are already paired or are connected to the same WiFi network and have the remote service enabled are shown here.</source>
3613 <translation>Тут відображаються лише пристрої, які вже з’єднано або підключено до однієї мережі Wi-Fi і для яких увімкнено віддалену службу.</translation>
3614 </message>
3615 <message>
3616 <source>More information</source>
3617 <extracomment>LABEL DESKTOP</extracomment>
3618 <translation>Додаткова інформація</translation>
3623 <source>Paired devices</source>
3624 <translation>З’єднані пристрої</translation>
3625 </message>
3626 <message>
3627 <source>Add pairing</source>
3628 <translation>Додавання пари</translation>
3629 </message>
3630 <message>
3631 <source>Open the %1 on your Smartphone as card reader.</source>
3632 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 2 of 4. %1 is a placeholder-tag for the app name.</extracomment>
3633 <translation>Відкрийте %1 на своєму смартфоні як пристрій читання карток.</translation>
3634 </message>
3635 <message>
3636 <source>Both devices have to be connected to the same WiFi.</source>
3637 <translation>Обидва пристрої мають бути підключені до однієї мережі Wi-Fi.</translation>
3638 </message>
3639 <message>
3640 <source>On that device go to %1Card reader%2 and then %1Pair device%2 rsp. %1Pair new device%2.</source>
3641 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 3 of 4. %1 and %2 are surrounding tags for bold font</extracomment>
3642 <translation>Перейдіть на тому пристрої до розділу %1Пристрій читання карток%2, а тоді виберіть %1Створити пару з пристроєм%2 і %1Створити пару з новим пристроєм%2.</translation>
3643 </message>
3644 <message>
3645 <source>Choose the device in the list to pair it.</source>
3646 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 4 of 4</extracomment>
3647 <translation>Виберіть пристрій у переліку, щоб створити з ним пару.</translation>
3648 </message>
3649 <message>
3650 <source>Last connected</source>
3651 <translation>Останнє з’єднання</translation>
3652 </message>
3653 <message>
3654 <source>Ensure that the %1 on your Smartphone as card reader has at least version %2.</source>
3655 <extracomment>LABEL ANDROID IOS Assistance text for pairing new devices. Step 1 of 4. %1 is a placeholder-tag for the app name.</extracomment>
3656 <translation>Переконайтеся, що %1 на вашому смартфоні як пристрiй читання карток має версію не нижче %2.</translation>
3657 </message>
3658 </context>
3659 <context>
3660 <name>RemoteServiceController</name>
3661 <message>
3662 <source>You are about to identify yourself towards the following provider using the device &quot;%1&quot;:</source>
3663 <extracomment>LABEL ANDROID IOS</extracomment>
3664 <translation>Ви збираєтеся ідентифікувати себе за допомогою пристрою «%1» для такого постачальника:</translation>
3665 </message>
3666 <message>
3667 <source>Card reader</source>
3668 <extracomment>LABEL ANDROID IOS</extracomment>
3669 <translation>Пристрій читання карток</translation>
3670 </message>
3671 <message>
3672 <source>Remote service</source>
3673 <extracomment>LABEL ANDROID IOS</extracomment>
3674 <translation>Віддалена служба</translation>
36193675 </message>
36203676 </context>
36213677 <context>
36223678 <name>RemoteServiceSettings</name>
36233679 <message>
3624 <source>Configure remote service</source>
3625 <extracomment>LABEL ANDROID IOS</extracomment>
3626 <translation>Налаштувати віддалену службу</translation>
3680 <source>Manage pairings</source>
3681 <extracomment>LABEL ANDROID IOS</extracomment>
3682 <translation>Керування створенням пари</translation>
36273683 </message>
36283684 </context>
36293685 <context>
36303686 <name>RemoteServiceView</name>
3631 <message>
3632 <source>Remote service</source>
3633 <extracomment>LABEL ANDROID IOS</extracomment>
3634 <translation>Віддалена служба</translation>
3635 </message>
36363687 <message>
36373688 <source>Pairing failed. Please start a new pairing process on your other device and enter the shown pairing code.</source>
36383689 <extracomment>ERROR ANDROID IOS An error occurred while pairing the device.</extracomment>
36643715 <translation>Очікування підключення</translation>
36653716 </message>
36663717 <message>
3667 <source>Remote service ready</source>
3668 <extracomment>LABEL ANDROID IOS</extracomment>
3669 <translation>Віддалена служба готова</translation>
3670 </message>
3671 <message>
36723718 <source>Waiting for connection from a paired device...</source>
36733719 <extracomment>INFO ANDROID IOS</extracomment>
36743720 <translation>Очікування підключення від пристрою, з яким створено пару…</translation>
36753721 </message>
36763722 <message>
3677 <source>Start the remote access in order to make this smartphone visible and use it as a card reader (SaC).
3723 <source>Pairing code: &lt;b&gt;%1&lt;/b&gt;</source>
3724 <extracomment>LABEL ANDROID IOS</extracomment>
3725 <translation>Код створення пари: &lt;b&gt;%1&lt;/b&gt;</translation>
3726 </message>
3727 <message>
3728 <source>Enable WiFi</source>
3729 <extracomment>LABEL ANDROID IOS</extracomment>
3730 <translation>Увімкнути Wi-Fi</translation>
3731 </message>
3732 <message>
3733 <source>Enable NFC</source>
3734 <extracomment>LABEL ANDROID IOS</extracomment>
3735 <translation>Увімкнути NFC</translation>
3736 </message>
3737 <message>
3738 <source>Pair device</source>
3739 <extracomment>LABEL ANDROID IOS</extracomment>
3740 <translation>Створити пару з пристроєм</translation>
3741 </message>
3742 <message>
3743 <source>Allow connection</source>
3744 <extracomment>LABEL ANDROID IOS</extracomment>
3745 <translation>Дозволити з’єднання</translation>
3746 </message>
3747 <message>
3748 <source>You can use this Smartphone as a card reader for the %1 on other devices e.g. a laptop.
36783749
3679 If you have not already paired a device, start the pairing now to set up this smartphone as a card reader.</source>
3750 To do this you first have to pair that device with this smartphone.</source>
36803751 <extracomment>INFO ANDROID IOS</extracomment>
3681 <translation>Запустіть віддалений доступ, щоб зробити цей смартфон видимим і використовувати його як пристрій читання карток (SaC).
3752 <translation>Ви можете використовувати цей смартфон як пристрій читання карток для %1 на інших пристроях, наприклад, на ноутбуці.
36823753
3683 Якщо ви ще не створили пару для пристрою, почніть створення пари зараз, щоб налаштувати цей смартфон як пристрій читання карток.</translation>
3684 </message>
3685 <message>
3686 <source>Pairing code: &lt;b&gt;%1&lt;/b&gt;</source>
3687 <extracomment>LABEL ANDROID IOS</extracomment>
3688 <translation>Код створення пари: &lt;b&gt;%1&lt;/b&gt;</translation>
3689 </message>
3690 <message>
3691 <source>Both of your devices have to be connected to the same WiFi.</source>
3692 <extracomment>INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.</extracomment>
3693 <translation>Обидва ваші пристрої має бути підключено до однієї мережі Wi-Fi.</translation>
3694 </message>
3695 <message>
3696 <source>Enable WiFi</source>
3697 <extracomment>LABEL ANDROID IOS</extracomment>
3698 <translation>Увімкнути Wi-Fi</translation>
3699 </message>
3700 <message>
3701 <source>Enable NFC</source>
3702 <extracomment>LABEL ANDROID IOS</extracomment>
3703 <translation>Увімкнути NFC</translation>
3704 </message>
3705 <message>
3706 <source>Stop remote service</source>
3707 <extracomment>LABEL ANDROID IOS</extracomment>
3708 <translation>Зупинити віддалену службу</translation>
3709 </message>
3710 <message>
3711 <source>Start remote service</source>
3712 <extracomment>LABEL ANDROID IOS</extracomment>
3713 <translation>Запустити віддалену службу</translation>
3714 </message>
3715 <message>
3716 <source>Stop pairing</source>
3717 <extracomment>LABEL ANDROID IOS</extracomment>
3718 <translation>Зупинити створення пари</translation>
3719 </message>
3720 <message>
3721 <source>Start pairing</source>
3722 <extracomment>LABEL ANDROID IOS</extracomment>
3723 <translation>Почати створення пари</translation>
3724 </message>
3725 <message>
3726 <source>Enter the code %1 in the %2 on your other device to use your smartphone as a card reader (SaC).</source>
3754 Для цього вам потрібно спочатку створити пару між таким пристроєм і цим смартфоном.</translation>
3755 </message>
3756 <message>
3757 <source>Card reader</source>
3758 <extracomment>LABEL ANDROID IOS</extracomment>
3759 <translation>Пристрій читання карток</translation>
3760 </message>
3761 <message>
3762 <source>Paired Devices</source>
37273763 <extracomment>INFO ANDROID IOS</extracomment>
3728 <translation>Введіть код %1 у %2 на своєму іншому пристрої, щоб використовувати свій смартфон як пристрій читання карток (SaC).</translation>
3764 <translation>З’єднані пристрої</translation>
3765 </message>
3766 <message>
3767 <source>Pair new device</source>
3768 <extracomment>LABEL ANDROID IOS</extracomment>
3769 <translation>Створення пари з новим пристроєм</translation>
3770 </message>
3771 <message>
3772 <source>Waiting for pairing</source>
3773 <extracomment>LABEL ANDROID IOS</extracomment>
3774 <translation>Очікування на створення пари</translation>
3775 </message>
3776 <message>
3777 <source>Start pairing of a new device</source>
3778 <extracomment>LABEL ANDROID IOS</extracomment>
3779 <translation>Почати створення пари з новим пристроєм</translation>
3780 </message>
3781 <message>
3782 <source>Where do I enter the pairing code?</source>
3783 <extracomment>LABEL ANDROID IOS</extracomment>
3784 <translation>Куди вводити код створення пари?</translation>
3785 </message>
3786 <message>
3787 <source>Enter the pairing code %1 in the %2 on your other device.</source>
3788 <extracomment>INFO ANDROID IOS</extracomment>
3789 <translation>Введіть код створення пари %1 у %2 на своєму іншому пристрої.</translation>
3790 </message>
3791 <message>
3792 <source>Cancel pairing</source>
3793 <extracomment>LABEL ANDROID IOS</extracomment>
3794 <translation>Скасувати створення пари</translation>
3795 </message>
3796 <message>
3797 <source>Allow a connection with paired devices to use this Smartphone as a card reader or pair another device.</source>
3798 <extracomment>INFO ANDROID IOS</extracomment>
3799 <translation>Надайте дозвіл на встановлення зв’язку зі з’єднаними пристроями, щоб використовувати цей смартфон як пристрій читання карток або створити пару з іншим пристроєм.</translation>
3800 </message>
3801 <message>
3802 <source>Paired devices may use this Smartphone as a card reader now.</source>
3803 <extracomment>INFO ANDROID IOS</extracomment>
3804 <translation>Тепер з’єднані пристрої можуть використовувати цей смартфон як пристрій читання карток.</translation>
37293805 </message>
37303806 </context>
37313807 <context>
37323808 <name>RemoteServiceViewRemote</name>
3733 <message>
3734 <source>Paired devices</source>
3735 <extracomment>LABEL ANDROID IOS</extracomment>
3736 <translation>З’єднані пристрої</translation>
3737 </message>
3738 <message>
3739 <source>No device is paired.</source>
3740 <extracomment>LABEL ANDROID IOS</extracomment>
3741 <translation>Із жодним пристроєм не створено пару.</translation>
3742 </message>
3743 <message>
3744 <source>Click to remove device</source>
3745 <extracomment>LABEL ANDROID IOS</extracomment>
3746 <translation>Натисніть, щоб видалити пристрій</translation>
3747 </message>
37483809 <message>
37493810 <source>Remove pairing</source>
37503811 <extracomment>INFO ANDROID IOS</extracomment>
37613822 <translation>Видалити</translation>
37623823 </message>
37633824 <message>
3764 <source>Available devices</source>
3765 <extracomment>LABEL ANDROID IOS</extracomment>
3766 <translation>Доступні пристрої</translation>
3767 </message>
3768 <message>
3769 <source>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.</source>
3770 <extracomment>INFO ANDROID IOS No SaC was found on the network, both devices need to be connected to the same WiFi network.</extracomment>
3771 <translation>Немає жодного з’єднаного смартфона як пристрою читання карток (SaC). Переконайтеся, що функцію смартфона як пристрою для читання карток (SaC) активовано в програмі AusweisApp2 на вашому іншому пристрої і що обидва пристрої підключено до однієї мережі Wi-Fi.</translation>
3772 </message>
3773 <message>
37743825 <source>Please connect your WiFi to use another smartphone as card reader (SaC).</source>
37753826 <extracomment>INFO ANDROID IOS Wifi is not enabled and no new devices can be paired.</extracomment>
37763827 <translation>Підключіть Wi-Fi, щоб використовувати інший смартфон як пристрій читання карток (SaC).</translation>
37813832 <translation>Увімкнути Wi-Fi</translation>
37823833 </message>
37833834 <message>
3835 <source>Pairing code</source>
3836 <extracomment>LABEL ANDROID IOS</extracomment>
3837 <translation>Код створення пари</translation>
3838 </message>
3839 <message>
3840 <source>Add pairing</source>
3841 <extracomment>LABEL ANDROID IOS</extracomment>
3842 <translation>Додавання пари</translation>
3843 </message>
3844 <message>
3845 <source>Click to remove device</source>
3846 <extracomment>LABEL ANDROID IOS</extracomment>
3847 <translation>Натисніть, щоб видалити пристрій</translation>
3848 </message>
3849 <message>
3850 <source>Last connected</source>
3851 <extracomment>LABEL ANDROID IOS</extracomment>
3852 <translation>Останнє з’єднання</translation>
3853 </message>
3854 <message>
3855 <source>Available</source>
3856 <extracomment>LABEL ANDROID IOS</extracomment>
3857 <translation>Доступно</translation>
3858 </message>
3859 <message>
3860 <source>Paired devices</source>
3861 <extracomment>LABEL ANDROID IOS</extracomment>
3862 <translation>З’єднані пристрої</translation>
3863 </message>
3864 <message>
37843865 <source>Click to pair</source>
37853866 <extracomment>LABEL ANDROID IOS</extracomment>
37863867 <translation>Натисніть, щоб створити пару</translation>
37873868 </message>
3788 <message>
3789 <source>Pairing mode</source>
3790 <extracomment>INFO ANDROID IOS</extracomment>
3791 <translation>Режим створення пари</translation>
3792 </message>
3793 <message>
3794 <source>Start the pairing mode on your smartphone if you haven&apos;t done it already.</source>
3795 <extracomment>INFO ANDROID IOS Information dialog that requests the user to start the pairing mode on the smartphone.</extracomment>
3796 <translation>Запустіть режим створення пари на своєму смартфоні, якщо ви ще цього не зробили.</translation>
3797 </message>
3798 <message>
3799 <source>Pairing code</source>
3800 <extracomment>LABEL ANDROID IOS</extracomment>
3801 <translation>Код створення пари</translation>
3869 </context>
3870 <context>
3871 <name>RemoteServiceWifiInfo</name>
3872 <message>
3873 <source>Both devices have to be connected to the same WiFi.</source>
3874 <extracomment>INFO ANDROID IOS The remote service is active. Hint that both devices need to be connected to the same network.</extracomment>
3875 <translation>Обидва пристрої мають бути підключені до однієї мережі Wi-Fi.</translation>
38023876 </message>
38033877 </context>
38043878 <context>
38053879 <name>RemoteWorkflow</name>
38063880 <message>
3807 <source>The device %1 was unpaired because it did not react to connection attempts. Pair the device again to use it as a card reader.</source>
3808 <extracomment>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.</extracomment>
3809 <translation>Пару з пристроєм %1 було скасовано, оскільки він не реагував на спроби підключення. Створіть пару з пристроєм знову, щоб використовувати його як пристрій читання карток.</translation>
3810 </message>
3811 <message>
38123881 <source>Enable WiFi</source>
38133882 <extracomment>LABEL ANDROID IOS</extracomment>
38143883 <translation>Увімкнути Wi-Fi</translation>
3815 </message>
3816 <message>
3817 <source>Pair device</source>
3818 <extracomment>LABEL ANDROID IOS</extracomment>
3819 <translation>Створити пару з пристроєм</translation>
38203884 </message>
38213885 <message>
38223886 <source>To use the remote service WiFi has to be activated. Please activate WiFi in your device settings.</source>
38243888 <translation>Для використання віддаленої служби має бути активовано Wi-Fi. Активуйте Wi-Fi у параметрах пристрою.</translation>
38253889 </message>
38263890 <message>
3827 <source>No paired smartphone as card reader (SaC) with activated &quot;remote service&quot; available.</source>
3828 <extracomment>INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.</extracomment>
3829 <translation>Немає жодного з’єднаного смартфона як пристрою читання карток (SaC) з активованою «віддаленою службою».</translation>
3830 </message>
3831 <message>
38323891 <source>Wifi disabled</source>
38333892 <extracomment>LABEL ANDROID IOS</extracomment>
38343893 <translation>Wi-Fi вимкнено</translation>
3835 </message>
3836 <message>
3837 <source>Waiting for connection</source>
3838 <extracomment>LABEL ANDROID IOS</extracomment>
3839 <translation>Очікування підключення</translation>
38403894 </message>
38413895 <message>
38423896 <source>Determine card</source>
38533907 <extracomment>INFO ANDROID IOS The connection to the smartphone was established, the ID card may be inserted.</extracomment>
38543908 <translation>Підключено до %1. Розташуйте інтерфейс NFC смартфона на своїй ID-картці.</translation>
38553909 </message>
3910 <message>
3911 <source>Manage pairings</source>
3912 <extracomment>LABEL ANDROID IOS</extracomment>
3913 <translation>Керування створенням пари</translation>
3914 </message>
3915 <message>
3916 <source>No smartphone as card reader connected</source>
3917 <extracomment>LABEL ANDROID IOS</extracomment>
3918 <translation>Не з’єднано жоден смартфон як пристрій читання карток</translation>
3919 </message>
3920 <message>
3921 <source>Allow a connection on a paired smartphone or pair a new smartphone.</source>
3922 <extracomment>INFO ANDROID IOS No paired and reachable device was found, hint that the remote device needs to be actually started for this feature.</extracomment>
3923 <translation>Надайте дозвіл на встановлення зв’язку на з’єднаному смартфоні або створіть пару з новим смартфоном.</translation>
3924 </message>
38563925 </context>
38573926 <context>
38583927 <name>ResultErrorView</name>
42484317 <translation>Введіть PIN-код на цьому пристрої</translation>
42494318 </message>
42504319 <message>
4251 <source>Remote card reader</source>
4252 <extracomment>LABEL ANDROID IOS</extracomment>
4253 <translation>Віддалений пристрій читання карток</translation>
4254 </message>
4255 <message>
4256 <source>Configure remote service for another device</source>
4257 <extracomment>LABEL ANDROID IOS</extracomment>
4258 <translation>Налаштувати віддалену службу для іншого пристрою</translation>
4259 </message>
4260 <message>
42614320 <source>Save history</source>
42624321 <extracomment>LABEL ANDROID IOS</extracomment>
42634322 <translation>Зберегти історію</translation>
43734432 <source>15 days old Logfile</source>
43744433 <extracomment>LABEL ALL_PLATFORMS</extracomment>
43754434 <translation>Файл журналу строком 15 днів</translation>
4435 </message>
4436 <message>
4437 <source>Show requested rights on this device as well</source>
4438 <extracomment>LABEL ANDROID IOS</extracomment>
4439 <translation>Показати запит на права також на цьому пристрої</translation>
4440 </message>
4441 <message>
4442 <source>Show access rights</source>
4443 <extracomment>LABEL ANDROID IOS</extracomment>
4444 <translation>Показати права доступу</translation>
4445 </message>
4446 <message>
4447 <source>Manage paired devices and add new devices</source>
4448 <extracomment>LABEL ANDROID IOS</extracomment>
4449 <translation>Керування з’єднаними пристроями й додавання нових пристроїв</translation>
4450 </message>
4451 <message>
4452 <source>Manage pairings</source>
4453 <extracomment>LABEL ANDROID IOS</extracomment>
4454 <translation>Керування створенням пари</translation>
43764455 </message>
43774456 </context>
43784457 <context>
47574836 <source>Continue</source>
47584837 <translation>Продовжити</translation>
47594838 </message>
4839 <message>
4840 <source>You have not yet set up a Smart-eID or it is no longer usable.
4841
4842 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.</source>
4843 <extracomment>LABEL ANDROID IOS</extracomment>
4844 <translation>Ви ще не налаштували Smart-eID або він більше не придатний для використання.
4845
4846 Щоб продовжити, скористайтеся своєю ID-карткою, вибравши інтерфейс NFC. Якщо ви хочете натомість налаштувати Smart-eID, перервіть поточний процес і почніть налаштування Smart-eID з головного екрана.</translation>
4847 </message>
47604848 </context>
47614849 <context>
47624850 <name>StoreFeedbackPopup</name>
51575245 <message>
51585246 <source>You can read our &lt;b&gt;FAQs&lt;/b&gt; or &lt;b&gt;write&lt;/b&gt; to us...</source>
51595247 <extracomment>LABEL ANDROID IOS</extracomment>
5160 <translation>Ознайомтеся з розділом &lt;b&gt;«Запитання й відповіді»&lt;/b&gt; або &lt;b&gt;напишіть&lt;/b&gt; нам…</translation>
5248 <translation>Ознайомтеся з розділом «Запитання й відповіді» або &lt;b&gt;напишіть&lt;/b&gt; нам…</translation>
51615249 </message>
51625250 <message>
51635251 <source>or</source>
53245412 <translation>Обидва пристрої має бути підключено до однієї мережі Wi-Fi</translation>
53255413 </message>
53265414 <message>
5327 <source>Now choose &quot;Remote&quot; in the AusweisApp2 on your smartphone...</source>
5328 <extracomment>LABEL ANDROID IOS</extracomment>
5329 <translation>Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні…</translation>
5415 <source>Now choose &quot;Card reader&quot; in the AusweisApp2 on your smartphone...</source>
5416 <extracomment>LABEL ANDROID IOS</extracomment>
5417 <translation>Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні…</translation>
53305418 </message>
53315419 <message>
53325420 <source>Now</source>
53345422 <translation>Зараз</translation>
53355423 </message>
53365424 <message>
5337 <source>Start pairing</source>
5338 <extracomment>LABEL ANDROID IOS</extracomment>
5339 <translation>Почати створення пари</translation>
5425 <source>Pair device</source>
5426 <extracomment>LABEL ANDROID IOS</extracomment>
5427 <translation>Створити пару з пристроєм</translation>
53405428 </message>
53415429 <message>
53425430 <source>Pairing code</source>
53615449 <message>
53625450 <source>Select the &lt;b&gt;Smartphone as card reader&lt;/b&gt; tab.</source>
53635451 <extracomment>LABEL ANDROID IOS</extracomment>
5364 <translation>Виберіть вкладку &lt;b&gt;Смартфон як пристрій читання карток&lt;/b&gt;.</translation>
5452 <translation>Виберіть вкладку «Смартфон як пристрій читання карток».</translation>
53655453 </message>
53665454 <message>
53675455 <source>Select smartphone from list</source>
54745562 <message>
54755563 <source>Install AusweisApp2 on both your device without NFC &lt;b&gt;and&lt;/b&gt; your smartphone with NFC capability.</source>
54765564 <extracomment>LABEL ANDROID IOS</extracomment>
5477 <translation>Установіть програму AusweisApp2 на пристрої без NFC &lt;b&gt;та&lt;/b&gt; смартфоні з функцією NFC.</translation>
5565 <translation>Установіть програму AusweisApp2 на пристрої &lt;b&gt;без&lt;/b&gt; NFC та смартфоні з функцією NFC.</translation>
54785566 </message>
54795567 <message>
54805568 <source>Both devices have to be connected to the same WiFi network</source>
54825570 <translation>Обидва пристрої має бути підключено до однієї мережі Wi-Fi</translation>
54835571 </message>
54845572 <message>
5485 <source>Now choose &quot;Remote&quot; in the AusweisApp2 on your smartphone...</source>
5486 <extracomment>LABEL ANDROID IOS</extracomment>
5487 <translation>Тепер виберіть «Віддалений доступ» у програмі AusweisApp2 на смартфоні…</translation>
5573 <source>Now choose &quot;Card reader&quot; in the AusweisApp2 on your smartphone...</source>
5574 <extracomment>LABEL ANDROID IOS</extracomment>
5575 <translation>Тепер виберіть «Пристрій читання карток» у програмі AusweisApp2 на смартфоні…</translation>
54885576 </message>
54895577 <message>
54905578 <source>Now</source>
54925580 <translation>Зараз</translation>
54935581 </message>
54945582 <message>
5495 <source>Start pairing</source>
5496 <extracomment>LABEL ANDROID IOS</extracomment>
5497 <translation>Почати створення пари</translation>
5583 <source>Pair device</source>
5584 <extracomment>LABEL ANDROID IOS</extracomment>
5585 <translation>Створити пару з пристроєм</translation>
54985586 </message>
54995587 <message>
55005588 <source>Pairing code</source>
55125600 <translation>Під час першого використання смартфона як пристрою читання карток (SaC) iOS запитає вашого дозволу на доступ до локальної мережі. Цей дозвіл потрібен для пошуку вашого SaC та підключення до нього. Після першого запиту ви завжди можете отримати доступ до дозволу в параметрах iOS для цієї програми.</translation>
55135601 </message>
55145602 <message>
5515 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Configure remote service&lt;/b&gt;.</source>
5603 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Manage pairings&lt;/b&gt;.</source>
55165604 <extracomment>LABEL IOS</extracomment>
5517 <translation>Тепер відкрийте програму AusweisApp2 на пристрої &lt;b&gt;без&lt;/b&gt; NFC і виберіть &lt;b&gt;Налаштувати віддалену службу&lt;/b&gt;.</translation>
5605 <translation>Тепер відкрийте програму AusweisApp2 на пристрої &lt;b&gt;без&lt;/b&gt; NFC і виберіть «Керування створенням пари».</translation>
55185606 </message>
55195607 <message>
55205608 <source>Now open the AusweisApp2 on your device &lt;b&gt;without&lt;/b&gt; NFC and select &lt;b&gt;Smartphone as card reader&lt;/b&gt;.</source>
55215609 <extracomment>LABEL ANDROID</extracomment>
5522 <translation>Тепер відкрийте програму AusweisApp2 на пристрої &lt;b&gt;без&lt;/b&gt; NFC і виберіть &lt;b&gt;Смартфон як пристрій читання карток&lt;/b&gt;.</translation>
5610 <translation>Тепер відкрийте програму AusweisApp2 на пристрої &lt;b&gt;без&lt;/b&gt; NFC і виберіть «Смартфон як пристрій читання карток».</translation>
55235611 </message>
55245612 <message>
55255613 <source>Now select &lt;b&gt;Settings&lt;/b&gt;.</source>
55265614 <extracomment>LABEL ANDROID IOS</extracomment>
5527 <translation>Тепер виберіть &lt;b&gt;Параметри&lt;/b&gt;.</translation>
5615 <translation>Тепер виберіть «Параметри».</translation>
55285616 </message>
55295617 <message>
55305618 <source>Choose smartphone from list</source>
56805768 <message>
56815769 <source>On every authentication you get displayed &lt;b&gt;who&lt;/b&gt; wants to access &lt;b&gt;which&lt;/b&gt; data</source>
56825770 <extracomment>LABEL ANDROID IOS</extracomment>
5683 <translation>Під час кожної автентифікації відображаються відомості, &lt;b&gt;хто&lt;/b&gt; хоче отримати доступ та до &lt;b&gt;яких&lt;/b&gt; даних,</translation>
5771 <translation>Під час кожної автентифікації відображаються відомості, &lt;b&gt;хто&lt;/b&gt; хоче отримати доступ та до &lt;b&gt;яких&lt;/b&gt; даних.</translation>
56845772 </message>
56855773 <message>
56865774 <source>and you consent to the request with your six-digit PIN.</source>
57435831 <message>
57445832 <source>The &lt;b&gt;integrated self-authentication&lt;/b&gt; is a special service to view the data saved on your ID card.</source>
57455833 <extracomment>LABEL ANDROID IOS</extracomment>
5746 <translation>Служба &lt;b&gt;вбудованої самоавтентифікації&lt;/b&gt; – це спеціальна служба для перегляду даних, збережених на ID-картці.</translation>
5834 <translation>&lt;b&gt;Служба вбудованої самоавтентифікації&lt;/b&gt; – це спеціальна служба для перегляду даних, збережених на ID-картці.</translation>
57475835 </message>
57485836 <message>
57495837 <source>And this is how it works</source>
59226010 <source>Checksum link:</source>
59236011 <extracomment>LABEL DESKTOP Link to download checksum to verify the downloaded update file.</extracomment>
59246012 <translation>Посилання на контрольну суму:</translation>
6013 </message>
6014 </context>
6015 <context>
6016 <name>Utils</name>
6017 <message>
6018 <source>today</source>
6019 <extracomment>LABEL ALL_PLATFORMS</extracomment>
6020 <translation>сьогодні</translation>
6021 </message>
6022 <message>
6023 <source>yesterday</source>
6024 <extracomment>LABEL ALL_PLATFORMS</extracomment>
6025 <translation>вчора</translation>
6026 </message>
6027 <message>
6028 <source>dd.MM.yyyy</source>
6029 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
6030 <translation>dd.MM.yyyy</translation>
59256031 </message>
59266032 </context>
59276033 <context>
63176423 </message>
63186424 <message>
63196425 <source>d. MMMM yyyy, hh:mm:ss AP</source>
6320 <extracomment>LABEL DESKTOP Timestamp, formatted according to the selected language</extracomment>
6426 <extracomment>LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
63216427 <translation>d MMMM yyyy р., hh:mm:ss</translation>
63226428 </message>
63236429 <message>
65276633 </message>
65286634 <message>
65296635 <source>dd.MM.yyyy, hh:mm:ss</source>
6530 <extracomment>LABEL DESKTOP Timestamp</extracomment>
6531 <translation>дд.ММ.рррр, гг:хх:сс</translation>
6636 <extracomment>LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
6637 <translation>dd.MM.yyyy, hh:mm:ss</translation>
65326638 </message>
65336639 <message>
65346640 <source>Last connection: %1</source>
67926898 <translation>Не вдалося виконати автентифікацію.</translation>
67936899 </message>
67946900 <message>
6795 <source>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.</source>
6796 <extracomment>ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length.</extracomment>
6797 <translation>Ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження.</translation>
6901 <source>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.</source>
6902 <extracomment>ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length.</extracomment>
6903 <translation>Довжину даних, надісланих на ID-картку, відхилено. Дані неправильні або ваш пристрій читання карток не підтримує зв’язок за допомогою функції Extended Length і не може використовуватися для читання ID-картки. На жаль, %1 не має впливу на це обмеження.</translation>
67986904 </message>
67996905 <message>
68006906 <source>No certificate description available.</source>
70947200 <name>governikus::HistoryModelSearchFilter</name>
70957201 <message>
70967202 <source>dd.MM.yyyy</source>
7097 <translation>дд.ММ.рррр</translation>
7203 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
7204 <translation>dd.MM.yyyy</translation>
70987205 </message>
70997206 </context>
71007207 <context>
71467253 </message>
71477254 <message>
71487255 <source>dd.MM.yyyy hh:mm:ss</source>
7149 <translation>дд.ММ.рррр гг:хх:сс</translation>
7256 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
7257 <translation>dd.MM.yyyy hh:mm:ss</translation>
71507258 </message>
71517259 <message>
71527260 <source>The logfile is disabled.</source>
72057313 <name>governikus::NotificationModel</name>
72067314 <message>
72077315 <source>hh:mm:ss</source>
7208 <translation>гг:хх:сс</translation>
7316 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
7317 <translation>hh:mm:ss</translation>
72097318 </message>
72107319 </context>
72117320 <context>
72987407 </message>
72997408 <message>
73007409 <source>dd.MM.yyyy hh:mm AP</source>
7301 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7410 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
73027411 <translation>dd.MM.yyyy hh:mm</translation>
73037412 </message>
73047413 <message>
73237432 </message>
73247433 <message>
73257434 <source>dd.MM.yyyy</source>
7326 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7327 <translation>дд.ММ.рррр</translation>
7435 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
7436 <translation>dd.MM.yyyy</translation>
73287437 </message>
73297438 <message>
73307439 <source>hh:mm AP</source>
7331 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7440 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
73327441 <translation>hh:mm</translation>
73337442 </message>
73347443 <message>
74747583 </message>
74757584 <message>
74767585 <source>hh:mm:ss AP</source>
7586 <extracomment>LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString</extracomment>
74777587 <translation>hh:mm:ss</translation>
74787588 </message>
74797589 <message>
75307640 <translation>З’єднаний, але не підтримується</translation>
75317641 </message>
75327642 <message>
7533 <source>Paired, but unavailable</source>
7534 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7535 <translation>З’єднаний, але недоступний</translation>
7536 </message>
7537 <message>
75387643 <source>Unsupported</source>
75397644 <extracomment>LABEL ALL_PLATFORMS</extracomment>
75407645 <translation>Не підтримується</translation>
75467651 </message>
75477652 <message>
75487653 <source>dd.MM.yyyy hh:mm AP</source>
7654 <extracomment>LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString</extracomment>
75497655 <translation>dd.MM.yyyy hh:mm</translation>
75507656 </message>
75517657 <message>
75577663 <source>No smartphone as card reader (Sac) available. Please make sure to activate the &quot;remote service&quot; on your smartphone and to connect both devices to the same WiFi. See %1 for details of use.</source>
75587664 <extracomment>INFO ALL_PLATFORMS No smartphone with enabled remote service was found on the same network.</extracomment>
75597665 <translation>Немає жодного смартфона як пристрою читання карток (SaC). Переконайтеся, що ви активували «віддалену службу» на своєму смартфоні та підключили обидва пристрої до однієї мережі Wi-Fi. Відомості про використання див. в розділі %1.</translation>
7666 </message>
7667 <message>
7668 <source>Unavailable</source>
7669 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7670 <translation>Недоступно</translation>
7671 </message>
7672 <message>
7673 <source>Click to pair</source>
7674 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7675 <translation>Натисніть, щоб створити пару</translation>
75607676 </message>
75617677 </context>
75627678 <context>
75897705
75907706 Увімкніть NFC, щоб використовувати свій смартфон як пристрій читання карток (SaC).</translation>
75917707 </message>
7708 <message>
7709 <source>Pairing with %1 successful.</source>
7710 <extracomment>LABEL ALL_PLATFORMS</extracomment>
7711 <translation>Створено пару з %1.</translation>
7712 </message>
75927713 </context>
75937714 <context>
75947715 <name>governikus::RemoteServiceSettings</name>
76127733 </message>
76137734 <message>
76147735 <source>dd.MM.yyyy</source>
7615 <translation>дд.ММ.рррр</translation>
7736 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString</extracomment>
7737 <translation>dd.MM.yyyy</translation>
76167738 </message>
76177739 <message>
76187740 <source>xx.MM.yyyy</source>
7619 <translation>xx.ММ.рррр</translation>
7741 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day</extracomment>
7742 <translation>xx.MM.yyyy</translation>
76207743 </message>
76217744 <message>
76227745 <source>xx.xx.yyyy</source>
7623 <translation>xx.xx.рррр</translation>
7746 <extracomment>LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month</extracomment>
7747 <translation>xx.xx.yyyy</translation>
76247748 </message>
76257749 <message>
76267750 <source>Family name</source>
77607884 <source>Access denied.</source>
77617885 <extracomment>INFO IOS The current session was interrupted because of a wrong password.</extracomment>
77627886 <translation>Немає доступу.</translation>
7887 </message>
7888 </context>
7889 <context>
7890 <name>governikus::StateEstablishPaceChannel</name>
7891 <message>
7892 <source>The secure channel is opened</source>
7893 <extracomment>INFO ALL_PLATFORMS First status message after the PIN was entered.</extracomment>
7894 <translation>Захищений канал відкрито</translation>
77637895 </message>
77647896 </context>
77657897 <context>
80958227 <message>
80968228 <source>The program remains available via the icon in the menu bar. Click on the %1 icon to reopen the user interface.</source>
80978229 <extracomment>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.</extracomment>
8098 <translation type="unfinished">Програма залишається доступною через піктограму в системному лотку. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача.</translation>
8230 <translation>Програма залишається доступною через піктограму на панелі меню. Натисніть піктограму %1, щоб знову відкрити інтерфейс користувача.</translation>
80998231 </message>
81008232 </context>
81018233 </TS>
218218 "": "Auskunft aus den Zentralen Registern des Kraftfahrt-Bundesamtes"
219219 },
220220 "longDescription": {
221 "": "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.<br/><ul><li>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.</li><li>Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.</li><li>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.</li><li>Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.</li></ul>"
222 },
223 "address": "https://www.kba-online.de/registerauskunft/ora/web",
221 "": "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.<br/><ul><li>Die Online-Auskunft aus dem Fahreignungsregister umfasst Informationen zu den eingetragenen Verkehrsverstößen, deren Punktbewertung und Löschungsdatum.</li><li>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.</li><li>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.</li><li>Die Online-Auskunft aus dem Berufskraftfahrerqualifikationsregister umfasst Informationen zu Fahrerqualifizierungsnachweisen sowie Teilnahmebescheinigungen zu Grundqualifikationen, Weiterbildungen und anderen abgeschlossenen Maßnahmen von Berufskraftfahrerinnen und -fahrern.</li></ul>"
222 },
223 "address": "https://www.kba-online.de/registerauskunft/app",
224224 "homepage": "https://www.kba.de",
225225 "phone": "+49 461 316 0",
226226 "email": "kba@kba.de",
227227 "postalAddress": "Kraftfahrt-Bundesamt<br/>Fördestraße 16<br/>24944 Flensburg",
228 "icon": "KraftfahrtBundesamt_icon.png",
229 "category": "citizen",
230 "subjectUrls": [
231 "https://www.kba-online.de"
232 ]
228 "icon": "KraftfahrtBundesamt_icon.svg",
229 "category": "citizen",
230 "subjectUrlInfo": "Using service from bundID (https://id.bund.de)."
233231 },
234232 {
235233 "shortName": {
288286 "postalAddress": "Ministerium für Wissenschaft, Energie, Klimaschutz und Umwelt des Landes Sachsen-Anhalt<br/>Leipziger Straße 58<br/>39112 Magdeburg",
289287 "icon": "BafoegDigital_icon.svg",
290288 "category": "citizen",
291 "subjectUrls": [
292 "https://id.bund.de"
293 ]
289 "subjectUrlInfo": "Using service from bundID (https://id.bund.de)."
294290 },
295291 {
296292 "shortName": {
462458 },
463459 {
464460 "shortName": {
465 "": "Stadt Magdeburg - iKFZ"
466 },
467 "longName": {
468 "": "Stadt Magdeburg - Internetbasierte Fahrzeugzulassung"
469 },
470 "longDescription": {
471 "": "Die internetbasierte Außerbetriebsetzung und Wiederzulassung eines Kraftfahrzeuges können über das Portal der Landeshauptstadt Magdeburg beantragt werden."
472 },
473 "address": "https://www.magdeburg.de/loadDocument.phtml?ObjSvrID=37&ObjID=27929",
474 "homepage": "https://www.magdeburg.de/Start/B%C3%BCrger-Stadt/Verwaltung-Service/B%C3%BCrgerService",
475 "phone": "+49 391 54 00",
476 "email": "info@magdeburg.de",
477 "postalAddress": "Landeshauptstadt Magdeburg<br/>Alter Markt 6<br/>39104 Magdeburg",
478 "category": "citizen",
479 "subjectUrlInfo": "Using service from Serviceportal Sachsen-Anhalt (https://bk.sachsen-anhalt-connect.de)"
480 },
481 {
482 "shortName": {
483461 "": "Stadt Netphen"
484462 },
485463 "longName": {
655633 "category": "citizen",
656634 "subjectUrls": [
657635 "https://www.buergerserviceportal.de",
658 "https://bayernid.freistaat.bayern"
636 "https://bayernid.freistaat.bayern",
637 "https://id.bayernportal.de"
659638 ]
660639 },
661640 {
21282107 },
21292108 {
21302109 "shortName": {
2131 "": "Online-Bürgerdienste Nürnberg"
2132 },
2133 "longName": {
2134 "": "Online-Bürgerdienste der Stadt Nürnberg"
2135 },
2136 "longDescription": {
2137 "": "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.<br/>Bei immer mehr Verfahren akzeptiert die Stadtverwaltung einen Unterschriftersatz durch die Online-Ausweisfunktion.<br/>Jeder Online-Dienst der Stadt Nürnberg, der die Online-Ausweisfunktion nutzt, ist an dem Hinweis 'mit eID' erkennbar. Derzeit sind dies z. B.:<br/><ul><li>Aufenthaltstitel beantragen</li><li>Gaststättenrechtliche Erlaubnis für den Ausschank von Alkohol beantragen</li><li>Hunde - Negativzeugnis für Kampfhunde beantragen</li><li>Kfz-Halterauskunft beantragen</li><li>Melderegister - Widerspruch gegen Datenübermittlung</li><li>Veranstaltung, Messe, Markt beantragen</li></ul>"
2138 },
2139 "address": "https://www.nuernberg.de/internet/onlinedienste",
2140 "homepage": "https://www.nuernberg.de",
2141 "phone": "+49 9 11 2 31 8613",
2142 "email": "poststelle@stadt.nuernberg.de",
2143 "postalAddress": "Amt für Organisation, Informationsverarbeitung und Zentrale Dienste<br/>E-Government-Büro<br/>Rathausplatz 2<br/>III. OG<br/>90403 Nürnberg",
2144 "category": "citizen",
2110 "": "Mein Nürnberg"
2111 },
2112 "longName": {
2113 "": "Mein Nürnberg - Die digitale Serviceplattform der Stadt Nürnberg"
2114 },
2115 "longDescription": {
2116 "": "Ü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."
2117 },
2118 "address": "https://www.nuernberg.de/internet/mein_nuernberg",
2119 "homepage": "https://www.nuernberg.de/internet/stadtportal",
2120 "phone": "+49 9 11 2 31 4 50 00",
2121 "email": "online-services@stadt.nuernberg.de",
2122 "postalAddress": "Stadt Nürnberg<br/>Amt für Digitalisierung und Prozessorganisation Rathausplatz 2<br/>90403 Nürnberg",
2123 "category": "citizen",
2124 "image": "MeinNuernberg_image.jpg",
2125 "icon": "MeinNuernberg_icon.png",
21452126 "subjectUrls": [
21462127 "https://meinkonto.nuernberg.de"
21472128 ]
23442325 "subjectUrls": [
23452326 "https://www.foerderportal-zeus.de"
23462327 ]
2328 },
2329 {
2330 "shortName": {
2331 "": "Landkreis Elbe-Elster"
2332 },
2333 "longName": {
2334 "": "Landkreis Elbe-Elster - Online Dienste"
2335 },
2336 "longDescription": {
2337 "": "Bürgerinnen und Bürger im Landkreis Elbe-Elster können viele Behördengänge digital erledigen.<br/>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."
2338 },
2339 "address": "https://www.lkee.de/Service-Verwaltung/Online-Dienste",
2340 "homepage": "https://www.lkee.de",
2341 "phone": "+49 3535 460",
2342 "email": "eap@lkee.de",
2343 "postalAddress": "Landkreis Elbe-Elster<br/>Der Landrat<br/>Ludwig-Jahn-Str. 2<br/>04916 Herzberg / Elster",
2344 "image": "lkee_image.jpg",
2345 "icon": "lkee_icon.png",
2346 "category": "citizen",
2347 "subjectUrlInfo": "Using service from Landesportal Brandenburg (https://e-ident.brandenburg.de)."
2348 },
2349 {
2350 "shortName": {
2351 "": "Online-Services der Landeshauptstadt München"
2352 },
2353 "longName": {
2354 "": "Online-Services der Landeshauptstadt München"
2355 },
2356 "longDescription": {
2357 "": "Die Landeshauptstadt München verfügt über eine Vielzahl an Online-Services. Diese können Sie hier einsehen und nutzen."
2358 },
2359 "address": "https://stadt.muenchen.de/infos/online-services.html",
2360 "homepage": "https://www.muenchen.de",
2361 "email": "rathaus@muenchen.de",
2362 "postalAddress": "Landeshauptstadt München<br/>80313 München",
2363 "image": "LandeshauptstadtMuenchen_image.png",
2364 "icon": "LandeshauptstadtMuenchen_icon.png",
2365 "category": "citizen",
2366 "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)."
2367 },
2368 {
2369 "shortName": {
2370 "": "Antrag auf Elterngeld in Bayern"
2371 },
2372 "longName": {
2373 "": "Antrag auf Elterngeld in Bayern"
2374 },
2375 "longDescription": {
2376 "": "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."
2377 },
2378 "address": "https://www.elterngeld.bayern.de/onlineantrag/default.aspx",
2379 "homepage": "https://www.zbfs.bayern.de",
2380 "email": "poststelle@zbfs.bayern.de",
2381 "postalAddress": "Zentrum Bayern Familie und Soziales<br/>95440 Bayreuth",
2382 "icon": "ZBFS_icon.png",
2383 "category": "citizen",
2384 "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)."
2385 },
2386 {
2387 "shortName": {
2388 "": "bundID"
2389 },
2390 "longName": {
2391 "": "bundID - Ihr Zugang zur digitalen Verwaltung. Einfach. Sicher."
2392 },
2393 "address": "https://id.bund.de",
2394 "homepage": "https://id.bund.de",
2395 "longDescription": {
2396 "": " 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.<br/><br/>Sie erhalten alle Bescheide und Nachrichten in Bezug auf den Online-Antrag bequem in Ihr elektronisches Postfach in Ihrem BundID-Konto."
2397 },
2398 "postalAddress": "Bundesministerium des Innern und für Heimat<br/>Alt-Moabit 140<br/>10557 Berlin",
2399 "category": "citizen",
2400 "subjectUrls": [
2401 "https://id.bund.de"
2402 ]
2403 },
2404 {
2405 "shortName": {
2406 "": "Stadt Oberhausen"
2407 },
2408 "longName": {
2409 "": "Stadt Oberhausen"
2410 },
2411 "address": "https://serviceportal.oberhausen.de/home",
2412 "homepage": "https://www.oberhausen.de",
2413 "email": "info@oberhausen.de",
2414 "longDescription": {
2415 "": "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."
2416 },
2417 "postalAddress": "Stadt Oberhausen<br/>Schwartzstraße 72<br/>46042 Oberhausen",
2418 "icon": "StadtOberhausen_icon.png",
2419 "category": "citizen",
2420 "subjectUrlInfo": "Using service from Servicekonto Nordrhein-Westfalen (https://servicekonto.nrw)."
2421 },
2422 {
2423 "shortName": {
2424 "": "Digitale Rentenübersicht"
2425 },
2426 "longName": {
2427 "": "Digitale Rentenübersicht - Zentrale Stelle für die Digitale Rentenübersicht (Deutsche Rentenversicherung Bund)"
2428 },
2429 "address": "https://app.rentenuebersicht.de",
2430 "homepage": "https://www.rentenuebersicht.de",
2431 "phone": "+49 800 1000 787",
2432 "email": "digitalerentenuebersicht@drv-bund.de",
2433 "longDescription": {
2434 "": "Mit der Online-Ausweisfunktion im neuen Personalausweis können Sie ...<br/><ul><li>Ihre individuellen Altersvorsorge-Ansprüche der gesetzlichen, betrieblichen und privaten Altersvorsorge bequem digital abrufen und</li><li>die Informationen zum Stand Ihrer Altersvorsorge-Ansprüche als Grundlage für eine weitere unabhängige Beratung herunterladen.</li></ul>"
2435 },
2436 "postalAddress": "Deutsche Rentenversicherung Bund Zentrale Stelle für die Digitale Rentenübersicht<br/>10868 Berlin",
2437 "icon": "DigitaleRentenuebersicht_icon.svg",
2438 "category": "citizen",
2439 "subjectUrls": [
2440 "https://login.deutsche-rentenversicherung.de"
2441 ]
2442 },
2443 {
2444 "shortName": {
2445 "": "Zoll-Portal"
2446 },
2447 "longName": {
2448 "": "Zoll-Portal"
2449 },
2450 "address": "https://www.zoll-portal.de",
2451 "homepage": "https://www.zoll-portal.de",
2452 "email": "Zoll-Portal@zoll.bund.de",
2453 "longDescription": {
2454 "": "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."
2455 },
2456 "postalAddress": "Generalzolldirektion<br/>Am Propsthof 78a<br/>53121 Bonn",
2457 "icon": "ZollPortal_icon.svg",
2458 "image": "ZollPortal_image.svg",
2459 "category": "citizen",
2460 "subjectUrls": [
2461 "https://www.zoll-portal.de"
2462 ]
2463 },
2464 {
2465 "shortName": {
2466 "": "Stadt Augsburg - Digitale Bürgerservices nutzen"
2467 },
2468 "longName": {
2469 "": "Stadt Augsburg - Digitale Bürgerservices nutzen"
2470 },
2471 "address": "https://www.augsburg.de/online-services",
2472 "homepage": "https://www.augsburg.de",
2473 "email": "augsburg@augsburg.de",
2474 "longDescription": {
2475 "": "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.<br/><br/>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.<br/><br/>Informationen zur Registrierung in der BayernID können Sie nachlesen (https://id.bayernportal.de/).<br/><br/>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."
2476 },
2477 "postalAddress": "Stadt Augsburg<br/>Rathausplatz 1<br/>86150 Augsburg",
2478 "icon": "StadtAugsburg_icon.png",
2479 "category": "citizen",
2480 "subjectUrlInfo": "Using service from Bürgerservice-Portale der bayerischen Kommunen (https://bayernid.freistaat.bayern)."
23472481 }
23482482 ]
23492483 }
206206 }
207207
208208
209 private void convertChromeOsIntent(Intent pIntent)
210 {
211 if (pIntent != null && pIntent.getAction().equals("org.chromium.arc.intent.action.VIEW"))
212 {
213 LogHandler.getLogger().info("Convert Intent action " + pIntent.getAction() + " to " + Intent.ACTION_VIEW);
214 pIntent.setAction(Intent.ACTION_VIEW);
215 }
216 }
217
218
209219 @Override
210220 public void onCreate(Bundle savedInstanceState)
211221 {
212222 setTheme(R.style.AppTheme);
213223
224 convertChromeOsIntent(getIntent());
214225 LogHandler.getLogger().info("onCreate: " + getIntent());
215226 super.onCreate(savedInstanceState);
216227
255266 @Override
256267 protected void onNewIntent(Intent newIntent)
257268 {
269 convertChromeOsIntent(newIntent);
258270 cIntent = newIntent;
259271 setIntent(newIntent);
260272 LogHandler.getLogger().info("onNewIntent: " + newIntent);
132132 ResponseApduResult result = card->transmit(commandApdu);
133133 if (result.mResponseApdu.getStatusCode() == StatusCode::WRONG_LENGTH)
134134 {
135 return {CardReturnCode::EXTENDED_LENGTH_MISSING};
135 return {CardReturnCode::WRONG_LENGTH};
136136 }
137137
138138 if (mSecureMessaging)
140140 result.mResponseApdu = mSecureMessaging->decrypt(result.mResponseApdu);
141141 if (result.mResponseApdu.isEmpty())
142142 {
143 qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must no be re-used.";
143 qCDebug(::card) << "Stopping Secure Messaging since it failed. The channel therefore must not be re-used.";
144144 stopSecureMessaging();
145145
146146 return {CardReturnCode::COMMAND_FAILED};
1111
1212
1313 Q_DECLARE_LOGGING_CATEGORY(card)
14
15 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
16 #define HEX hex
17 #else
18 #define HEX Qt::hex
19 #endif
20
2114
2215 constexpr std::byte CLA {0x00};
2316 constexpr std::byte CLA_PROPRIETARY {0x80};
127120
128121 if (mData.size() > EXTENDED_MAX_LC)
129122 {
130 qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC;
123 qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC;
131124 }
132125
133126 if (mLe > EXTENDED_MAX_LE)
134127 {
135 qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE;
128 qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE;
136129 }
137130 }
138131
147140 {
148141 if (mData.size() > EXTENDED_MAX_LC)
149142 {
150 qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << HEX << EXTENDED_MAX_LC;
143 qCCritical(card).nospace() << "Command data exceeds maximum of 0x" << Qt::hex << EXTENDED_MAX_LC;
151144 }
152145
153146 if (mLe > EXTENDED_MAX_LE)
154147 {
155 qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << HEX << EXTENDED_MAX_LE;
148 qCCritical(card).nospace() << "Expected length exceeds maximum value of 0x" << Qt::hex << EXTENDED_MAX_LE;
156149 }
157150 }
158151
209202 return Ins(mIns);
210203 }
211204
212 qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << HEX << mIns;
205 qCCritical(card).nospace().noquote() << "Unknown INS value, returning UNKNOWN, value: 0x" << Qt::hex << mIns;
213206 return Ins::UNKNOWN;
214207 }
215208
189189 break;
190190
191191 case StatusCode::WRONG_LENGTH:
192 return CardReturnCode::EXTENDED_LENGTH_MISSING;
192 return CardReturnCode::WRONG_LENGTH;
193193
194194 default:
195195 qCWarning(card) << "TA PSO:Verify Certificate failed:" << psoResult.getStatusCode();
114114 case CardReturnCode::PUK_INOPERATIVE:
115115 case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS:
116116 case CardReturnCode::PROTOCOL_ERROR:
117 case CardReturnCode::EXTENDED_LENGTH_MISSING:
117 case CardReturnCode::WRONG_LENGTH:
118118 return EstablishPaceChannelErrorCode::UnexpectedDataInInput;
119119
120120 case CardReturnCode::INVALID_CAN:
5959 if (mSimulatorReader)
6060 {
6161 mSimulatorReader->disconnectReader(pError);
62
63 auto info = mSimulatorReader->getReaderInfo();
64 mSimulatorReader.reset();
65 Q_EMIT fireReaderRemoved(info);
6266 }
6367 ReaderManagerPlugIn::stopScan(pError);
64 mSimulatorReader.reset();
6568 }
6669
6770
394394 }
395395
396396
397 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
398 #define HEX hex
399 #else
400 #define HEX Qt::hex
401 #endif
402
403
404397 QDebug operator<<(QDebug pDbg, const EidStatus& pStatus)
405398 {
406399 const auto& toString = [](const EidStatus& status){
429422 };
430423
431424 QDebugStateSaver saver(pDbg);
432 pDbg.nospace() << toString(pStatus) << " 0x" << HEX << static_cast<int>(pStatus);
425 pDbg.nospace() << toString(pStatus) << " 0x" << Qt::hex << static_cast<int>(pStatus);
433426 return pDbg;
434427 }
435428
459452 };
460453
461454 QDebugStateSaver saver(pDbg);
462 pDbg.nospace() << toString(pInfo) << " 0x" << HEX << static_cast<int>(pInfo);
455 pDbg.nospace() << toString(pInfo) << " 0x" << Qt::hex << static_cast<int>(pInfo);
463456 return pDbg;
464457 }
465458
492485 };
493486
494487 QDebugStateSaver saver(pDbg);
495 pDbg.nospace() << toString(pResult) << " 0x" << HEX << static_cast<int>(pResult);
488 pDbg.nospace() << toString(pResult) << " 0x" << Qt::hex << static_cast<int>(pResult);
496489 return pDbg;
497490 }
158158 mConnectionTestWithProxyDone = false;
159159 mConnectionTestWithoutProxyDone = false;
160160
161 const auto& proxy = QNetworkProxy::applicationProxy();
161 const QUrl& testUrl = QUrl(Env::getSingleton<SecureStorage>()->getUpdateServerBaseUrl());
162 const auto& proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(testUrl));
163 const auto& proxy = proxies.constFirst();
164 if (proxies.size() > 1)
165 {
166 qDebug() << "More than one proxy found, using first proxy:" << proxy;
167 }
168
162169 if (proxy.type() == QNetworkProxy::ProxyType::NoProxy)
163170 {
164171 mIsProxySet = false;
174181 mProxyCapabilities = getProxyCapabilitiesAsQString(proxy.capabilities());
175182 }
176183
177 const QUrl& testUrl = QUrl(Env::getSingleton<SecureStorage>()->getUpdateServerBaseUrl());
178184 if (mIsProxySet)
179185 {
180186 mPingSocketToProxy.reset();
338338 QDateTime timestampValue = mContext->getTimestamp();
339339 if (timestampValue.isValid())
340340 {
341 //: LABEL DESKTOP Timestamp, formatted according to the selected language
341 //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString
342342 QString timestamp = LanguageLoader::getInstance().getUsedLocale().toString(timestampValue, tr("d. MMMM yyyy, hh:mm:ss AP"));
343343 //: LABEL DESKTOP
344344 mTimestampSection << ContentItem(tr("Time of diagnosis"), timestamp);
705705
706706 if (!info.getFingerprint().isEmpty())
707707 {
708 //: LABEL DESKTOP Timestamp
708 //: LABEL DESKTOP Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString
709709 const QString& timestamp = LanguageLoader::getInstance().getUsedLocale().toString(info.getLastConnected(), tr("dd.MM.yyyy, hh:mm:ss"));
710710 //: LABEL DESKTOP
711711 mRemoteDeviceSection << ContentItem(info.getNameEscaped(), tr("Last connection: %1").arg(timestamp));
112112 {tr("Date"),
113113 //: LABEL ALL_PLATFORMS
114114 tr("Details")});
115 //: LABEL ALL_PLATFORMS
115 //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString
116116 const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP");
117117 const auto& infos = Env::getSingleton<AppSettings>()->getHistorySettings().getHistoryInfos();
118118 for (const auto& entry : infos)
141141 closeTable();
142142
143143 const auto& now = QDateTime::currentDateTime();
144 //: LABEL ALL_PLATFORMS
144 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString
145145 QString date = locale.toString(now, tr("dd.MM.yyyy"));
146 //: LABEL ALL_PLATFORMS
146 //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString
147147 QString time = locale.toString(now, tr("hh:mm AP"));
148148 //: LABEL ALL_PLATFORMS
149149 const auto& headline = tr("At %1 %2 the following data were saved:").arg(date, time);
180180 closeTable();
181181
182182 const auto& locale = LanguageLoader::getInstance().getUsedLocale();
183 //: LABEL ALL_PLATFORMS
183 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString
184184 QString date = locale.toString(pDate, tr("dd.MM.yyyy"));
185 //: LABEL ALL_PLATFORMS
185 //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString
186186 QString time = locale.toString(pDate, tr("hh:mm AP"));
187187 //: LABEL ALL_PLATFORMS
188188 const auto& headline = tr("At %1 %2 the following data has been read out of your ID card:").arg(date, time);
+0
-56
src/external/smart/README.md less more
0 eid-applet-service jni bridge
1 =============================
2
3 - Current `eid_applet_interface.h` version: `0.16.0`
4 - Current `eid-applet-service-lib.aar` version: `0.10.3-180`
5
6 ## Availability
7
8 If you have access to the `partner.bdr.de` network, the
9 `eid-applet-service-lib` library is also available through the
10 artifactory maven repository. `app/build.gradle` integration:
11
12 ```gradle
13 implementation "de.bdr.android.eid-applet-service-lib:eid-applet-service-lib:0.10.3-180"
14 ```
15
16 Parse and set the credentials within the root `build.gradle`.
17
18 ```gradle
19 allprojects {
20 repositories {
21 // ...
22 maven {
23 url 'https://partner.bdr.de/artifactory/mid-mvn/'
24 credentials {
25 username "Your_User_Name"
26 password "Your_Password_Or_API_Key"
27 }
28 }
29 }
30 }
31 ```
32
33 ## Usage
34
35 To use the service library, it must first be initialized correctly. The
36 function `initializeService(JNIEnv *mEnv, jobject mApplicationContext)`
37 must be called so that the `JNIEnv` reference and the android
38 `ApplicationContext` can be passed correctly. If the functionality is no
39 longer needed, the service can be released by the function
40 `shutdownService()`. If a function is called without previous
41 initialization of the library, the return value of the function contains
42 a corresponding error message. The function could not be executed
43 successfully.
44
45 ## Additional remarks
46
47 - Currently used ndk version: `21.3.6528147`
48
49 License
50 -------
51
52 ```
53 Copyright (C) 2021 Bundesdruckerei GmbH and Governikus GmbH
54 ```
55
3131 case CardReturnCode::PROTOCOL_ERROR:
3232 return GlobalStatus::Code::Card_Protocol_Error;
3333
34 case CardReturnCode::EXTENDED_LENGTH_MISSING:
35 return GlobalStatus::Code::Workflow_No_Extended_Length_Error;
34 case CardReturnCode::WRONG_LENGTH:
35 return GlobalStatus::Code::Workflow_Wrong_Length_Error;
3636
3737 case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS:
3838 return GlobalStatus::Code::Card_Unexpected_Transmit_Status;
9898 case CardReturnCode::UNKNOWN:
9999 case CardReturnCode::COMMAND_FAILED:
100100 case CardReturnCode::PROTOCOL_ERROR:
101 case CardReturnCode::EXTENDED_LENGTH_MISSING:
101 case CardReturnCode::WRONG_LENGTH:
102102 case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS:
103103 case CardReturnCode::OK:
104104 case CardReturnCode::OK_PUK:
3636 PUK_INOPERATIVE,
3737 NO_ACTIVE_PIN_SET,
3838 PROTOCOL_ERROR,
39 EXTENDED_LENGTH_MISSING,
39 WRONG_LENGTH,
4040 UNEXPECTED_TRANSMIT_STATUS)
4141
4242
102102 addConversionElement(GlobalStatus::Code::Card_Unexpected_Transmit_Status, Minor::AL_Unknown_Error);
103103 addConversionElement(GlobalStatus::Code::Card_NewPin_Invalid_Length, Minor::AL_Unknown_Error);
104104 addConversionElement(GlobalStatus::Code::Workflow_AlreadyInProgress_Error, Minor::AL_Unknown_Error);
105 addConversionElement(GlobalStatus::Code::Workflow_No_Extended_Length_Error, Minor::AL_Unknown_Error);
105 addConversionElement(GlobalStatus::Code::Workflow_Wrong_Length_Error, Minor::AL_Unknown_Error);
106106 addConversionElement(GlobalStatus::Code::Card_Not_Found, Minor::AL_Unknown_Error);
107107 addConversionElement(GlobalStatus::Code::Card_Communication_Error, Minor::AL_Unknown_Error);
108108 addConversionElement(GlobalStatus::Code::Card_Input_TimeOut, Minor::AL_Unknown_Error);
4141 Certificate_Check_Failed_Hash_Mismatch,
4242 Certificate_Check_Failed_Same_Origin_Policy_Violation,
4343 Certificate_Check_Failed_Hash_Missing_In_Description,
44 Pre_Verfication_No_Test_Environment,
45 Pre_Verfication_Invalid_Certificate_Chain,
46 Pre_Verfication_Invalid_Certificate_Signature,
47 Pre_Verfication_Certificate_Expired,
44 Pre_Verification_No_Test_Environment,
45 Pre_Verification_Invalid_Certificate_Chain,
46 Pre_Verification_Invalid_Certificate_Signature,
47 Pre_Verification_Certificate_Expired,
4848 Extract_Cvcs_From_Eac1_No_Unique_At,
4949 Extract_Cvcs_From_Eac1_No_Unique_Dv,
5050 Extract_Cvcs_From_Eac1_At_Missing,
6363 Did_Authenticate_Eac2_Card_Command_Failed,
6464 Generic_Send_Receive_Paos_Unhandled,
6565 Generic_Send_Receive_Network_Error,
66 Generic_Send_Receive_Ssl_Error,
66 Generic_Send_Receive_Tls_Error,
6767 Generic_Send_Receive_Server_Error,
6868 Generic_Send_Receive_Client_Error,
6969 Generic_Send_Receive_Paos_Unknown,
7474 Transmit_Card_Command_Failed,
7575 Start_Paos_Response_Missing,
7676 Start_Paos_Response_Error,
77 Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply,
77 Check_Refresh_Address_Fatal_Tls_Error_Before_Reply,
7878 Check_Refresh_Address_Invalid_Ephemeral_Key_Length,
7979 Check_Refresh_Address_Service_Unavailable,
8080 Check_Refresh_Address_Service_Timeout,
8181 Check_Refresh_Address_Proxy_Error,
82 Check_Refresh_Address_Fatal_Ssl_Error_After_Reply,
82 Check_Refresh_Address_Fatal_Tls_Error_After_Reply,
8383 Check_Refresh_Address_Unknown_Network_Error,
8484 Check_Refresh_Address_Invalid_Http_Response,
8585 Check_Refresh_Address_Empty,
9393 Generic_Provider_Communication_Network_Error,
9494 Generic_Provider_Communication_Invalid_Ephemeral_Key_Length,
9595 Generic_Provider_Communication_Certificate_Error,
96 Generic_Provider_Communication_Ssl_Error,
96 Generic_Provider_Communication_Tls_Error,
9797 Get_SelfAuthData_Invalid_Or_Empty,
9898 Change_Pin_No_SetEidPinCommand_Response,
9999 Change_Pin_Input_Timeout,
161161 //: ERROR ALL_PLATFORMS DidAuthenticateEAC2, AA2 or the ID card declined the certificates.
162162 return tr("Authentication failed.");
163163
164 case Code::Workflow_No_Extended_Length_Error:
165 //: ERROR ALL_PLATFORMS DidAuthenticateEAC2 was not able to send the certificates to the card because the card reader does not support extended length.
166 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());
164 case Code::Workflow_Wrong_Length_Error:
165 //: ERROR ALL_PLATFORMS A card command failed because the data length was wrong or the card reader does not support Extended Length.
166 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());
167167
168168 case Code::Workflow_Certificate_No_Description:
169169 //: ERROR_MASKED ALL_PLATFORMS
5656 Workflow_No_Unique_AtCvc,
5757 Workflow_No_Unique_DvCvc,
5858 Workflow_No_Permission_Error,
59 Workflow_No_Extended_Length_Error,
59 Workflow_Wrong_Length_Error,
6060 Workflow_Certificate_No_Description,
6161 Workflow_Certificate_No_Url_In_Description,
6262 Workflow_Certificate_Hash_Error,
283283 {
284284 QByteArray function(pFunction);
285285
286 // Remove anonymous namespace
287 function.replace(QByteArrayLiteral("(anonymous namespace)::"), "");
288
286289 // Remove the parameter list
287290 function = function.left(function.indexOf('('));
288291
290293 function.replace(QByteArrayLiteral("governikus::"), "");
291294
292295 // Remove the return type (if any)
293 if (function.indexOf(' ') != -1)
294 {
295 function = function.mid(function.lastIndexOf(' ') + 1);
296 if (const auto index = function.lastIndexOf(' ') + 1; index > 0)
297 {
298 function = function.mid(index);
299 if (!function.isEmpty() && function.at(0) == '*')
300 {
301 function.remove(0, 1);
302 }
296303 }
297304
298305 // Trim function name
159159 qCWarning(ifd) << "Connection error:" << pError;
160160
161161 mTimer.stop();
162 if (pError == QAbstractSocket::SocketError::RemoteHostClosedError)
162 if (pError == QAbstractSocket::SocketError::RemoteHostClosedError
163 || pError == QAbstractSocket::SocketError::SslHandshakeFailedError)
163164 {
164165 Q_EMIT fireConnectionError(mIfdDescriptor, IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION);
165166 }
2626
2727 Q_INVOKABLE virtual void send(const QByteArray& pDataBlock) = 0;
2828 Q_INVOKABLE virtual void close() = 0;
29 [[nodiscard]] virtual bool isPairingConnection() const = 0;
2930 [[nodiscard]] virtual const QString& getId() const = 0;
3031
3132 Q_SIGNALS:
3737 IfdDescriptor::IfdDescriptorData::IfdDescriptorData(const QString& pIfdName,
3838 const QString& pIfdId,
3939 const QVector<IfdVersion::Version>& pApiVersions,
40 const bool pIsPairingAnnounced,
4041 const QUrl& pRemoteUrl,
4142 bool pIsLocalIfd)
4243 : mIfdName(pIfdName)
4344 , mIfdId(pIfdId)
4445 , mApiVersions(pApiVersions)
46 , mIsPairingAnnounced(pIsPairingAnnounced)
4547 , mUrl(pRemoteUrl)
4648 , mIsLocalIfd(pIsLocalIfd)
4749 {
5658 return mIfdName == pOther.mIfdName &&
5759 mIfdId == pOther.mIfdId &&
5860 mApiVersions == pOther.mApiVersions &&
61 mIsPairingAnnounced == pOther.mIsPairingAnnounced &&
5962 mUrl == pOther.mUrl;
6063 }
6164
7881 const QString& ifdName = pDiscovery.getIfdName();
7982 const QString& ifdId = pDiscovery.getIfdId();
8083 const QVector<IfdVersion::Version>& supportedApis = pDiscovery.getSupportedApis();
81 d = new IfdDescriptorData(ifdName, ifdId, supportedApis, url, pLocalIfd);
84 const bool isPairing = pDiscovery.getPairing();
85 d = new IfdDescriptorData(ifdName, ifdId, supportedApis, isPairing, url, pLocalIfd);
8286 }
8387
8488
109113 bool IfdDescriptor::isSupported() const
110114 {
111115 return IfdVersion(IfdVersion::selectLatestSupported(getApiVersions())).isValid();
116 }
117
118
119 bool IfdDescriptor::isPairingAnnounced() const
120 {
121 return !isNull() && d->mIsPairingAnnounced;
112122 }
113123
114124
2929 IfdDescriptorData(const QString& pIfdName,
3030 const QString& pIfdId,
3131 const QVector<IfdVersion::Version>& pApiVersions,
32 const bool pIsPairingAnnounced,
3233 const QUrl& pUrl,
3334 bool pIsLocalIfd);
3435
3738 const QString mIfdName;
3839 const QString mIfdId;
3940 const QVector<IfdVersion::Version> mApiVersions;
41 const bool mIsPairingAnnounced;
4042 const QUrl mUrl;
4143 const bool mIsLocalIfd;
4244
5658 [[nodiscard]] const QString& getIfdId() const;
5759 [[nodiscard]] const QVector<IfdVersion::Version>& getApiVersions() const;
5860 [[nodiscard]] bool isSupported() const;
61 [[nodiscard]] bool isPairingAnnounced() const;
5962 [[nodiscard]] const QUrl& getUrl() const;
6063 [[nodiscard]] bool isNull() const;
6164 [[nodiscard]] bool isLocalIfd() const;
8888 }
8989
9090
91 bool IfdDispatcher::isPairingConnection() const
92 {
93 if (!mDataChannel)
94 {
95 return false;
96 }
97
98 return mDataChannel->isPairingConnection();
99 }
100
101
91102 QString IfdDispatcher::getId() const
92103 {
93104 if (!mDataChannel)
4545 explicit IfdDispatcher(IfdVersion::Version pVersion, const QSharedPointer<DataChannel>& pDataChannel);
4646 ~IfdDispatcher() override;
4747
48 [[nodiscard]] virtual bool isPairingConnection() const;
4849 [[nodiscard]] virtual QString getId() const;
4950 [[nodiscard]] virtual const QString& getContextHandle() const;
5051 [[nodiscard]] IfdVersion::Version getVersion() const;
107107 void IfdReaderManagerPlugIn::onContextEstablished(const QString& pIfdName, const QString& pId)
108108 {
109109 const auto& dispatcher = mDispatcherList.value(pId);
110 if (isInitialPairing(pIfdName, pId))
111 {
112 QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection);
113 }
114 else
115 {
116 QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] {
117 const QSharedPointer<const IfdGetStatus>& ifdGetStatus = QSharedPointer<IfdGetStatus>::create();
118 dispatcher->send(ifdGetStatus);
119 }, Qt::QueuedConnection);
120 }
110
111 if (getInfo().getPlugInType() == ReaderManagerPlugInType::REMOTE_IFD)
112 {
113 dispatcher->saveRemoteNameInSettings(pIfdName);
114 if (dispatcher->isPairingConnection())
115 {
116 QMetaObject::invokeMethod(dispatcher.data(), &IfdDispatcher::close, Qt::QueuedConnection);
117 return;
118 }
119 }
120
121 QMetaObject::invokeMethod(dispatcher.data(), [dispatcher] {
122 const QSharedPointer<const IfdGetStatus>& ifdGetStatus = QSharedPointer<IfdGetStatus>::create();
123 dispatcher->send(ifdGetStatus);
124 }, Qt::QueuedConnection);
121125 }
122126
123127
1212 #include <QMap>
1313 #include <QSharedPointer>
1414
15
16 class test_RemoteIfdReaderManagerPlugIn;
17
18
1519 namespace governikus
1620 {
1721
2024 : public ReaderManagerPlugIn
2125 {
2226 Q_OBJECT
27 friend class ::test_RemoteIfdReaderManagerPlugIn;
2328
2429 private:
2530 QMultiMap<QString, QString> mReadersForDispatcher;
3944 void removeDispatcher(const QString& pId);
4045 [[nodiscard]] const QMap<QString, QSharedPointer<IfdDispatcherClient>>& getDispatchers() const;
4146
42 virtual bool isInitialPairing(const QString& pIfdName, const QString& pId) = 0;
4347 virtual IfdClient* getIfdClient() = 0;
4448
4549 public:
4444 void firePskChanged(const QByteArray& pPsk);
4545 void fireConnectedChanged(bool pConnected);
4646 void fireIsRunningChanged();
47 void firePairingCompleted();
47 void firePairingCompleted(const QSslCertificate& pCertificate);
4848 };
4949
5050 } // namespace governikus
3434
3535 virtual void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput&) = 0;
3636 virtual void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) = 0;
37 virtual void setAllowedCardTypes(const QVector<ReaderManagerPlugInType>& pAllowedCardTypes) = 0;
3738
3839 Q_SIGNALS:
3940 void fireCardConnected(const QSharedPointer<CardConnection>& pConnection);
41 void fireDisplayTextChanged(const QString& pDisplayText);
4042 void fireEstablishPaceChannel(const QSharedPointer<const IfdEstablishPaceChannel>& pMessage, const QSharedPointer<CardConnection>& pConnection);
4143 void fireModifyPin(const QSharedPointer<const IfdModifyPin>& pMessage, const QSharedPointer<CardConnection>& pConnection);
4244 void fireCardDisconnected(const QSharedPointer<CardConnection>& pConnection);
3939 }
4040
4141
42 ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer<DataChannel>& pDataChannel, const QVector<ReaderManagerPlugInType>& pAllowedPlugInTypes)
42 ServerMessageHandlerImpl::ServerMessageHandlerImpl(const QSharedPointer<DataChannel>& pDataChannel,
43 const QVector<ReaderManagerPlugInType>& pAllowedTypes)
4344 : ServerMessageHandler()
4445 , mDispatcher(Env::create<IfdDispatcherServer*>(pDataChannel), &QObject::deleteLater)
45 , mAllowedPlugInTypes(pAllowedPlugInTypes)
46 , mAllowedPlugInTypes(pAllowedTypes)
47 , mAllowedCardTypes(pAllowedTypes)
4648 , mCardConnections()
4749 {
4850 connect(mDispatcher.data(), &IfdDispatcherServer::fireReceived, this, &ServerMessageHandlerImpl::onMessage);
215217 if (!progressMessage.isNull())
216218 {
217219 cardConnection->setProgressMessage(progressMessage);
220 Q_EMIT fireDisplayTextChanged(progressMessage);
218221 }
219222
220223 qCDebug(ifd) << "Transmit card APDU for" << slotHandle;
333336
334337 const auto& response = QSharedPointer<IfdModifyPinResponse>::create(pSlotHandle, ccid, minor);
335338 mDispatcher->send(response);
339 }
340
341
342 void ServerMessageHandlerImpl::setAllowedCardTypes(const QVector<ReaderManagerPlugInType>& pAllowedCardTypes)
343 {
344 mAllowedCardTypes = pAllowedCardTypes;
336345 }
337346
338347
443452 }
444453 }
445454
455 mDispatcher->send(QSharedPointer<IfdStatus>::create(pInfo, mAllowedCardTypes.contains(pInfo.getPlugInType())));
456 }
457
458
459 void ServerMessageHandlerImpl::onReaderRemoved(const ReaderInfo& pInfo)
460 {
461 if (!mAllowedPlugInTypes.contains(pInfo.getPlugInType()))
462 {
463 return;
464 }
465
446466 mDispatcher->send(QSharedPointer<IfdStatus>::create(pInfo));
447467 }
448468
449469
450 void ServerMessageHandlerImpl::onReaderRemoved(const ReaderInfo& pInfo)
451 {
452 if (!mAllowedPlugInTypes.contains(pInfo.getPlugInType()))
453 {
454 return;
455 }
456
457 mDispatcher->send(QSharedPointer<IfdStatus>::create(pInfo));
458 }
459
460
461470 } // namespace governikus
3232 private:
3333 const QSharedPointer<IfdDispatcherServer> mDispatcher;
3434 QVector<ReaderManagerPlugInType> mAllowedPlugInTypes;
35 QVector<ReaderManagerPlugInType> mAllowedCardTypes;
3536 QMap<QString, QSharedPointer<CardConnection>> mCardConnections;
3637
3738 [[nodiscard]] QString slotHandleForReaderName(const QString& pReaderName) const;
5354
5455 public:
5556 explicit ServerMessageHandlerImpl(const QSharedPointer<DataChannel>& pDataChannel,
56 const QVector<ReaderManagerPlugInType>& pAllowedPlugInTypes = Enum<ReaderManagerPlugInType>::getList());
57 const QVector<ReaderManagerPlugInType>& pAllowedTypes = Enum<ReaderManagerPlugInType>::getList());
5758
5859 void sendEstablishPaceChannelResponse(const QString& pSlotHandle, const EstablishPaceChannelOutput& pChannelOutput) override;
5960 void sendModifyPinResponse(const QString& pSlotHandle, const ResponseApdu& pResponseApdu) override;
61 void setAllowedCardTypes(const QVector<ReaderManagerPlugInType>& pAllowedCardTypes) override;
6062 };
6163
6264
4444 {
4545 close();
4646 mPsk.clear();
47 }
48
49
50 bool TlsServer::hasPsk() const
51 {
52 return !mPsk.isEmpty();
4753 }
4854
4955
4343 void setPsk(const QByteArray& pPsk);
4444 void stopListening();
4545 virtual bool startListening(quint16 pPort) = 0;
46 [[nodiscard]] bool hasPsk() const;
4647
4748 Q_SIGNALS:
4849 void fireNewConnection(QTcpSocket* pSocket);
44 #include "WebSocketChannel.h"
55
66 #include "RemoteServiceSettings.h"
7 #include "SecureStorage.h"
78
89 #include <QLoggingCategory>
910 #include <QThread>
9394 }
9495
9596
97 bool WebSocketChannel::isPairingConnection() const
98 {
99 const auto& pairingCiphers = Env::getSingleton<SecureStorage>()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers();
100 return pairingCiphers.contains(mConnection->sslConfiguration().sessionCipher());
101 }
102
103
96104 const QString& WebSocketChannel::getId() const
97105 {
98106 return mId;
3434
3535 void send(const QByteArray& pDataBlock) override;
3636 void close() override;
37 [[nodiscard]] bool isPairingConnection() const override;
3738 [[nodiscard]] const QString& getId() const override;
3839
3940 private Q_SLOTS:
8080 }
8181
8282
83 IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo)
83 IfdStatus::IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard)
8484 : IfdMessage(IfdMessageType::IFDStatus)
8585 , mSlotName(pReaderInfo.getName())
8686 , mHasPinPad(!pReaderInfo.isBasicReader())
8787 , mMaxApduLength(pReaderInfo.getMaxApduLength())
8888 , mConnectedReader(pReaderInfo.isValid())
89 , mCardAvailable(pReaderInfo.hasCard())
89 , mCardAvailable(pReaderInfo.hasCard() && pPublishCard)
9090 {
9191 if (!mHasPinPad && pReaderInfo.getPlugInType() == ReaderManagerPlugInType::NFC)
9292 {
3232 void parsePinPad(const QJsonObject& pMessageObject);
3333
3434 public:
35 explicit IfdStatus(const ReaderInfo& pReaderInfo);
35 explicit IfdStatus(const ReaderInfo& pReaderInfo, bool pPublishCard = true);
3636 explicit IfdStatus(const QJsonObject& pMessageObject);
3737 ~IfdStatus() override = default;
3838
9696 }
9797
9898
99 bool LocalIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId)
100 {
101 Q_UNUSED(pIfdName)
102 Q_UNUSED(pId)
103 return false;
104 }
105
106
10799 bool LocalIfdReaderManagerPlugIn::isAusweisApp2Installed()
108100 {
109101 if (mServiceConnected)
3535 void stopScan(const QString& pError = QString()) override;
3636
3737 protected:
38 bool isInitialPairing(const QString& pIfdName, const QString& pId) override;
3938 LocalIfdClient* getIfdClient() override;
4039 void addDispatcher(const QSharedPointer<IfdDispatcherClient>& pDispatcher) override;
4140
3939 const RemoteServiceSettings& remoteServiceSettings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
4040 for (const QSharedPointer<IfdListEntry>& remoteDevice : pRemoteDevices)
4141 {
42 if (!remoteDevice->getIfdDescriptor().isSupported())
42 const auto& ifdDescriptor = remoteDevice->getIfdDescriptor();
43 if (!ifdDescriptor.isSupported() || ifdDescriptor.isPairingAnnounced())
4344 {
4445 continue;
4546 }
4647
47 const QString ifdId = remoteDevice->getIfdDescriptor().getIfdId();
48 const QString ifdId = ifdDescriptor.getIfdId();
4849
4950 // If already connected: skip.
5051 if (getDispatchers().contains(ifdId))
105106 {
106107 return Env::getSingleton<RemoteIfdClient>();
107108 }
108
109
110 bool RemoteIfdReaderManagerPlugIn::isInitialPairing(const QString& pIfdName, const QString& pId)
111 {
112 RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
113 auto info = settings.getRemoteInfo(pId);
114 bool initialPairing = false;
115 if (info.getNameEscaped().isEmpty())
116 {
117 initialPairing = true;
118 }
119 info.setNameUnescaped(pIfdName);
120 settings.updateRemoteInfo(info);
121
122 return initialPairing;
123 }
3939 void stopScan(const QString& pError = QString()) override;
4040
4141 protected:
42 bool isInitialPairing(const QString& pIfdName, const QString& pId) override;
4342 IfdClient* getIfdClient() override;
4443
4544 };
3131 const auto& remoteServiceSettings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
3232 const auto& ifdId = QString::fromLatin1(remoteServiceSettings.getCertificate().toPem());
3333 quint16 port = mWebSocketServer->getServerPort();
34 mRemoteReaderAdvertiser.reset(Env::create<RemoteReaderAdvertiser*>(ifdName, ifdId, port));
34 bool isPairing = mWebSocketServer->isPairingAnnounced();
35 mRemoteReaderAdvertiser.reset(Env::create<RemoteReaderAdvertiser*>(ifdName, ifdId, port, isPairing));
3536 }
3637
3738 Q_EMIT fireConnectedChanged(pConnected);
1717 namespace governikus
1818 {
1919
20 template<> RemoteReaderAdvertiser* createNewObject<RemoteReaderAdvertiser*, const QString&, const QString&, quint16&>(const QString& pIfdName, const QString& pIfdId, quint16& pPort)
20 template<> RemoteReaderAdvertiser* createNewObject<RemoteReaderAdvertiser*, const QString&, const QString&, quint16&, bool&>(const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool& pIsPairing)
2121 {
22 return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort);
22 return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pIsPairing);
2323 }
2424
2525
5050 }
5151
5252
53 RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval, bool pPairing)
53 RemoteReaderAdvertiserImpl::RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing, int pTimerInterval)
5454 : RemoteReaderAdvertiser()
5555 , mHandler(Env::create<DatagramHandler*>(false))
5656 , mTimerId(startTimer(pTimerInterval))
5252
5353 public:
5454 ~RemoteReaderAdvertiserImpl() override;
55 RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, int pTimerInterval = 1000, bool pPairing = false);
55 RemoteReaderAdvertiserImpl(const QString& pIfdName, const QString& pIfdId, quint16 pPort, bool pPairing = false, int pTimerInterval = 1000);
5656
5757 void setPairing(bool pEnabled) override;
5858 };
109109 const auto& pairingCiphers = Env::getSingleton<SecureStorage>()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getCiphers();
110110 if (pairingCiphers.contains(cfg.sessionCipher()))
111111 {
112 qCDebug(ifd) << "Pairing completed | Add certificate:" << cfg.peerCertificate();
113 settings.addTrustedCertificate(cfg.peerCertificate());
112 const auto& sslCertificate = cfg.peerCertificate();
113 qCDebug(ifd) << "Pairing completed | Add certificate:" << sslCertificate;
114 settings.addTrustedCertificate(sslCertificate);
114115 setPairing(false);
115 Q_EMIT firePairingCompleted();
116 Q_EMIT firePairingCompleted(sslCertificate);
116117 }
117118 else
118119 {
3131 void onSslErrors(const QList<QSslError>& pErrors) override;
3232
3333 Q_SIGNALS:
34 void firePairingCompleted();
34 void firePairingCompleted(const QSslCertificate& pCertificate);
3535 };
3636
3737 } // namespace governikus
2121 ~RemoteWebSocketServer() override;
2222
2323 [[nodiscard]] virtual bool isPairingConnection() const = 0;
24 [[nodiscard]] virtual bool isPairingAnnounced() const = 0;
2425 virtual void setPairing(bool pEnable = true) = 0;
2526 [[nodiscard]] virtual QSslCertificate getCurrentCertificate() const = 0;
2627
2728 Q_SIGNALS:
28 void firePairingCompleted();
29 void firePairingCompleted(const QSslCertificate& pCertificate);
2930
3031 };
3132
102102 }
103103
104104
105 bool RemoteWebSocketServerImpl::isPairingAnnounced() const
106 {
107 return mRemoteTlsServer->hasPsk();
108 }
109
110
105111 void RemoteWebSocketServerImpl::setPairing(bool pEnable)
106112 {
107113 mRemoteTlsServer->setPairing(pEnable);
4444 const QSharedPointer<ServerMessageHandler>& getMessageHandler() const override;
4545
4646 [[nodiscard]] bool isPairingConnection() const override;
47 [[nodiscard]] bool isPairingAnnounced() const override;
4748 void setPairing(bool pEnable = true) override;
4849 [[nodiscard]] QSslCertificate getCurrentCertificate() const override;
4950 };
44 #include "NetworkManager.h"
55
66 #include "AppSettings.h"
7 #include "LogHandler.h"
78 #include "NetworkReplyError.h"
8 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
9 #include "NetworkReplyTimeout.h"
10 #endif
11 #include "LogHandler.h"
129 #include "SecureStorage.h"
1310 #include "TlsChecker.h"
1411 #include "VersionInfo.h"
334331 --mOpenConnectionCount;
335332 });
336333 connect(this, &NetworkManager::fireShutdown, pResponse, &QNetworkReply::abort, Qt::QueuedConnection);
337
338 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
339 NetworkReplyTimeout::setTimeout(this, pResponse, 30000);
340 #endif
341334 }
342335
343336 return QSharedPointer<QNetworkReply>(pResponse, &QObject::deleteLater);
+0
-49
src/network/NetworkReplyTimeout.cpp less more
0 /**
1 * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany
2 */
3
4 #include "NetworkReplyTimeout.h"
5
6 #include <QCoreApplication>
7
8 using namespace governikus;
9
10 NetworkReplyTimeout::NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout)
11 : QObject(pReply)
12 {
13 Q_ASSERT(pReply);
14 if (pReply == nullptr)
15 {
16 return;
17 }
18
19 connect(&mTimer, &QTimer::timeout, this, &NetworkReplyTimeout::onTimeout);
20 mTimer.setSingleShot(true);
21 mTimer.setInterval(pTimeout);
22 mTimer.start();
23 }
24
25
26 void NetworkReplyTimeout::onTimeout()
27 {
28 auto* reply = static_cast<QNetworkReply*>(parent());
29 if (reply != nullptr && reply->isRunning())
30 {
31 reply->abort();
32 }
33 }
34
35
36 void NetworkReplyTimeout::onShutdown()
37 {
38 mTimer.stop();
39 onTimeout();
40 }
41
42
43 void NetworkReplyTimeout::setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeout)
44 {
45 // since the QNetworkReply is set as parent, we don't need to care about destruction
46 const auto* timeout = new NetworkReplyTimeout(pReply, pTimeout);
47 connect(pManager, &NetworkManager::fireShutdown, timeout, &NetworkReplyTimeout::onShutdown);
48 }
+0
-40
src/network/NetworkReplyTimeout.h less more
0 /**
1 * Copyright (c) 2014-2023 Governikus GmbH & Co. KG, Germany
2 */
3
4 /*!
5 * \brief Utility class to set a timeout on a QNetworkReply
6 */
7
8 #pragma once
9
10 #include "NetworkManager.h"
11
12 #include <QNetworkReply>
13 #include <QTimer>
14
15 namespace governikus
16 {
17
18 class NetworkReplyTimeout
19 : public QObject
20 {
21 Q_OBJECT
22
23 private:
24 QTimer mTimer;
25
26 NetworkReplyTimeout(QNetworkReply* pReply, const int pTimeout);
27
28 private Q_SLOTS:
29 void onTimeout();
30 void onShutdown();
31
32 public:
33 /*!
34 * Set the timeout in milli-seconds on the specified QNetworkReply.
35 */
36 static void setTimeout(const NetworkManager* pManager, QNetworkReply* pReply, const int pTimeoutMilliSeconds);
37 };
38
39 } // namespace governikus
2424 {
2525 case UpdateType::APPCAST:
2626 mExplicitSuccessMessage = pForceUpdate;
27 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
28 mTimer.start(mOneDayInMs);
29 if (pForceUpdate || Env::getSingleton<AppSettings>()->getGeneralSettings().isAutoUpdateCheck())
27 if (Env::getSingleton<AppSettings>()->getGeneralSettings().isAutoUpdateAvailable())
3028 {
31 Q_UNUSED(Env::getSingleton<AppUpdater>()->checkAppUpdate(pForceUpdate))
32 break;
29 mTimer.start(mOneDayInMs);
30 if (pForceUpdate || Env::getSingleton<AppSettings>()->getGeneralSettings().isAutoUpdateCheck())
31 {
32 Q_UNUSED(Env::getSingleton<AppUpdater>()->checkAppUpdate(pForceUpdate))
33 break;
34 }
3335 }
34 #endif
36
3537 Q_FALLTHROUGH();
3638
3739 case UpdateType::PROVIDER:
446446
447447 bool GeneralSettings::isAutoUpdateAvailable() const
448448 {
449 #if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN) || defined(Q_OS_MACOS)
449 #if !defined(QT_NO_DEBUG) || defined(Q_OS_WIN)
450450 return true;
451451
452452 #else
2828 SETTINGS_NAME(SETTINGS_GROUP_NAME_REMOTEREADER, "remotereader")
2929 SETTINGS_NAME(SETTINGS_NAME_DEVICE_NAME, "serverName")
3030 SETTINGS_NAME(SETTINGS_NAME_PIN_PAD_MODE, "pinPadMode")
31 SETTINGS_NAME(SETTINGS_NAME_SHOW_ACCESS_RIGHTS, "showAccessRights")
3132 SETTINGS_NAME(SETTINGS_ARRAY_NAME_TRUSTED_CERTIFICATES, "trustedCertificates")
3233 SETTINGS_NAME(SETTINGS_NAME_TRUSTED_CERTIFICATE_ITEM, "certificate")
3334 SETTINGS_NAME(SETTINGS_NAME_TRUSTED_REMOTE_INFO, "trustedRemoteInfo")
8384
8485 bool RemoteServiceSettings::getPinPadMode() const
8586 {
86 return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), false).toBool();
87 return mStore->value(SETTINGS_NAME_PIN_PAD_MODE(), true).toBool();
8788 }
8889
8990
9091 void RemoteServiceSettings::setPinPadMode(bool pPinPadMode)
9192 {
9293 mStore->setValue(SETTINGS_NAME_PIN_PAD_MODE(), pPinPadMode);
94 save(mStore);
95 }
96
97
98 bool RemoteServiceSettings::getShowAccessRights() const
99 {
100 return mStore->value(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), false).toBool();
101 }
102
103
104 void RemoteServiceSettings::setShowAccessRights(bool pShowAccessRights)
105 {
106 mStore->setValue(SETTINGS_NAME_SHOW_ACCESS_RIGHTS(), pShowAccessRights);
93107 save(mStore);
94108 }
95109
228242
229243 RemoteServiceSettings::RemoteInfo RemoteServiceSettings::getRemoteInfo(const QSslCertificate& pCertificate) const
230244 {
245 if (pCertificate.isNull())
246 {
247 return RemoteInfo();
248 }
249
231250 return getRemoteInfo(generateFingerprint(pCertificate));
232251 }
233252
321340 iter.next();
322341 if (iter.value().getFingerprint() == pInfo.getFingerprint())
323342 {
343 const bool hadNoNameYet = iter.value().mName.isEmpty();
324344 iter.setValue(pInfo);
325345 setRemoteInfos(infos);
346 if (hadNoNameYet)
347 {
348 Q_EMIT fireInitialDeviceNameSet(pInfo.getNameEscaped());
349 }
326350 return true;
327351 }
328352 }
8888 [[nodiscard]] bool getPinPadMode() const;
8989 void setPinPadMode(bool pPinPadMode);
9090
91 [[nodiscard]] bool getShowAccessRights() const;
92 void setShowAccessRights(bool pShowAccessRights);
93
9194 [[nodiscard]] QList<QSslCertificate> getTrustedCertificates() const;
9295 void addTrustedCertificate(const QSslCertificate& pCertificate);
9396 void removeTrustedCertificate(const QSslCertificate& pCertificate);
111114 Q_SIGNALS:
112115 void fireTrustedCertificatesChanged();
113116 void fireTrustedRemoteInfosChanged();
117 void fireInitialDeviceNameSet(const QString& pName);
114118 };
115119
116120
386386 #ifdef Q_OS_IOS
387387 {
388388 const auto allowedStates = {MsgType::ENTER_PIN, MsgType::ENTER_CAN, MsgType::ENTER_PUK, MsgType::ENTER_NEW_PIN};
389 const auto lastPaceResult = mContext.getContext()->getLastPaceResult();
390 return handleCurrentState(cmdType, allowedStates, [lastPaceResult] {
391 switch (lastPaceResult)
389 const auto& workflowContext = mContext.getContext();
390 return handleCurrentState(cmdType, allowedStates, [&workflowContext] {
391 workflowContext->setInterruptRequested(true);
392 switch (workflowContext->getLastPaceResult())
392393 {
393394 case CardReturnCode::OK:
394395 case CardReturnCode::OK_PUK:
55
66 #include "context/AuthContext.h"
77 #include "context/ChangePinContext.h"
8 #include "context/IfdServiceContext.h"
89 #include "context/SelfAuthContext.h"
910
1011 #include "BuildHelper.h"
224225 if (mContext.objectCast<AuthContext>())
225226 {
226227 return Workflow::WORKFLOW_AUTHENTICATION;
228 }
229 if (mContext.objectCast<IfdServiceContext>())
230 {
231 return Workflow::WORKFLOW_REMOTE_SERVICE;
227232 }
228233 return Workflow::WORKFLOW_NONE;
229234 }
9696 WORKFLOW_SELF_AUTHENTICATION,
9797 WORKFLOW_AUTHENTICATION,
9898 WORKFLOW_SMART,
99 WORKFLOW_REMOTE_SERVICE,
99100 WORKFLOW_NONE
100101 };
101102 Q_ENUM(Workflow)
44 #include "CertificateDescriptionModel.h"
55
66 #include "LanguageLoader.h"
7 #include "context/AuthContext.h"
8 #include "context/IfdServiceContext.h"
79
810
911 using namespace governikus;
2022
2123 QSharedPointer<const CertificateDescription> CertificateDescriptionModel::getCertificateDescription() const
2224 {
23 if (mContext && mContext->getDidAuthenticateEac1())
25 if (const auto authContext = mContext.objectCast<AuthContext>(); authContext && authContext->getDidAuthenticateEac1())
2426 {
25 return mContext->getDidAuthenticateEac1()->getCertificateDescription();
27 return authContext->getDidAuthenticateEac1()->getCertificateDescription();
28 }
29
30 if (const auto ifdContext = mContext.objectCast<IfdServiceContext>(); ifdContext && ifdContext->getCertificateDescription())
31 {
32 return ifdContext->getCertificateDescription();
2633 }
2734
2835 return QSharedPointer<const CertificateDescription>();
8491 }
8592
8693
87 void CertificateDescriptionModel::resetContext(const QSharedPointer<AuthContext>& pContext)
94 void CertificateDescriptionModel::resetContext(const QSharedPointer<WorkflowContext>& pContext)
8895 {
8996 mContext = pContext;
90 if (mContext)
97 if (auto authContext = pContext.objectCast<AuthContext>())
9198 {
92 connect(mContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed);
93 connect(mContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed);
99 connect(authContext.data(), &AuthContext::fireDidAuthenticateEac1Changed, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed);
100 connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed);
101 }
102 else if (auto ifdContext = pContext.objectCast<IfdServiceContext>())
103 {
104 connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &CertificateDescriptionModel::onDidAuthenticateEac1Changed);
94105 }
95106
96107 onDidAuthenticateEac1Changed();
120131
121132 QString CertificateDescriptionModel::getValidity() const
122133 {
123 if (mContext && mContext->getAccessRightManager() && mContext->getAccessRightManager()->getTerminalCvc())
134 if (const auto authContext = mContext.objectCast<AuthContext>(); authContext&& authContext->getAccessRightManager() && authContext->getAccessRightManager()->getTerminalCvc())
124135 {
125 const CVCertificateBody body = mContext->getAccessRightManager()->getTerminalCvc()->getBody();
136 const CVCertificateBody body = authContext->getAccessRightManager()->getTerminalCvc()->getBody();
126137 const auto locale = LanguageLoader::getInstance().getUsedLocale();
127138 const auto effectiveDate = locale.toString(body.getCertificateEffectiveDate(), QLocale::ShortFormat);
128139 const auto expirationDate = locale.toString(body.getCertificateExpirationDate(), QLocale::ShortFormat);
99
1010 #include "Env.h"
1111 #include "asn1/CertificateDescription.h"
12 #include "context/AuthContext.h"
12 #include "context/WorkflowContext.h"
1313
1414 #include <QAbstractListModel>
1515 #include <QPair>
3131
3232 private:
3333 QVector<QPair<QString, QString>> mData;
34 QSharedPointer<AuthContext> mContext;
34 QSharedPointer<WorkflowContext> mContext;
3535
3636 CertificateDescriptionModel();
3737 ~CertificateDescriptionModel()override = default;
5353 TEXT
5454 };
5555
56 void resetContext(const QSharedPointer<AuthContext>& pContext = QSharedPointer<AuthContext>());
56 void resetContext(const QSharedPointer<WorkflowContext>& pContext = QSharedPointer<WorkflowContext>());
5757
5858 [[nodiscard]] QString getSubjectName() const;
5959 [[nodiscard]] QString getSubjectUrl() const;
1010 #include "AppSettings.h"
1111 #include "asn1/AccessRoleAndRight.h"
1212 #include "asn1/CVCertificate.h"
13 #include "context/AuthContext.h"
14 #include "context/IfdServiceContext.h"
1315 #include "context/SelfAuthContext.h"
1416
1517 using namespace governikus;
1618
1719 ChatModel::ChatModel()
1820 : QAbstractListModel()
19 , mAuthContext()
21 , mContext()
2022 , mAllRights()
2123 , mOptionalRights()
2224 , mSelectedRights()
4850 }
4951
5052
51 void ChatModel::resetContext(const QSharedPointer<AuthContext>& pContext)
52 {
53 mAuthContext = pContext;
53 void ChatModel::resetContext(const QSharedPointer<WorkflowContext>& pContext)
54 {
55 mContext = pContext;
5456
5557 beginResetModel();
5658
6062
6163 endResetModel();
6264
63 if (!pContext.isNull())
64 {
65 connect(pContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged);
65 if (auto authContext = pContext.objectCast<AuthContext>())
66 {
67 connect(authContext.data(), &AuthContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged);
68 }
69 else if (auto ifdContext = pContext.objectCast<IfdServiceContext>())
70 {
71 connect(ifdContext.data(), &IfdServiceContext::fireAccessRightManagerCreated, this, &ChatModel::onAuthenticationDataChanged);
6672 }
6773 }
6874
112118
113119 QVariant ChatModel::data(const QModelIndex& pIndex, int pRole) const
114120 {
115 if (pIndex.isValid() && pIndex.row() < rowCount())
116 {
117 auto right = mAllRights.at(pIndex.row());
118 if (pRole == Qt::DisplayRole || pRole == NAME_ROLE)
121 if (!pIndex.isValid() || pIndex.row() >= rowCount())
122 {
123 return QVariant();
124 }
125
126 const auto& right = mAllRights.at(pIndex.row());
127 switch (pRole)
128 {
129 case Qt::DisplayRole:
130 case NAME_ROLE:
119131 {
120132 QString displayText = AccessRoleAndRightsUtil::toDisplayText(right);
121133 if (right == AccessRight::AGE_VERIFICATION)
122134 {
123 displayText += QStringLiteral(" (%1)").arg(mAuthContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge());
135 if (auto authContext = mContext.objectCast<AuthContext>())
136 {
137 displayText += QStringLiteral(" (%1)").arg(authContext->getDidAuthenticateEac1()->getAuthenticatedAuxiliaryData()->getRequiredAge());
138 }
124139 }
125140 return displayText;
126141 }
127 if (pRole == OPTIONAL_ROLE)
128 {
142
143 case OPTIONAL_ROLE:
129144 return mOptionalRights.contains(right);
130 }
131 if (pRole == SELECTED_ROLE)
132 {
145
146 case SELECTED_ROLE:
133147 return mSelectedRights.contains(right);
134 }
135 if (pRole == WRITE_RIGHT)
136 {
148
149 case WRITE_RIGHT:
137150 return AccessRoleAndRightsUtil::isWriteAccessRight(right);
138 }
139 }
140 return QVariant();
151
152 default:
153 Q_UNREACHABLE();
154 return QVariant();
155 }
141156 }
142157
143158
184199
185200 void ChatModel::transferAccessRights()
186201 {
187 Q_ASSERT(mAuthContext->getAccessRightManager());
188
189 *mAuthContext->getAccessRightManager() = mSelectedRights;
202 if (auto authContext = mContext.objectCast<AuthContext>())
203 {
204 Q_ASSERT(authContext->getAccessRightManager());
205 *authContext->getAccessRightManager() = mSelectedRights;
206 }
190207 }
191208
192209
1414 #include <QSortFilterProxyModel>
1515
1616 #include "Env.h"
17 #include "context/AuthContext.h"
17 #include "context/AccessRightManager.h"
18 #include "context/WorkflowContext.h"
1819
1920 class test_ChatModel;
2021
3536 Q_PROPERTY(QSortFilterProxyModel * write READ getFilterWriteModel CONSTANT)
3637
3738 private:
38 QSharedPointer<AuthContext> mAuthContext;
39 QSharedPointer<WorkflowContext> mContext;
3940 QList<AccessRight> mAllRights;
4041 QSet<AccessRight> mOptionalRights;
4142 QSet<AccessRight> mSelectedRights;
6263 void onAuthenticationDataChanged(QSharedPointer<AccessRightManager> pAccessRightManager);
6364
6465 public:
65 void resetContext(const QSharedPointer<AuthContext>& pContext = QSharedPointer<AuthContext>());
66 void resetContext(const QSharedPointer<WorkflowContext>& pContext = QSharedPointer<WorkflowContext>());
6667
6768 [[nodiscard]] int rowCount(const QModelIndex& = QModelIndex()) const override;
6869 [[nodiscard]] QVariant data(const QModelIndex& pIndex, int pRole = Qt::DisplayRole) const override;
2424 }
2525
2626 const QModelIndex& modelIndex = dataSourceModel->index(pSourceRow, 0);
27 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString
2728 if (dataSourceModel->data(modelIndex, HistoryModel::DATETIME).toDateTime().toString(tr("dd.MM.yyyy")).contains(mFilterString, Qt::CaseInsensitive)
2829 || dataSourceModel->data(modelIndex, HistoryModel::SUBJECT).toString().contains(mFilterString, Qt::CaseInsensitive)
2930 || dataSourceModel->data(modelIndex, HistoryModel::PURPOSE).toString().contains(mFilterString, Qt::CaseInsensitive)
124124 {
125125 if (!entry.isEmpty())
126126 {
127 //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString
127128 logFileNames += LanguageLoader::getInstance().getUsedLocale().toString(LogHandler::getFileDate(QFileInfo(entry)), tr("dd.MM.yyyy hh:mm:ss"));
128129 }
129130 }
4040 }
4141
4242 beginInsertRows(QModelIndex(), mNotificationEntries.size(), mNotificationEntries.size());
43 //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString
4344 const auto& time = QTime::currentTime().toString(tr("hh:mm:ss"));
4445 mNotificationEntries.append({pCategoryName, time, pMsg});
4546 endInsertRows();
33
44 #include "PinResetInformationModel.h"
55
6 #include "LanguageLoader.h"
67 #include "ProviderConfiguration.h"
78
9
810 using namespace governikus;
11
912
1013 PinResetInformationModel::PinResetInformationModel()
1114 : QObject()
2427 if (homepage.isEmpty())
2528 {
2629 return tr("https://www.personalausweisportal.de/EN");
30 }
31
32 if (LanguageLoader::getLocaleCode() != QStringLiteral("de"))
33 {
34 return homepage + QStringLiteral("/en");
2735 }
2836
2937 return homepage;
254254 return QString();
255255 }
256256
257 //: LABEL ALL_PLATFORMS Time format according to https://doc.qt.io/qt/qtime.html#toString
257258 const auto& updateTime = LanguageLoader::getInstance().getUsedLocale().toString(mConnectedReadersUpdateTime, tr("hh:mm:ss AP"));
258259 //: LABEL ALL_PLATFORMS
259260 return tr("The list of card readers was last updated at %1.").arg(updateTime);
0 /**
1 * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany
2 */
3
4 #include "RemoteDeviceFilterModel.h"
5
6 #include "RemoteDeviceModel.h"
7
8 using namespace governikus;
9 using namespace std::placeholders;
10
11
12 RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction)
13 : QSortFilterProxyModel()
14 , mFilterToApply(pFilterFunction)
15 {
16 QSortFilterProxyModel::setSourceModel(pSourceModel);
17 }
18
19
20 RemoteDeviceFilterModel::ShowAvailableAndPaired RemoteDeviceFilterModel::showAvailableAndPaired = {};
21 RemoteDeviceFilterModel::ShowUnavailableAndPaired RemoteDeviceFilterModel::showUnavailableAndPaired = {};
22 RemoteDeviceFilterModel::ShowActivePairingMode RemoteDeviceFilterModel::showActivePairingMode = {};
23
24
25 RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired)
26 : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::availableNotPairing, this, _1, _2))
27 {
28 }
29
30
31 RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired)
32 : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::unavailableAndPaired, this, _1, _2))
33 {
34 }
35
36
37 RemoteDeviceFilterModel::RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode)
38 : RemoteDeviceFilterModel(pSourceModel, std::bind(&RemoteDeviceFilterModel::isPairing, this, _1, _2))
39 {
40 }
41
42
43 bool RemoteDeviceFilterModel::available(int pSourceRow, const QModelIndex& pSourceParent) const
44 {
45 const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent);
46 const bool isNetworkVisible = sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE).toBool();
47 return isNetworkVisible;
48 }
49
50
51 bool RemoteDeviceFilterModel::isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const
52 {
53 const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent);
54 return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED).toBool();
55 }
56
57
58 bool RemoteDeviceFilterModel::availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const
59 {
60 return available(pSourceRow, pSourceParent) && !isPairing(pSourceRow, pSourceParent);
61 }
62
63
64 bool RemoteDeviceFilterModel::unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const
65 {
66 return !available(pSourceRow, pSourceParent) && isDevicePaired(pSourceRow, pSourceParent);
67 }
68
69
70 bool RemoteDeviceFilterModel::isPairing(int pSourceRow, const QModelIndex& pSourceParent) const
71 {
72 const QModelIndex index = sourceModel()->index(pSourceRow, 0, pSourceParent);
73 return sourceModel()->data(index, RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING).toBool();
74 }
75
76
77 bool RemoteDeviceFilterModel::filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const
78 {
79 return mFilterToApply(pSourceRow, pSourceParent);
80 }
0 /**
1 * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany
2 */
3
4 #pragma once
5
6 #include <QSortFilterProxyModel>
7
8 class test_RemoteDeviceFilterModel;
9
10 namespace governikus
11 {
12
13 class RemoteDeviceFilterModel
14 : public QSortFilterProxyModel
15 {
16 friend class ::test_RemoteDeviceFilterModel;
17
18 private:
19 using FilterFunctionType = std::function<bool (int pSourceRow, const QModelIndex& pSourceParent)>;
20 FilterFunctionType mFilterToApply;
21
22 RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, const FilterFunctionType& pFilterFunction);
23
24 public:
25 struct ShowAvailableAndPaired {};
26 struct ShowUnavailableAndPaired {};
27 struct ShowActivePairingMode {};
28
29 static ShowAvailableAndPaired showAvailableAndPaired;
30 static ShowUnavailableAndPaired showUnavailableAndPaired;
31 static ShowActivePairingMode showActivePairingMode;
32
33 RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowAvailableAndPaired);
34 RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowUnavailableAndPaired);
35 RemoteDeviceFilterModel(QAbstractItemModel* pSourceModel, ShowActivePairingMode);
36
37 ~RemoteDeviceFilterModel() override = default;
38
39 private:
40 [[nodiscard]] bool available(int pSourceRow, const QModelIndex& pSourceParent) const;
41 [[nodiscard]] bool isDevicePaired(int pSourceRow, const QModelIndex& pSourceParent) const;
42
43 [[nodiscard]] bool availableNotPairing(int pSourceRow, const QModelIndex& pSourceParent) const;
44 [[nodiscard]] bool unavailableAndPaired(int pSourceRow, const QModelIndex& pSourceParent) const;
45 [[nodiscard]] bool isPairing(int pSourceRow, const QModelIndex& pSourceParent) const;
46
47 protected:
48 [[nodiscard]] bool filterAcceptsRow(int pSourceRow, const QModelIndex& pSourceParent) const override;
49 };
50
51 } // namespace governikus
1515
1616 using namespace governikus;
1717
18 RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QString& pDeviceNameEscaped,
19 const QString& pId,
20 const QSharedPointer<IfdListEntry>& pRemoteDeviceListEntry)
21 : mDeviceName(pDeviceNameEscaped)
22 , mId(pId)
18 RemoteDeviceModelEntry::RemoteDeviceModelEntry(const QSharedPointer<IfdListEntry>& pListEntry)
19 : mDeviceName(RemoteServiceSettings::escapeDeviceName(pListEntry->getIfdDescriptor().getIfdName()))
20 , mId(pListEntry->getIfdDescriptor().getIfdId())
2321 , mPaired(false)
22 , mIsPairing(pListEntry->getIfdDescriptor().isPairingAnnounced())
2423 , mNetworkVisible(false)
2524 , mConnected(false)
26 , mSupported(pRemoteDeviceListEntry->getIfdDescriptor().isSupported())
25 , mSupported(pListEntry->getIfdDescriptor().isSupported())
2726 , mLastConnected()
28 , mRemoteDeviceListEntry(pRemoteDeviceListEntry)
27 , mRemoteDeviceListEntry(pListEntry)
2928 {
3029 Q_ASSERT(!mDeviceName.contains(QLatin1Char('<')));
3130 }
3635 bool pNetworkVisible,
3736 bool pConnected,
3837 bool pSupported,
38 bool pIsPairing,
3939 const QDateTime& pLastConnected,
4040 const QSharedPointer<IfdListEntry>& pRemoteDeviceListEntry)
4141 : mDeviceName(pDeviceNameEscaped)
4242 , mId(pId)
4343 , mPaired(true)
44 , mIsPairing(pIsPairing)
4445 , mNetworkVisible(pNetworkVisible)
4546 , mConnected(pConnected)
4647 , mSupported(pSupported)
5556 : mDeviceName(pDeviceNameEscaped)
5657 , mId()
5758 , mPaired(false)
59 , mIsPairing(false)
5860 , mNetworkVisible(false)
5961 , mConnected(false)
6062 , mSupported(false)
8688 void RemoteDeviceModelEntry::setPaired(bool pPaired)
8789 {
8890 mPaired = pPaired;
91 }
92
93
94 bool RemoteDeviceModelEntry::isPairing() const
95 {
96 return mIsPairing;
97 }
98
99
100 void RemoteDeviceModelEntry::setIsPairing(bool pIsPairing)
101 {
102 mIsPairing = pIsPairing;
89103 }
90104
91105
190204 roles.insert(IS_NETWORK_VISIBLE, QByteArrayLiteral("isNetworkVisible"));
191205 roles.insert(IS_SUPPORTED, QByteArrayLiteral("isSupported"));
192206 roles.insert(IS_PAIRED, QByteArrayLiteral("isPaired"));
207 roles.insert(IS_PAIRING, QByteArrayLiteral("isPairing"));
193208 roles.insert(LINK_QUALITY, QByteArrayLiteral("linkQualityInPercent"));
209 roles.insert(IS_LAST_ADDED_DEVICE, QByteArrayLiteral("isLastAddedDevice"));
194210 return roles;
195211 }
196212
219235 {
220236 //: LABEL ALL_PLATFORMS
221237 return tr("Not connected");
238 }
239
240 if (pRemoteDeviceModelEntry.isPairing())
241 {
242 //: LABEL ALL_PLATFORMS
243 return tr("Click to pair");
222244 }
223245
224246 if (pRemoteDeviceModelEntry.isPaired())
234256 return tr("Paired, but unsupported");
235257 }
236258 //: LABEL ALL_PLATFORMS
237 return tr("Paired, but unavailable");
259 return tr("Unavailable");
238260 }
239261
240262 if (!pRemoteDeviceModelEntry.isSupported())
258280 bool visible = false;
259281 bool connected = false;
260282 bool supported = true;
283 bool isPairing = false;
261284 QSharedPointer<IfdListEntry> deviceListEntry;
262285 for (const auto& availableReader : availableReaders)
263286 {
266289 visible = true;
267290 connected = connectedDeviceIDs.contains(availableReader.getId());
268291 supported = availableReader.isSupported();
292 isPairing = availableReader.isPairing();
269293 deviceListEntry = availableReader.getRemoteDeviceListEntry();
270294 break;
271295 }
283307 visible,
284308 connected,
285309 supported,
310 isPairing,
286311 pairedReader.getLastConnected(),
287312 deviceListEntry);
288313 addOrUpdateReader(modelEntry);
335360 const auto& announcingRemoteDevices = Env::getSingleton<RemoteIfdClient>()->getAnnouncingRemoteDevices();
336361 QVector<RemoteDeviceModelEntry> presentReaders;
337362
338 for (auto deviceListEntry : announcingRemoteDevices)
339 {
340 const auto& deviceDescriptor = deviceListEntry->getIfdDescriptor();
341 auto modelEntry = RemoteDeviceModelEntry(RemoteServiceSettings::escapeDeviceName(deviceDescriptor.getIfdName()), deviceDescriptor.getIfdId(), deviceListEntry);
363 for (auto& deviceListEntry : announcingRemoteDevices)
364 {
365 auto modelEntry = RemoteDeviceModelEntry(deviceListEntry);
342366 presentReaders.append(modelEntry);
343367 }
344368
381405 const auto& reader = mAllRemoteReaders.at(pIndex.row());
382406 switch (pRole)
383407 {
408 case Qt::DisplayRole:
384409 case REMOTE_DEVICE_NAME:
385410 return reader.getDeviceNameEscaped();
386411
390415 case LAST_CONNECTED:
391416 {
392417 const auto& locale = LanguageLoader::getInstance().getUsedLocale();
418
419 //: LABEL ALL_PLATFORMS Datetime format according to https://doc.qt.io/qt/qdate.html#toString and https://doc.qt.io/qt/qtime.html#toString
393420 const auto& dateTimeFormat = tr("dd.MM.yyyy hh:mm AP");
394421 return locale.toString(reader.getLastConnected(), dateTimeFormat);
395422 }
406433 case IS_PAIRED:
407434 return isPaired(pIndex);
408435
436 case IS_PAIRING:
437 return isPairing(pIndex);
438
409439 case LINK_QUALITY:
410440 return reader.getLinkQuality();
441
442 case IS_LAST_ADDED_DEVICE:
443 return mLastPairedDevice.getFingerprint() == reader.getId();
411444 }
412445
413446 return QVariant();
447480 }
448481
449482 return mAllRemoteReaders.at(pIndex.row()).isPaired();
483 }
484
485
486 bool RemoteDeviceModel::isPairing(const QModelIndex& pIndex) const
487 {
488 if (!indexIsValid(pIndex))
489 {
490 return false;
491 }
492
493 return mAllRemoteReaders.at(pIndex.row()).isPairing();
450494 }
451495
452496
584628 }
585629
586630
631 void RemoteDeviceModel::setLastPairedReader(const QSslCertificate& pCert)
632 {
633 const RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
634 mLastPairedDevice = settings.getRemoteInfo(pCert);
635 Q_EMIT dataChanged(index(0), index(rowCount() - 1), {IS_LAST_ADDED_DEVICE});
636 }
637
638
587639 void RemoteDeviceModel::onDeviceDisconnected(GlobalStatus::Code pCloseCode, const QString& pId)
588640 {
589641 Q_UNUSED(pCloseCode)
2020 #include <QVector>
2121
2222 class test_RemoteDeviceModel;
23 class test_RemoteDeviceFilterModel;
2324
2425 namespace governikus
2526 {
3233 QString mDeviceName;
3334 QString mId;
3435 bool mPaired;
36 bool mIsPairing;
3537 bool mNetworkVisible;
3638 bool mConnected;
3739 bool mSupported;
3941 QSharedPointer<IfdListEntry> mRemoteDeviceListEntry;
4042
4143 public:
42 RemoteDeviceModelEntry(const QString& pDeviceNameEscaped,
43 const QString& mId,
44 const QSharedPointer<IfdListEntry>& pRemoteDeviceListEntry);
44 explicit RemoteDeviceModelEntry(const QSharedPointer<IfdListEntry>& pListEntry);
4545 RemoteDeviceModelEntry(const QString& pDeviceNameEscaped,
4646 const QString& mId,
4747 bool pNetworkVisible,
4848 bool pConnected,
4949 bool pSupported,
50 bool pIsPairing,
5051 const QDateTime& pLastConnected,
5152 const QSharedPointer<IfdListEntry>& pRemoteDeviceListEntry);
5253 explicit RemoteDeviceModelEntry(const QString& pDeviceNameEscaped = QStringLiteral("UnknownReader"));
5354
5455 [[nodiscard]] bool isPaired() const;
5556 void setPaired(bool pPaired);
57 [[nodiscard]] bool isPairing() const;
58 void setIsPairing(bool pIsPairing);
5659 [[nodiscard]] const QString& getId() const;
5760 void setId(const QString& pId);
5861 [[nodiscard]] bool isNetworkVisible() const;
7477 Q_OBJECT
7578 Q_PROPERTY(QString emptyListDescriptionString READ getEmptyListDescriptionString NOTIFY fireModelChanged)
7679 friend class ::test_RemoteDeviceModel;
80 friend class ::test_RemoteDeviceFilterModel;
7781
7882 private:
7983 QMap<QString, RemoteServiceSettings::RemoteInfo> mPairedReaders;
8084 QVector<RemoteDeviceModelEntry> mAllRemoteReaders;
85 RemoteServiceSettings::RemoteInfo mLastPairedDevice;
8186 const bool mShowPairedReaders;
8287 const bool mShowUnpairedReaders;
8388 QTimer mTimer;
111116 IS_NETWORK_VISIBLE,
112117 IS_SUPPORTED,
113118 IS_PAIRED,
114 LINK_QUALITY
119 IS_PAIRING,
120 LINK_QUALITY,
121 IS_LAST_ADDED_DEVICE
115122 };
116123
117124 RemoteDeviceModel(QObject* pParent = nullptr, bool pShowPairedReaders = true, bool pShowUnpairedReaders = true);
123130 [[nodiscard]] QSharedPointer<IfdListEntry> getRemoteDeviceListEntry(const QModelIndex& pIndex) const;
124131 [[nodiscard]] QSharedPointer<IfdListEntry> getRemoteDeviceListEntry(const QString& pDeviceId) const;
125132 [[nodiscard]] bool isPaired(const QModelIndex& pIndex) const;
133 [[nodiscard]] bool isPairing(const QModelIndex& pIndex) const;
126134 [[nodiscard]] bool isSupported(const QModelIndex& pIndex) const;
127135 void forgetDevice(const QModelIndex& pIndex);
128136 void forgetDevice(const QString& pDeviceId);
129137
130138 [[nodiscard]] QString getEmptyListDescriptionString() const;
139
140 void setLastPairedReader(const QSslCertificate& pCert);
131141
132142 public Q_SLOTS:
133143 void setDetectRemoteDevices(bool pNewStatus);
1616
1717
1818 using namespace governikus;
19
20
21 namespace
22 {
23 const QRegularExpression percentMatcher = QRegularExpression(QStringLiteral("(\\s|^)(100|\\d{1,2}) ?%"));
24 } // namespace
1925
2026
2127 RemoteServiceModel::RemoteServiceModel()
2733 , mPairingRequested(false)
2834 , mErrorMessage()
2935 , mPsk()
30 , mAvailableRemoteDevices(this, false, true)
31 , mKnownDevices(this, true, false)
36 , mAllDevices(this, true, true)
37 , mAvailableDevicesInPairingMode(&mAllDevices, RemoteDeviceFilterModel::showActivePairingMode)
38 , mAvailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showAvailableAndPaired)
39 , mUnavailablePairedDevices(&mAllDevices, RemoteDeviceFilterModel::showUnavailableAndPaired)
3240 , mConnectionInfo()
3341 , mConnectedServerDeviceNames()
3442 , mRememberedServerEntry()
4149 , mRequiresLocalNetworkPermission(false)
4250 #endif
4351 {
52 QQmlEngine::setObjectOwnership(&mAllDevices, QQmlEngine::CppOwnership);
53 QQmlEngine::setObjectOwnership(&mAvailableDevicesInPairingMode, QQmlEngine::CppOwnership);
54 QQmlEngine::setObjectOwnership(&mAvailablePairedDevices, QQmlEngine::CppOwnership);
55 QQmlEngine::setObjectOwnership(&mUnavailablePairedDevices, QQmlEngine::CppOwnership);
56
4457 const auto readerManager = Env::getSingleton<ReaderManager>();
4558 connect(readerManager, &ReaderManager::firePluginAdded, this, &RemoteServiceModel::onEnvironmentChanged);
4659 connect(readerManager, &ReaderManager::fireStatusChanged, this, &RemoteServiceModel::onEnvironmentChanged);
5871 connect(ifdClient, &IfdClient::fireDeviceVanished, this, &RemoteServiceModel::fireRemoteReaderVisibleChanged);
5972 connect(ifdClient, &IfdClient::fireCertificateRemoved, this, &RemoteServiceModel::fireCertificateRemoved);
6073
74 connect(this, &WorkflowModel::fireReaderPlugInTypeChanged, this, &RemoteServiceModel::onReaderPlugInTypesChanged);
75
76 const RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
77 connect(&settings, &RemoteServiceSettings::fireInitialDeviceNameSet, this, [](const QString& pName){
78 //: LABEL ALL_PLATFORMS
79 Env::getSingleton<ApplicationModel>()->showFeedback(tr("Pairing with %1 successful.").arg(pName));
80 });
81
6182 QMetaObject::invokeMethod(this, &RemoteServiceModel::onEnvironmentChanged, Qt::QueuedConnection);
6283 }
6384
113134 }
114135
115136
137 void RemoteServiceModel::onPairingCompleted(const QSslCertificate& pCertificate)
138 {
139 mAllDevices.setLastPairedReader(pCertificate);
140 Q_EMIT firePairingCompleted();
141 }
142
143
116144 void RemoteServiceModel::onTranslationChanged()
117145 {
118146 onEnvironmentChanged();
147 }
148
149
150 void RemoteServiceModel::onReaderPlugInTypesChanged(bool pExplicitStart)
151 {
152 if (!mContext)
153 {
154 return;
155 }
156
157 const auto& plugInType = getReaderPlugInType();
158 if (mContext->getIfdServer() && mContext->getIfdServer()->getMessageHandler())
159 {
160 mContext->getIfdServer()->getMessageHandler()->setAllowedCardTypes({plugInType});
161 }
162 auto* readerManager = Env::getSingleton<ReaderManager>();
163 readerManager->stopScanAll();
164 #ifdef Q_OS_IOS
165 if (plugInType != ReaderManagerPlugInType::NFC || pExplicitStart)
166 #else
167 Q_UNUSED(pExplicitStart)
168 #endif
169 {
170 readerManager->startScan(plugInType);
171 }
119172 }
120173
121174
169222 }
170223
171224
172 RemoteDeviceModel* RemoteServiceModel::getAvailableRemoteDevices()
173 {
174 return &mAvailableRemoteDevices;
175 }
176
177
178 RemoteDeviceModel* RemoteServiceModel::getKnownDevices()
179 {
180 return &mKnownDevices;
225 RemoteDeviceModel* RemoteServiceModel::getAllDevices()
226 {
227 return &mAllDevices;
228 }
229
230
231 RemoteDeviceFilterModel* RemoteServiceModel::getAvailablePairedDevices()
232 {
233 return &mAvailablePairedDevices;
234 }
235
236
237 RemoteDeviceFilterModel* RemoteServiceModel::getAvailableDevicesInPairingMode()
238 {
239 return &mAvailableDevicesInPairingMode;
240 }
241
242
243 RemoteDeviceFilterModel* RemoteServiceModel::getUnavailablePairedDevices()
244 {
245 return &mUnavailablePairedDevices;
181246 }
182247
183248
184249 void RemoteServiceModel::setDetectRemoteDevices(bool pNewStatus)
185250 {
186 mAvailableRemoteDevices.setDetectRemoteDevices(pNewStatus);
187 mKnownDevices.setDetectRemoteDevices(pNewStatus);
251 mAllDevices.setDetectRemoteDevices(pNewStatus);
188252 }
189253
190254
207271 }
208272
209273
274 QVector<ReaderManagerPlugInType> RemoteServiceModel::getSupportedReaderPlugInTypes() const
275 {
276 #if __has_include("SmartManager.h")
277 return {ReaderManagerPlugInType::NFC, ReaderManagerPlugInType::SMART};
278
279 #else
280 return {ReaderManagerPlugInType::NFC};
281
282 #endif
283 }
284
285
210286 bool RemoteServiceModel::rememberServer(const QString& pDeviceId)
211287 {
212 mRememberedServerEntry = mAvailableRemoteDevices.getRemoteDeviceListEntry(pDeviceId);
288 mRememberedServerEntry = mAllDevices.getRemoteDeviceListEntry(pDeviceId);
213289 return !mRememberedServerEntry.isNull();
214290 }
215291
226302 }
227303 else
228304 {
229 Q_EMIT firePairingSuccess(deviceName);
305 Q_EMIT firePairingSuccess();
230306 }
231307 }
232308
235311 {
236312 if (mContext && pConnected)
237313 {
238 const RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
239 const QString peerName = settings.getRemoteInfo(mContext->getIfdServer()->getCurrentCertificate()).getNameEscaped();
240314 //: 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.
241 mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(peerName);
315 mConnectionInfo = tr("Please pay attention to the display on your other device \"%1\".").arg(getConnectedClientName());
242316 Q_EMIT fireConnectionInfoChanged();
317 }
318 else if (mContext)
319 {
320 mContext->setReaderPlugInTypes({});
243321 }
244322 Q_EMIT fireConnectedChanged();
245323 }
274352 mPsk = pPsk;
275353 });
276354 connect(mContext->getIfdServer().data(), &IfdServer::firePskChanged, this, &RemoteServiceModel::firePskChanged);
355 connect(mContext.data(), &IfdServiceContext::fireDisplayTextChanged, this, &RemoteServiceModel::fireDisplayTextChanged);
277356 connect(mContext->getIfdServer().data(), &IfdServer::fireConnectedChanged, this, &RemoteServiceModel::onConnectionInfoChanged);
278 connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::firePairingCompleted);
357 connect(mContext->getIfdServer().data(), &IfdServer::firePairingCompleted, this, &RemoteServiceModel::onPairingCompleted);
279358 connect(mContext.data(), &IfdServiceContext::fireCardConnected, this, &RemoteServiceModel::onCardConnected);
280359 connect(mContext.data(), &IfdServiceContext::fireCardDisconnected, this, &RemoteServiceModel::onCardDisconnected);
281360 connect(mContext.data(), &IfdServiceContext::fireEstablishPaceChannelUpdated, this, &RemoteServiceModel::fireEstablishPaceChannelUpdated);
356435 }
357436
358437
438 QString RemoteServiceModel::getDisplayText() const
439 {
440 QString displayText = mContext ? mContext->getDisplayText() : QString();
441 return displayText.remove(percentMatcher);
442 }
443
444
445 int RemoteServiceModel::getPercentage() const
446 {
447 QString displayText = mContext ? mContext->getDisplayText() : QString();
448 return percentMatcher.match(displayText).captured(2).toInt();
449 }
450
451
359452 QString RemoteServiceModel::getConnectionInfo() const
360453 {
361454 return mConnectionInfo;
371464 bool RemoteServiceModel::getRemoteReaderVisible() const
372465 {
373466 return Env::getSingleton<RemoteIfdClient>()->hasAnnouncingRemoteDevices();
467 }
468
469
470 QString RemoteServiceModel::getTransactionInfo() const
471 {
472 return QString();
473 }
474
475
476 QString RemoteServiceModel::getConnectedClientName() const
477 {
478 if (mContext)
479 {
480 const auto& sslCertificate = mContext->getIfdServer()->getCurrentCertificate();
481 const RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
482 return settings.getRemoteInfo(sslCertificate).getNameEscaped();
483 }
484
485 return QString();
374486 }
375487
376488
404516
405517 void RemoteServiceModel::forgetDevice(const QString& pId)
406518 {
407 mKnownDevices.forgetDevice(pId);
519 mAllDevices.forgetDevice(pId);
408520 }
409521
410522
99
1010 #include "Env.h"
1111 #include "ReaderManager.h"
12 #include "RemoteDeviceFilterModel.h"
1213 #include "RemoteDeviceModel.h"
1314 #include "WorkflowModel.h"
1415 #include "WorkflowRequest.h"
3334 Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY fireEnvironmentChanged)
3435 Q_PROPERTY(bool isPairing READ isPairing NOTIFY firePskChanged)
3536 Q_PROPERTY(QByteArray psk READ getPsk NOTIFY firePskChanged)
37 Q_PROPERTY(QString displayText READ getDisplayText NOTIFY fireDisplayTextChanged)
38 Q_PROPERTY(int percentage READ getPercentage NOTIFY fireDisplayTextChanged)
3639 Q_PROPERTY(bool connectedToPairedDevice READ isConnectedToPairedDevice NOTIFY fireConnectedChanged)
3740 Q_PROPERTY(QString connectionInfo READ getConnectionInfo NOTIFY fireConnectionInfoChanged)
3841 Q_PROPERTY(QString connectedServerDeviceNames READ getConnectedServerDeviceNames NOTIFY fireConnectedServerDeviceNamesChanged)
39 Q_PROPERTY(RemoteDeviceModel * availableRemoteDevices READ getAvailableRemoteDevices CONSTANT)
40 Q_PROPERTY(RemoteDeviceModel * knownDevices READ getKnownDevices CONSTANT)
42 Q_PROPERTY(RemoteDeviceModel * allDevices READ getAllDevices CONSTANT)
43 Q_PROPERTY(RemoteDeviceFilterModel * availableDevicesInPairingMode READ getAvailableDevicesInPairingMode CONSTANT)
44 Q_PROPERTY(RemoteDeviceFilterModel * availablePairedDevices READ getAvailablePairedDevices CONSTANT)
45 Q_PROPERTY(RemoteDeviceFilterModel * unavailablePairedDevices READ getUnavailablePairedDevices CONSTANT)
4146 Q_PROPERTY(bool detectRemoteDevices READ detectRemoteDevices WRITE setDetectRemoteDevices NOTIFY fireDetectionChanged)
4247 Q_PROPERTY(bool enableTransportPinLink READ enableTransportPinLink NOTIFY fireEstablishPaceChannelUpdated)
4348 Q_PROPERTY(bool remoteReaderVisible READ getRemoteReaderVisible NOTIFY fireRemoteReaderVisibleChanged)
4449 Q_PROPERTY(bool requiresLocalNetworkPermission MEMBER mRequiresLocalNetworkPermission CONSTANT)
50 Q_PROPERTY(QString transactionInfo READ getTransactionInfo NOTIFY fireTransactionInfoChanged)
51 Q_PROPERTY(QString connectedClientName READ getConnectedClientName NOTIFY fireConnectionInfoChanged)
4552
4653 private:
4754 QSharedPointer<IfdServiceContext> mContext;
5158 bool mPairingRequested;
5259 QString mErrorMessage;
5360 QByteArray mPsk;
54 RemoteDeviceModel mAvailableRemoteDevices;
55 RemoteDeviceModel mKnownDevices;
61 RemoteDeviceModel mAllDevices;
62 RemoteDeviceFilterModel mAvailableDevicesInPairingMode;
63 RemoteDeviceFilterModel mAvailablePairedDevices;
64 RemoteDeviceFilterModel mUnavailablePairedDevices;
5665 QString mConnectionInfo;
5766 QString mConnectedServerDeviceNames;
5867 QSharedPointer<IfdListEntry> mRememberedServerEntry;
7786 void onConnectedDevicesChanged();
7887 void onEnvironmentChanged();
7988 void onApplicationStateChanged(const bool pIsAppInForeground);
89 void onPairingCompleted(const QSslCertificate& pCertificate);
8090
8191 public Q_SLOTS:
8292 void onTranslationChanged();
93 void onReaderPlugInTypesChanged(bool pExplicitStart);
8394
8495 public:
8596 [[nodiscard]] bool isRunning() const;
8697 Q_INVOKABLE void setRunning(bool pState, bool pEnablePairing = false);
8798 [[nodiscard]] bool isStarting() const;
8899
89 [[nodiscard]] RemoteDeviceModel* getAvailableRemoteDevices();
90 [[nodiscard]] RemoteDeviceModel* getKnownDevices();
100
101 [[nodiscard]] RemoteDeviceModel* getAllDevices();
102 [[nodiscard]] RemoteDeviceFilterModel* getAvailableDevicesInPairingMode();
103 [[nodiscard]] RemoteDeviceFilterModel* getAvailablePairedDevices();
104 [[nodiscard]] RemoteDeviceFilterModel* getUnavailablePairedDevices();
91105 void setDetectRemoteDevices(bool pNewStatus);
92106 [[nodiscard]] bool detectRemoteDevices() const;
93107 Q_INVOKABLE bool rememberServer(const QString& pDeviceId);
94108 Q_INVOKABLE void connectToRememberedServer(const QString& pServerPsk);
109 [[nodiscard]] QVector<ReaderManagerPlugInType> getSupportedReaderPlugInTypes() const override;
95110
96111 void resetRemoteServiceContext(const QSharedPointer<IfdServiceContext>& pContext = QSharedPointer<IfdServiceContext>());
97112 void setPairing(bool pEnabled);
102117 [[nodiscard]] bool isCanEnableNfc() const;
103118 [[nodiscard]] QString getErrorMessage() const;
104119 [[nodiscard]] QByteArray getPsk() const;
120 [[nodiscard]] QString getDisplayText() const;
121 [[nodiscard]] int getPercentage() const;
105122 [[nodiscard]] QString getConnectionInfo() const;
106123 [[nodiscard]] QString getConnectedServerDeviceNames() const;
107124 [[nodiscard]] bool getRemoteReaderVisible() const;
125 [[nodiscard]] QString getTransactionInfo() const;
126 [[nodiscard]] QString getConnectedClientName() const;
108127
109128 [[nodiscard]] Q_INVOKABLE bool pinPadModeOn() const;
110129 Q_INVOKABLE void forgetDevice(const QString& pId);
117136 void fireIsRunningChanged();
118137 void fireEnvironmentChanged();
119138 void firePskChanged(const QByteArray& pPsk);
139 void fireDisplayTextChanged();
120140 void fireConnectedChanged();
121141 void fireServerPskChanged();
122142 void fireDetectionChanged();
123143 void firePairingFailed(const QString& pDeviceName, const QString& pErrorMessage);
124 void firePairingSuccess(const QString& pDeviceName);
144 void firePairingSuccess();
125145 void firePairingCompleted();
126146 void fireConnectionInfoChanged();
127147 void fireConnectedServerDeviceNamesChanged();
128148 void fireRemoteReaderVisibleChanged();
129149 void fireEstablishPaceChannelUpdated();
130150 void fireCertificateRemoved(const QString& pDeviceName);
151 void fireTransactionInfoChanged();
131152 };
132153
133154
164164
165165 void SettingsModel::setPinPadMode(bool pPinPadMode)
166166 {
167 auto& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
168 settings.setPinPadMode(pPinPadMode);
167 if (getPinPadMode() != pPinPadMode)
168 {
169 auto& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
170 settings.setPinPadMode(pPinPadMode);
171 Q_EMIT firePinPadModeChanged();
172 }
173 }
174
175
176 bool SettingsModel::getShowAccessRights() const
177 {
178 return Env::getSingleton<AppSettings>()->getRemoteServiceSettings().getShowAccessRights();
179 }
180
181
182 void SettingsModel::setShowAccessRights(bool pShowAccessRights)
183 {
184 if (getShowAccessRights() != pShowAccessRights)
185 {
186 auto& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
187 settings.setShowAccessRights(pShowAccessRights);
188 Q_EMIT fireShowAccessRightsChanged();
189 }
169190 }
170191
171192
3030 Q_PROPERTY(bool showBetaTesting MEMBER mShowBetaTesting NOTIFY fireDeveloperOptionsChanged)
3131 Q_PROPERTY(bool useSelfauthenticationTestUri READ useSelfauthenticationTestUri WRITE setUseSelfauthenticationTestUri NOTIFY fireDeveloperOptionsChanged)
3232 Q_PROPERTY(bool pinPadMode READ getPinPadMode WRITE setPinPadMode NOTIFY firePinPadModeChanged)
33 Q_PROPERTY(bool showAccessRights READ getShowAccessRights WRITE setShowAccessRights NOTIFY fireShowAccessRightsChanged)
3334 Q_PROPERTY(QString serverName READ getServerName WRITE setServerName NOTIFY fireDeviceNameChanged)
3435 Q_PROPERTY(bool historyEnabled READ isHistoryEnabled WRITE setHistoryEnabled NOTIFY fireHistoryEnabledChanged)
3536 Q_PROPERTY(bool useScreenKeyboard READ isUseScreenKeyboard WRITE setUseScreenKeyboard NOTIFY fireScreenKeyboardChanged)
8788
8889 [[nodiscard]] bool getPinPadMode() const;
8990 void setPinPadMode(bool pPinPadMode);
91
92 [[nodiscard]] bool getShowAccessRights() const;
93 void setShowAccessRights(bool pShowAccessRights);
9094
9195 [[nodiscard]] bool isHistoryEnabled() const;
9296 void setHistoryEnabled(bool pEnabled);
155159 void fireDeveloperOptionsChanged();
156160 void fireDeviceNameChanged();
157161 void firePinPadModeChanged();
162 void fireShowAccessRightsChanged();
158163 void fireHistoryEnabledChanged();
159164 void fireScreenKeyboardChanged();
160165 void fireCanAllowedChanged();
406406 if (auto remoteServiceContext = pContext.objectCast<IfdServiceContext>())
407407 {
408408 Env::getSingleton<RemoteServiceModel>()->resetRemoteServiceContext(remoteServiceContext);
409 Env::getSingleton<ChatModel>()->resetContext(remoteServiceContext);
410 Env::getSingleton<CertificateDescriptionModel>()->resetContext(remoteServiceContext);
409411 }
410412 }
411413
455457 if (pContext.objectCast<IfdServiceContext>())
456458 {
457459 Env::getSingleton<RemoteServiceModel>()->resetRemoteServiceContext();
460 Env::getSingleton<ChatModel>()->resetContext();
461 Env::getSingleton<CertificateDescriptionModel>()->resetContext();
458462 }
459463
460464 #if __has_include("context/PersonalizationContext.h")
5555 connect(mContext.data(), &WorkflowContext::fireResultChanged, this, &WorkflowModel::fireResultChanged);
5656 connect(mContext.data(), &WorkflowContext::fireReaderPlugInTypesChanged, this, &WorkflowModel::fireReaderPlugInTypeChanged);
5757 connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireSelectedReaderChanged);
58 connect(mContext.data(), &WorkflowContext::fireCardConnectionChanged, this, &WorkflowModel::fireHasCardChanged);
5859 connect(mContext.data(), &WorkflowContext::fireIsSmartCardAllowedChanged, this, &WorkflowModel::fireIsSmartCardAllowedChanged);
5960 connect(mContext.data(), &WorkflowContext::fireNextWorkflowPending, this, &WorkflowModel::fireNextWorkflowPendingChanged);
6061 connect(mContext.data(), &WorkflowContext::fireRemoveCardFeedbackChanged, this, &WorkflowModel::fireRemoveCardFeedbackChanged);
158159 }
159160
160161
161 void WorkflowModel::startScanIfNecessary()
162 void WorkflowModel::startScanExplicitly()
162163 {
163164 if (mContext)
164165 {
165 Q_EMIT mContext->fireReaderPlugInTypesChanged();
166 Q_EMIT mContext->fireReaderPlugInTypesChanged(true);
166167 }
167168 }
168169
186187 }
187188
188189 return false;
190 }
191
192
193 bool WorkflowModel::hasCard() const
194 {
195 if (!mContext)
196 {
197 return false;
198 }
199
200 const auto& readerInfos = Env::getSingleton<ReaderManager>()->getReaderInfos(ReaderFilter({getReaderPlugInType()}));
201 const auto& readersWithEid = filter<ReaderInfo>([](const ReaderInfo& i){return i.hasEid();}, readerInfos);
202 return !readersWithEid.isEmpty();
189203 }
190204
191205
464478 mReaderImage = newReaderImage;
465479 Q_EMIT fireReaderImageChanged();
466480 }
467 }
481
482 Q_EMIT fireHasCardChanged();
483 }
3838 Q_PROPERTY(QString statusHintText READ getStatusHintText NOTIFY fireResultChanged)
3939 Q_PROPERTY(QString statusHintActionText READ getStatusHintActionText NOTIFY fireResultChanged)
4040 Q_PROPERTY(bool showRemoveCardFeedback READ showRemoveCardFeedback WRITE setRemoveCardFeedback NOTIFY fireRemoveCardFeedbackChanged)
41 Q_PROPERTY(bool hasCard READ hasCard NOTIFY fireHasCardChanged)
4142 friend class ::test_WorkflowModel;
4243
4344 private:
6465
6566 [[nodiscard]] bool isBasicReader() const;
6667 [[nodiscard]] bool isRemoteReader() const;
68 [[nodiscard]] bool hasCard() const;
6769
6870 [[nodiscard]] bool isSmartCardAllowed() const;
6971
8587 Q_INVOKABLE void insertSmartCard();
8688 Q_INVOKABLE void insertSimulator();
8789 Q_INVOKABLE void cancelWorkflow();
88 Q_INVOKABLE void startScanIfNecessary();
90 Q_INVOKABLE void startScanExplicitly();
8991 Q_INVOKABLE void continueWorkflow();
9092 Q_INVOKABLE void setInitialPluginType();
9193 [[nodiscard]] Q_INVOKABLE bool shouldSkipResultView() const;
103105 Q_SIGNALS:
104106 void fireCurrentStateChanged(const QString& pState);
105107 void fireResultChanged();
106 void fireReaderPlugInTypeChanged();
108 void fireReaderPlugInTypeChanged(bool pExplicitStart = false);
107109 void fireSelectedReaderChanged();
108110 void fireIsSmartCardAllowedChanged();
109111 void fireReaderImageChanged();
110112 void fireNextWorkflowPendingChanged();
111113 void fireSupportedPlugInTypesChanged();
112114 void fireRemoveCardFeedbackChanged();
115 void fireHasCardChanged();
113116 };
114117
115118
6767 }
6868
6969 mEffectiveAccessRights = mRequiredAccessRights + mOptionalAccessRights;
70 }
71
72
73 AccessRightManager::AccessRightManager(QSharedPointer<CHAT> pRequiredChat)
74 : QObject()
75 , mTerminalCvc()
76 , mDIDAuthenticateEAC1()
77 , mOptionalAccessRights()
78 , mEffectiveAccessRights(pRequiredChat->getAccessRights())
79 , mRequiredAccessRights(pRequiredChat->getAccessRights())
80 {
81
7082 }
7183
7284
2828
2929 public:
3030 explicit AccessRightManager(QSharedPointer<DIDAuthenticateEAC1> pDIDAuthenticateEAC1, QSharedPointer<const CVCertificate> pTerminalCvc);
31 explicit AccessRightManager(QSharedPointer<CHAT> pRequiredChat);
3132
3233
3334 [[nodiscard]] const QSharedPointer<const CVCertificate>& getTerminalCvc() const
4646 , mProgressMessage()
4747 , mShowRemoveCardFeedback(false)
4848 , mClaimedBy()
49 , mInterruptRequested(false)
4950 {
5051 connect(this, &WorkflowContext::fireCancelWorkflow, this, &WorkflowContext::onWorkflowCancelled);
5152 }
595596 || acceptedEidTypes.contains(AcceptedEidType::SE_ENDORSED)
596597 || acceptedEidTypes.contains(AcceptedEidType::HW_KEYSTORE));
597598 }
599
600
601 bool WorkflowContext::interruptRequested() const
602 {
603 return mInterruptRequested;
604 }
605
606
607 void WorkflowContext::setInterruptRequested(bool pInterruptRequested)
608 {
609 mInterruptRequested = pInterruptRequested;
610 }
6565 QString mProgressMessage;
6666 bool mShowRemoveCardFeedback;
6767 QString mClaimedBy;
68 bool mInterruptRequested;
6869
6970 private Q_SLOTS:
7071 void onWorkflowCancelled();
7273 Q_SIGNALS:
7374 void fireStateApprovedChanged(bool pApproved);
7475 void fireStateChanged(const QString& pNewState);
75 void fireReaderPlugInTypesChanged();
76 void fireReaderPlugInTypesChanged(bool pExplicitStart = false);
7677 void fireReaderInfoChanged();
7778 void fireReaderNameChanged();
7879 void fireCardConnectionChanged();
219220 [[nodiscard]] virtual QVector<AcceptedEidType> getAcceptedEidTypes() const = 0;
220221
221222 bool isPhysicalCardRequired() const;
223
224 [[nodiscard]] bool interruptRequested() const;
225 void setInterruptRequested(bool pInterruptRequested);
222226 };
223227
224228 } // namespace governikus
194194 }
195195
196196
197 void AbstractState::startNfcScanIfNecessary()
198 {
199 #if defined(Q_OS_IOS)
200 if (isStartStopEnabled())
201 {
202 Env::getSingleton<ReaderManager>()->startScan(ReaderManagerPlugInType::NFC);
203 }
204 #endif
205 }
206
207
208197 void AbstractState::stopNfcScanIfNecessary(const QString& pError)
209198 {
210199 #if defined(Q_OS_IOS)
4646 void updateStatus(const GlobalStatus& pStatus);
4747 void updateStartPaosResult(const ECardApiResult& pStartPaosResult);
4848
49 void startNfcScanIfNecessary();
5049 void stopNfcScanIfNecessary(const QString& pError = QString());
5150
5251 public:
172172 if (TlsChecker::containsFatalError(mReply, pErrors))
173173 {
174174 reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString()}
175 }, FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_Before_Reply);
175 }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_Before_Reply);
176176 }
177177 }
178178
272272
273273 case NetworkManager::NetworkError::SecurityError:
274274 reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, {GlobalStatus::ExternalInformation::LAST_URL, mUrl.toString()}
275 }, FailureCode::Reason::Check_Refresh_Address_Fatal_Ssl_Error_After_Reply, mReply->errorString());
275 }, FailureCode::Reason::Check_Refresh_Address_Fatal_Tls_Error_After_Reply, mReply->errorString());
276276 break;
277277
278278 case NetworkManager::NetworkError::OtherError:
2020 void StateCleanUpReaderManager::run()
2121 {
2222 const QSharedPointer<WorkflowContext> context = getContext();
23
24 const auto& reader = context->getReaderName();
25 if (!reader.isEmpty() && !context->getStatus().isError())
23 if (const auto& reader = context->getReaderName(); !reader.isEmpty())
2624 {
2725 const auto& readerInfo = Env::getSingleton<ReaderManager>()->getReaderInfo(reader);
2826 if (readerInfo.hasCard() && readerInfo.getCardInfo().getCardType() != CardType::SMART_EID)
6161 newStatus = GlobalStatus::Code::Workflow_Card_Removed;
6262 break;
6363
64 case CardReturnCode::EXTENDED_LENGTH_MISSING:
65 newStatus = GlobalStatus::Code::Workflow_No_Extended_Length_Error;
64 case CardReturnCode::WRONG_LENGTH:
65 newStatus = GlobalStatus::Code::Workflow_Wrong_Length_Error;
6666 break;
6767
6868 default:
33
44 #include "StateEnterPacePassword.h"
55
6 #include "ReaderManager.h"
67 #include "VolatileSettings.h"
78
89
1314 : AbstractState(pContext)
1415 , GenericContextContainer(pContext)
1516 {
17 const auto& readerManager = Env::getSingleton<ReaderManager>();
18 mConnections += connect(readerManager, &ReaderManager::fireStatusChanged, this, &StateEnterPacePassword::onReaderStatusChanged);
19
1620 setKeepCardConnectionAlive();
1721 }
1822
4852
4953 AbstractState::onEntry(pEvent);
5054 }
55
56
57 void StateEnterPacePassword::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const
58 {
59 #if defined(Q_OS_IOS)
60 const auto& volatileSettings = Env::getSingleton<VolatileSettings>();
61 if (!volatileSettings->isUsedAsSDK() || pInfo.getPlugInType() != ReaderManagerPlugInType::NFC)
62 {
63 return;
64 }
65
66 if (!Env::getSingleton<ReaderManager>()->isScanRunning(ReaderManagerPlugInType::NFC))
67 {
68 if (getContext()->interruptRequested())
69 {
70 getContext()->setInterruptRequested(false);
71 }
72 else
73 {
74 Q_EMIT getContext()->fireCancelWorkflow();
75 }
76 }
77 #else
78 Q_UNUSED(pInfo)
79 #endif
80 }
2424 explicit StateEnterPacePassword(const QSharedPointer<WorkflowContext>& pContext);
2525 void run() override;
2626
27 private Q_SLOTS:
28 void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo) const;
29
2730 public:
2831 void onEntry(QEvent* pEvent) override;
2932
2121
2222 void StateEstablishPaceChannel::run()
2323 {
24 if (getContext()->getStatus().isError())
25 {
26 Q_ASSERT(getContext()->getFailureCode().has_value());
24 const auto& context = getContext();
25 Q_ASSERT(context);
26
27 if (context->getStatus().isError())
28 {
29 Q_ASSERT(context->getFailureCode().has_value());
2730 Q_EMIT firePaceChannelFailed();
2831 return;
2932 }
3033
3134 QByteArray effectiveChat;
3235 QByteArray certificateDescription;
33 auto authContext = getContext().objectCast<AuthContext>();
34 mPasswordId = getContext()->getEstablishPaceChannelType();
36 const auto& authContext = context.objectCast<AuthContext>();
37 mPasswordId = context->getEstablishPaceChannelType();
3538 Q_ASSERT(mPasswordId != PacePasswordId::UNKNOWN);
3639
3740 if (mPasswordId == PacePasswordId::PACE_PIN ||
38 (mPasswordId == PacePasswordId::PACE_CAN && getContext()->isCanAllowedMode()))
41 (mPasswordId == PacePasswordId::PACE_CAN && context->isCanAllowedMode()))
3942 {
4043 if (authContext && authContext->getDidAuthenticateEac1())
4144 {
5457 switch (mPasswordId)
5558 {
5659 case PacePasswordId::PACE_CAN:
57 password = getContext()->getCan().toLatin1();
60 password = context->getCan().toLatin1();
5861 break;
5962
6063 case PacePasswordId::PACE_PIN:
61 password = getContext()->getPin().toLatin1();
64 password = context->getPin().toLatin1();
6265 break;
6366
6467 case PacePasswordId::PACE_PUK:
65 password = getContext()->getPuk().toLatin1();
68 password = context->getPuk().toLatin1();
6669 break;
6770
6871 case PacePasswordId::UNKNOWN:
7174 break;
7275 }
7376
74 auto cardConnection = getContext()->getCardConnection();
77 auto cardConnection = context->getCardConnection();
7578 if (!cardConnection)
7679 {
7780 qCDebug(statemachine) << "No card connection available.";
78 getContext()->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND);
81 context->setLastPaceResult(CardReturnCode::CARD_NOT_FOUND);
7982 Q_EMIT fireNoCardConnection();
8083 return;
8184 }
9093 return;
9194 }
9295
96 //: INFO ALL_PLATFORMS First status message after the PIN was entered.
97 context->setProgress(0, tr("The secure channel is opened"));
98
9399 qDebug() << "Establish connection using" << mPasswordId;
94100 Q_ASSERT(!password.isEmpty() || !cardConnection->getReaderInfo().isBasicReader());
95101
96102 if (mPasswordId == PacePasswordId::PACE_PIN && !cardConnection->getReaderInfo().isBasicReader())
97103 {
98 const auto pinContext = getContext().objectCast<ChangePinContext>();
104 const auto pinContext = context.objectCast<ChangePinContext>();
99105 if (pinContext && pinContext->isRequestTransportPin())
100106 {
101107 password = QByteArray(5, 0);
123123 }
124124
125125 const GlobalStatus& status = {GlobalStatus::Code::Network_Ssl_Establishment_Error, infoMap};
126 const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Ssl_Error,
126 const FailureCode& failure {FailureCode::Reason::Generic_Provider_Communication_Tls_Error,
127127 {
128128 {FailureCode::Info::Network_Error, mReply->errorString()},
129129 {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)},
101101 {FailureCode::Info::State_Name, getStateName()},
102102 {FailureCode::Info::Ssl_Errors, TlsChecker::sslErrorsToString(pErrors)}
103103 };
104 Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Ssl_Error, infoMap});
104 Q_EMIT fireAbort({FailureCode::Reason::Generic_Send_Receive_Tls_Error, infoMap});
105105 }
106106 }
107107
4141 case CardReturnCode::UNDEFINED:
4242 case CardReturnCode::COMMAND_FAILED:
4343 case CardReturnCode::PROTOCOL_ERROR:
44 case CardReturnCode::EXTENDED_LENGTH_MISSING:
44 case CardReturnCode::WRONG_LENGTH:
4545 case CardReturnCode::UNEXPECTED_TRANSMIT_STATUS:
4646 {
4747 Q_ASSERT(!CardReturnCodeUtil::equalsWrongPacePassword(lastPaceResult));
5252 {
5353 qCritical() << "Using the developer mode is only allowed in a test environment";
5454 updateStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error);
55 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_No_Test_Environment);
55 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_No_Test_Environment);
5656 return;
5757 }
5858
6767 {
6868 qCritical() << "Pre-verification failed: cannot build certificate chain";
6969 updateStatus(GlobalStatus::Code::Workflow_Preverification_Error);
70 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain);
70 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain);
7171 return;
7272 }
7373 else if (!SignatureChecker(certificateChain).check())
7474 {
7575 qCritical() << "Pre-verification failed: signature check failed";
7676 updateStatus(GlobalStatus::Code::Workflow_Preverification_Error);
77 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature);
77 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature);
7878 return;
7979 }
8080 else if (!isValid(certificateChain))
8787 {
8888 qCritical() << "Pre-verification failed: certificate not valid";
8989 updateStatus(GlobalStatus::Code::Workflow_Preverification_Error);
90 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verfication_Certificate_Expired);
90 Q_EMIT fireAbort(FailureCode::Reason::Pre_Verification_Certificate_Expired);
9191 return;
9292 }
9393 }
2727 , mIfdServer(pIfdServer)
2828 , mNewPin()
2929 , mSlotHandle()
30 , mDisplayText()
3031 , mEstablishPaceChannel()
3132 , mRequestTransportPin(false)
3233 , mAllowToChangePinLength(false)
3334 , mEstablishPaceChannelOutput()
35 , mAccessRightManager()
3436 , mModifyPinMessage()
3537 , mModifyPinMessageResponseApdu()
3638 {
115117 mEstablishPaceChannel = pMessage->getInputData();
116118 mRequestTransportPin = pMessage->getExpectedPinLength() == 5;
117119 mAllowToChangePinLength = isPinChangeWorkflow() && pMessage->getExpectedPinLength() == 0;
120 const auto& chat = mEstablishPaceChannel.getChat();
121 if (!chat.isEmpty())
122 {
123 const auto& requiredChat = CHAT::decode(chat);
124 mAccessRightManager = QSharedPointer<AccessRightManager>::create(requiredChat);
125 Q_EMIT fireAccessRightManagerCreated(mAccessRightManager);
126 }
118127 }
119128 else
120129 {
121130 mSlotHandle.clear();
131 mAccessRightManager.clear();
122132 mEstablishPaceChannel = EstablishPaceChannel();
123133 mRequestTransportPin = false;
124134 mAllowToChangePinLength = false;
138148 }
139149
140150
151 void IfdServiceContext::setDisplayText(const QString& pDisplayText)
152 {
153 if (mDisplayText != pDisplayText)
154 {
155 mDisplayText = pDisplayText;
156 Q_EMIT fireDisplayTextChanged();
157 }
158 }
159
160
161 const QString& IfdServiceContext::getDisplayText() const
162 {
163 return mDisplayText;
164 }
165
166
141167 const EstablishPaceChannel& IfdServiceContext::getEstablishPaceChannel() const
142168 {
143169 return mEstablishPaceChannel;
170 }
171
172
173 QSharedPointer<AccessRightManager> IfdServiceContext::getAccessRightManager() const
174 {
175 return mAccessRightManager;
176 }
177
178
179 QSharedPointer<const CertificateDescription> IfdServiceContext::getCertificateDescription() const
180 {
181 const auto& certDescription = mEstablishPaceChannel.getCertificateDescription();
182 if (certDescription.isEmpty())
183 {
184 return QSharedPointer<const CertificateDescription>();
185 }
186
187 return CertificateDescription::decode(certDescription);
144188 }
145189
146190
231275
232276 [[nodiscard]] QVector<AcceptedEidType> IfdServiceContext::getAcceptedEidTypes() const
233277 {
234 if (mIfdServer->isLocal())
235 {
236 return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE};
237 }
238 return {AcceptedEidType::CARD_CERTIFIED};
239 }
278 return {AcceptedEidType::CARD_CERTIFIED, AcceptedEidType::SE_CERTIFIED, AcceptedEidType::SE_ENDORSED, AcceptedEidType::HW_KEYSTORE};
279 }
88 #pragma once
99
1010 #include "IfdServer.h"
11 #include "asn1/CertificateDescription.h"
12 #include "context/AccessRightManager.h"
1113 #include "context/WorkflowContext.h"
1214 #include "messages/IfdEstablishPaceChannel.h"
1315 #include "messages/IfdModifyPin.h"
3133 QString mNewPin;
3234
3335 QString mSlotHandle;
36 QString mDisplayText;
3437 EstablishPaceChannel mEstablishPaceChannel;
3538 bool mRequestTransportPin;
3639 bool mAllowToChangePinLength;
3740 EstablishPaceChannelOutput mEstablishPaceChannelOutput;
41 QSharedPointer<AccessRightManager> mAccessRightManager;
3842
3943 QSharedPointer<const IfdModifyPin> mModifyPinMessage;
4044 ResponseApdu mModifyPinMessageResponseApdu;
4650
4751 Q_SIGNALS:
4852 void fireCardConnected(const QSharedPointer<CardConnection>& pConnection);
53 void fireDisplayTextChanged();
4954 void fireCardDisconnected(const QSharedPointer<CardConnection>& pConnection);
5055 void fireCancelPasswordRequest();
5156 void fireEstablishPaceChannelUpdated();
5257 void fireIsRunningChanged();
58 void fireAccessRightManagerCreated(QSharedPointer<AccessRightManager> pAccessRightManager);
5359
5460 public:
5561 explicit IfdServiceContext(const QSharedPointer<IfdServer>& pIfdServer);
6975
7076 void setEstablishPaceChannel(const QSharedPointer<const IfdEstablishPaceChannel>& pMessage);
7177 [[nodiscard]] const QString& getSlotHandle() const;
78 void setDisplayText(const QString& pDisplayText);
79 [[nodiscard]] const QString& getDisplayText() const;
7280 [[nodiscard]] const EstablishPaceChannel& getEstablishPaceChannel() const;
81 [[nodiscard]] QSharedPointer<AccessRightManager> getAccessRightManager() const;
82 [[nodiscard]] QSharedPointer<const CertificateDescription> getCertificateDescription() const;
7383
7484 void changePinLength();
7585 [[nodiscard]] bool allowToChangePinLength() const;
2828 const QSharedPointer<IfdServer> server = context->getIfdServer();
2929 Q_ASSERT(server);
3030
31 mConnections += connect(Env::getSingleton<ReaderManager>(), &ReaderManager::fireStatusChanged, this, &StateProcessIfdMessages::onReaderStatusChanged);
32 mConnections += connect(Env::getSingleton<ReaderManager>(), &ReaderManager::fireReaderPropertiesUpdated, this, &StateProcessIfdMessages::onReaderPropertiesUpdated);
3331 mConnections += connect(server.data(), &IfdServer::fireMessageHandlerAdded, this, &StateProcessIfdMessages::onMessageHandlerAdded);
34 mConnections += connect(server.data(), &IfdServer::fireConnectedChanged, this, &StateProcessIfdMessages::onConnectedChanged);
3532
3633 const auto messageHandler = server->getMessageHandler();
3734 if (messageHandler)
5350 }
5451
5552 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireCardConnected, this, &StateProcessIfdMessages::onCardConnected, Qt::UniqueConnection);
53 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireDisplayTextChanged, this, &StateProcessIfdMessages::onDisplayTextChanged, Qt::UniqueConnection);
5654 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireEstablishPaceChannel, this, &StateProcessIfdMessages::onEstablishPaceChannel, Qt::UniqueConnection);
5755 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireModifyPin, this, &StateProcessIfdMessages::onModifyPin, Qt::UniqueConnection);
5856 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireCardDisconnected, this, &StateProcessIfdMessages::onCardDisconnected, Qt::UniqueConnection);
5957 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::destroyed, this, &StateProcessIfdMessages::onClosed, Qt::UniqueConnection);
6058 mMessageConnections += connect(pHandler.data(), &ServerMessageHandler::fireSecureMessagingStopped, this, &StateProcessIfdMessages::fireSecureMessagingStopped, Qt::UniqueConnection);
61 }
62
63
64 void StateProcessIfdMessages::onConnectedChanged(bool pConnected)
65 {
66 if (pConnected && !getContext()->getIfdServer()->isPairingConnection())
67 {
68 startNfcScanIfNecessary();
69 Env::getSingleton<ReaderManager>()->startScan(ReaderManagerPlugInType::SMART);
70 }
71 else
72 {
73 stopNfcScanIfNecessary();
74 Env::getSingleton<ReaderManager>()->stopScan(ReaderManagerPlugInType::SMART);
75 }
7659 }
7760
7861
8972 }
9073
9174
92 void StateProcessIfdMessages::onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo)
75 void StateProcessIfdMessages::onCardConnected()
9376 {
94 if (pInfo.getPlugInType() != ReaderManagerPlugInType::NFC)
95 {
96 return;
97 }
98
99 if (Env::getSingleton<ReaderManager>()->isScanRunning(ReaderManagerPlugInType::NFC))
100 {
101 return;
102 }
103
104 const auto& context = getContext();
105 if (context->getIfdServer()->isConnected())
106 {
107 qCDebug(statemachine) << "Stopping IfdService because NFC was disabled.";
108 Q_EMIT fireContinue();
109 }
77 mResetContextOnDisconnect = false;
11078 }
11179
11280
113 void StateProcessIfdMessages::onReaderPropertiesUpdated(const ReaderInfo& pInfo)
81 void StateProcessIfdMessages::onDisplayTextChanged(const QString& pDisplayText) const
11482 {
115 if (Env::getSingleton<VolatileSettings>()->isUsedAsSDK())
116 {
117 if (pInfo.isInsertable() && pInfo.getCardInfo().getCardType() == CardType::NONE)
118 {
119 Env::getSingleton<ReaderManager>()->insert(pInfo);
120 }
121 }
122 }
123
124
125 void StateProcessIfdMessages::onCardConnected()
126 {
127 mResetContextOnDisconnect = false;
83 getContext()->setDisplayText(pDisplayText);
12884 }
12985
13086
157113
158114 void StateProcessIfdMessages::onCardDisconnected()
159115 {
116 getContext()->setDisplayText(QString());
160117 if (mResetContextOnDisconnect)
161118 {
162119 getContext()->reset();
163120 }
164 }
165
166
167 void StateProcessIfdMessages::onEntry(QEvent* pEvent)
168 {
169 onConnectedChanged(getContext()->getIfdServer()->isConnected());
170
171 AbstractState::onEntry(pEvent);
172121 }
173122
174123
99 #pragma once
1010
1111
12 #include "ReaderManager.h"
1312 #include "context/IfdServiceContext.h"
1413 #include "states/AbstractState.h"
1514 #include "states/GenericContextContainer.h"
3736 private Q_SLOTS:
3837 void onMessageHandlerAdded(const QSharedPointer<ServerMessageHandler>& pHandler);
3938 void onClosed();
40 void onConnectedChanged(bool pConnected);
41 void onReaderStatusChanged(const ReaderManagerPlugInInfo& pInfo);
42 void onReaderPropertiesUpdated(const ReaderInfo& pInfo);
4339 void onCardConnected();
40 void onDisplayTextChanged(const QString& pDisplayText) const;
4441 void onModifyPin(const QSharedPointer<const IfdModifyPin>& pMessage, const QSharedPointer<CardConnection>& pConnection);
4542 void onEstablishPaceChannel(const QSharedPointer<const IfdEstablishPaceChannel>& pMessage, const QSharedPointer<CardConnection>& pConnection);
4643 void onCardDisconnected();
4744
4845 protected:
49 void onEntry(QEvent* pEvent) override;
5046 void onExit(QEvent* pEvent) override;
5147
5248 public:
247247 QString SelfAuthenticationData::SelfData::formatDate(const QString& pDate)
248248 {
249249 static const QVector<QPair<QString, QLatin1String>> formattingPattern({
250 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString
250251 qMakePair(QStringLiteral("yyyy-MM-dd+hh:mm"), QLatin1String(QT_TR_NOOP("dd.MM.yyyy"))),
252 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day
251253 qMakePair(QStringLiteral("yyyy-MM"), QLatin1String(QT_TR_NOOP("xx.MM.yyyy"))),
254 //: LABEL ALL_PLATFORMS Date format according to https://doc.qt.io/qt/qdate.html#toString with unknown day and month
252255 qMakePair(QStringLiteral("yyyy"), QLatin1String(QT_TR_NOOP("xx.xx.yyyy"))),
253256 });
254257
99 using namespace governikus;
1010
1111
12 MockDataChannel::MockDataChannel()
13 : mId(QUuid::createUuid().toString())
12 MockDataChannel::MockDataChannel(bool pPairing)
13 : mPairing(pPairing)
14 , mId(QUuid::createUuid().toString())
1415 , mReceivedDataBlocks()
1516 {
1617 }
2425 void MockDataChannel::close()
2526 {
2627 Q_EMIT fireClosed(GlobalStatus::Code::No_Error);
28 }
29
30
31 bool MockDataChannel::isPairingConnection() const
32 {
33 return mPairing;
2734 }
2835
2936
2121 Q_OBJECT
2222
2323 private:
24 bool mPairing;
2425 QString mId;
2526 QVector<QByteArray> mReceivedDataBlocks;
2627
2728 public:
28 MockDataChannel();
29 explicit MockDataChannel(bool pPairing = false);
2930 ~MockDataChannel() override;
3031
3132 void send(const QByteArray& pDataBlock) override;
3233 void close() override;
34 [[nodiscard]] bool isPairingConnection() const override;
3335 [[nodiscard]] const QString& getId() const override;
3436 void closeAbnormal();
3537
2323 MockIfdDispatcher::MockIfdDispatcher(DispatcherState pState)
2424 : IfdDispatcherClient(IfdVersion::Version::v2, QSharedPointer<MockDataChannel>::create())
2525 , mState(pState)
26 , mPairing(false)
2627 , mId(QUuid::createUuid().toString())
2728 , mContextHandle(QStringLiteral("#TestContext"))
2829 {
30 }
31
32
33 void MockIfdDispatcher::setPairingConnection(bool pPairing)
34 {
35 mPairing = pPairing;
36 }
37
38
39 bool MockIfdDispatcher::isPairingConnection() const
40 {
41 return mPairing;
2942 }
3043
3144
2929
3030 private:
3131 DispatcherState mState;
32 bool mPairing;
3233 QString mId;
3334 QString mContextHandle;
3435
3536 public:
3637 MockIfdDispatcher(DispatcherState pState = DispatcherState::WithoutReader);
3738
39 void setPairingConnection(bool pPairing);
40 [[nodiscard]] bool isPairingConnection() const override;
3841 [[nodiscard]] QString getId() const override;
3942 [[nodiscard]] const QString& getContextHandle() const override;
4043 Q_INVOKABLE void send(const QSharedPointer<const IfdMessage>& pMessage) override;
3131 }
3232 function test_size(data) {
3333 let button = createTemporaryQmlObject("import Governikus.Global 1.0; GButton {icon.source: \"" + data.icon + "\"; text: \"" + data.text + "\"}", testCase);
34 waitForRendering(button);
35 compare(button.height, data.height);
36 compare(button.width, data.width);
34 tryCompare(button, "height", data.height);
35 tryCompare(button, "width", data.width);
3736 }
3837 function test_size_data() {
39 if (Qt.platform.os !== "osx") {
40 skip();
41 }
4238 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);
43 waitForRendering(text);
44 let longTextWidth = Math.round(text.width + 0.1);
39 verify(waitForRendering(text));
40 let longTextWidth = Math.ceil(text.width);
4541 return [{
4642 "tag": "noIconNoText",
4743 "icon": "",
7167 "icon": "qrc:///images/identify.svg",
7268 "text": "t",
7369 "height": Constants.is_desktop ? 39 : 40,
74 "width": Constants.is_desktop ? 59 : 112
70 "width": Constants.is_desktop ? (Qt.platform.os === "linux" ? 64 : 59) : 112
7571 }, {
7672 "tag": "withIconLongText",
7773 "icon": "qrc:///images/identify.svg",
301301 }
302302 }
303303
304 QCOMPARE(attachedEidCounter, 20);
304 QCOMPARE(attachedEidCounter, 21);
305305 }
306306
307307
223223 QTest::addColumn<int>("majorVersion");
224224 QTest::addColumn<int>("count");
225225
226 const int all = 113;
227 const int withEidSupport = 91;
226 const int all = 120;
227 const int withEidSupport = 98;
228228 QTest::newRow("win") << QOperatingSystemVersion::Windows << -1 << all;
229229 QTest::newRow("mac") << QOperatingSystemVersion::MacOS << -1 << all;
230230 QTest::newRow("linux") << QOperatingSystemVersion::Unknown << -1 << all;
446446 QTest::newRow("createSingleton") << QByteArray("T* governikus::Env::createSingleton() [with T = governikus::AppUpdater]")
447447 << QByteArray("Env::createSingleton");
448448
449 QTest::newRow("createSingletonPtr") << QByteArray("T *governikus::Env::createSingleton() [T = governikus::NetworkManager]")
450 << QByteArray("Env::createSingleton");
451
452 QTest::newRow("processUpdaterRequest") << QByteArray("auto governikus::NetworkManager::processUpdaterRequest(QNetworkRequest &, const std::function<QSharedPointer<QNetworkReply> (QNetworkRequest &)> &)::(anonymous class)::operator()() const")
453 << QByteArray("NetworkManager::processUpdaterRequest");
454
449455 QTest::newRow("printInfo") << QByteArray("void printInfo()")
450456 << QByteArray("printInfo");
451457
465471 QTest::newRow("UILoader::load") << QByteArray("std::enable_if_t<std::is_base_of<governikus::UIPlugIn, T>::value, bool> governikus::UILoader::load() const [with T = governikus::UIPlugInJson; std::enable_if_t<std::is_base_of<governikus::UIPlugIn, T>::value, bool> = bool]")
466472 << QByteArray("UILoader::load");
467473
474 QTest::newRow("anonymous") << QByteArray("virtual QList<QNetworkProxy> (anonymous namespace)::SystemProxyFactory::queryProxy(const QNetworkProxyQuery &)")
475 << QByteArray("SystemProxyFactory::queryProxy");
468476 }
469477
470478
480488 }
481489
482490
491 void formatFunctionNullptr()
492 {
493 const auto* handler = Env::getSingleton<LogHandler>();
494 const auto& formattedFunction = handler->formatFunction(nullptr, QByteArray(), 1811);
495
496 QCOMPARE(formattedFunction, QByteArray());
497 }
498
499
483500 };
484501
485502 QTEST_GUILESS_MAIN(test_LogHandler)
110110 Env::set(RemoteIfdClient::staticMetaObject, mIfdClient.data());
111111
112112 mDispatcher1.reset(new MockIfdDispatcher());
113 mDispatcher1->setPairingConnection(false);
113114 mDispatcher1->moveToThread(&mNetworkThread);
114115
115116 mDispatcher2.reset(new MockIfdDispatcher());
117 mDispatcher2->setPairingConnection(true);
116118 mDispatcher2->moveToThread(&mNetworkThread);
117119
118120 mPlugin.reset(new RemoteIfdReaderManagerPlugIn());
524526 }
525527
526528
529 void testKeepNormalConnection()
530 {
531 QSignalSpy spySend(mDispatcher1.data(), &MockIfdDispatcher::fireSend);
532
533 Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher1);
534 QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations
535 spySend.clear();
536
537 mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher1->getId());
538 QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations
539 QSharedPointer<const IfdMessage> result = qvariant_cast<QSharedPointer<const IfdMessage>>(spySend.takeFirst().at(0));
540 QCOMPARE(result->getType(), IfdMessageType::IFDGetStatus);
541 }
542
543
544 void testClosePairingConnection()
545 {
546 QSignalSpy spySend(mDispatcher2.data(), &MockIfdDispatcher::fireSend);
547 QSignalSpy spyClosed(mDispatcher2.data(), &MockIfdDispatcher::fireClosed);
548
549 Q_EMIT mIfdClient->fireNewDispatcher(mDispatcher2);
550 QTRY_COMPARE(spySend.count(), 1); // clazy:exclude=qstring-allocations
551
552 mPlugin->onContextEstablished(QStringLiteral("MAC-MINI"), mDispatcher2->getId());
553 QTRY_COMPARE(spyClosed.count(), 1); // clazy:exclude=qstring-allocations
554 }
555
556
527557 };
528558
529559 QTEST_GUILESS_MAIN(test_RemoteIfdReaderManagerPlugIn)
9797 }
9898
9999
100 [[nodiscard]] bool isPairingAnnounced() const override
101 {
102 return mPairing;
103 }
104
105
100106 void setPairing(bool pEnabled = true) override
101107 {
102108 mPairing = pEnabled;
158164 private Q_SLOTS:
159165 void init()
160166 {
161 std::function<RemoteReaderAdvertiser* (const QString&, const QString&, quint16&)> creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort){
167 std::function<RemoteReaderAdvertiser* (const QString&, const QString&, quint16&, bool&)> creator = [this](const QString& pIfdName, const QString& pIfdId, quint16& pPort, bool&){
162168 mAdvertiserMock = new RemoteReaderAdvertiserMock(pIfdName, pIfdId, pPort);
163169 return mAdvertiserMock;
164170 };
165 Env::setCreator<RemoteReaderAdvertiser*, const QString&, const QString&, quint16&>(creator);
171 Env::setCreator<RemoteReaderAdvertiser*>(creator);
166172 std::function<RemoteWebSocketServer* ()> creator2 = [this](){
167173 mWebSocketMock = new RemoteWebSocketServerMock();
168174 return mWebSocketMock;
1818 {
1919
2020
21 template<> RemoteReaderAdvertiser* createNewObject<RemoteReaderAdvertiser*, const QString&, const QString&, quint16&, int&>(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pTimerInterval, bool& pPairing)
21 template<> RemoteReaderAdvertiser* createNewObject<RemoteReaderAdvertiser*, const QString&, const QString&, quint16&, int&, bool&>(const QString& pIfdName, const QString& pIfdId, quint16& pPort, int& pInterval, bool& pPairing)
2222 {
23 return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pTimerInterval, pPairing);
23 return new RemoteReaderAdvertiserImpl(pIfdName, pIfdId, pPort, pPairing, pInterval);
2424 }
2525
2626
5656 RemoteTlsServer server;
5757 server.setPairing(serverPairing);
5858 server.startListening(0);
59 QCOMPARE(server.hasPsk(), serverPairing);
5960
6061 auto config = Env::getSingleton<SecureStorage>()->getTlsConfigRemoteIfd(clientConfig).getConfiguration();
6162 config.setPrivateKey(pair.getKey());
9091 });
9192 server.setPairing();
9293 server.startListening(0);
94 QVERIFY(server.hasPsk());
9395
9496 auto config = Env::getSingleton<SecureStorage>()->getTlsConfigRemoteIfd(SecureStorage::TlsSuite::PSK).getConfiguration();
9597 config.setPrivateKey(pair.getKey());
175175 PskHandler pskHandler(&client, mServer.data());
176176 mServer->setPairing();
177177 QVERIFY(mServer->listen(QStringLiteral("TestServer")));
178 QVERIFY(mServer->isPairingAnnounced());
178179
179180 client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort())));
180181
278279 PskHandler pskHandler(&client, mServer.data());
279280 mServer->setPairing();
280281 client.open(QString("wss://127.0.0.1:").append(QString::number(mServer->getServerPort())));
282 QVERIFY(mServer->isPairingAnnounced());
281283
282284 QTRY_COMPARE(newConnectionSpy.count(), 1); // clazy:exclude=qstring-allocations
283285 QTRY_COMPARE(serverConnectedSpy.count(), 1); // clazy:exclude=qstring-allocations
426426 QTRY_COMPARE(spyConnectorError.count(), 1); // clazy:exclude=qstring-allocations
427427 QCOMPARE(spyConnectorSuccess.count(), 0);
428428
429 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
430 verifyErrorSignal(spyConnectorError, {IfdErrorCode::CONNECTION_ERROR}, serverPort, QStringLiteral("Smartphone1"));
431 #else
432429 verifyErrorSignal(spyConnectorError, {IfdErrorCode::REMOTE_HOST_REFUSED_CONNECTION}, serverPort, QStringLiteral("Smartphone1"));
433 #endif
434430
435431 QCOMPARE(spySocketError.count(), 0);
436432 QCOMPARE(spySocketSuccess.count(), 0);
337337 }
338338
339339
340 void isNormalConnection()
341 {
342 const QSharedPointer<MockDataChannel> clientChannel(new MockDataChannel(false));
343 const QSharedPointer<IfdDispatcherClient> clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel));
344 QVERIFY(!clientDispatcher->isPairingConnection());
345 }
346
347
348 void isPairingConnection()
349 {
350 const QSharedPointer<MockDataChannel> clientChannel(new MockDataChannel(true));
351 const QSharedPointer<IfdDispatcherClient> clientDispatcher(new IfdDispatcherClient(IfdVersion::Version::v2, clientChannel));
352 QVERIFY(clientDispatcher->isPairingConnection());
353 }
354
355
340356 };
341357
342358 QTEST_GUILESS_MAIN(test_IfdDispatcher)
602602 }
603603
604604
605 void ifdTransmit_data()
606 {
607 QTest::addColumn<bool>("sendProgressMessage");
608
609 QTest::newRow("Send message") << true;
610 QTest::newRow("Don't send message") << false;
611 }
612
613
614 void ifdTransmit()
615 {
616 QFETCH(bool, sendProgressMessage);
617
618 QSignalSpy logSpy(Env::getSingleton<LogHandler>()->getEventHandler(), &LogEventHandler::fireLog);
619 ServerMessageHandlerImpl serverMessageHandler(mDataChannel);
620 QString contextHandle;
621 ensureContext(contextHandle);
622
623 QSignalSpy sendSpy(mDataChannel.data(), &MockDataChannel::fireSend);
624
625 MockReader* reader = MockReaderManagerPlugIn::getInstance().addReader("test-reader");
626 QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations
627 reader->setCard(MockCardConfig({
628 {CardReturnCode::OK, QByteArray("9000")}
629 }));
630 QTRY_COMPARE(sendSpy.count(), 2); // clazy:exclude=qstring-allocations
631 const CardInfo cardInfo(CardType::EID_CARD, QSharedPointer<const EFCardAccess>(), 3, true);
632 ReaderInfo info = reader->getReaderInfo();
633 info.setCardInfo(cardInfo);
634 reader->setReaderInfo(info);
635 QTRY_COMPARE(sendSpy.count(), 3); // clazy:exclude=qstring-allocations
636 sendSpy.clear();
637
638 const QByteArray ifdConnectMsg = IfdConnect(QStringLiteral("test-reader"), true).toByteArray(IfdVersion::Version::latest, contextHandle);
639 mDataChannel->onReceived(ifdConnectMsg);
640
641 QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations
642
643 const QList<QVariant>& connectResponseArguments = sendSpy.last();
644 const QVariant connectResponseVariant = connectResponseArguments.at(0);
645 QVERIFY(connectResponseVariant.canConvert<QByteArray>());
646
647 const IfdConnectResponse connectResponse(IfdMessage::parseByteArray(connectResponseVariant.toByteArray()));
648 QVERIFY(!connectResponse.isIncomplete());
649 QCOMPARE(connectResponse.getType(), IfdMessageType::IFDConnectResponse);
650 QCOMPARE(connectResponse.getContextHandle(), contextHandle);
651 QVERIFY(!connectResponse.getSlotHandle().isEmpty());
652
653 QVERIFY(!connectResponse.resultHasError());
654 QCOMPARE(connectResponse.getResultMinor(), ECardApiResult::Minor::null);
655
656 sendSpy.clear();
657
658 QSignalSpy displayTextSpy(&serverMessageHandler, &ServerMessageHandler::fireDisplayTextChanged);
659 // Card connected, try to provoke message.
660 const QByteArray ifdTransmitMsg = IfdTransmit(connectResponse.getSlotHandle(), QByteArray("ABCDEF"), sendProgressMessage ? QStringLiteral("DummyText") : QString()).toByteArray(IfdVersion::Version::latest, contextHandle);
661 mDataChannel->onReceived(ifdTransmitMsg);
662 QTRY_COMPARE(sendSpy.count(), 1); // clazy:exclude=qstring-allocations
663
664 const QList<QVariant>& transmitResponseArguments = sendSpy.last();
665 const QVariant transmitResponseVariant = transmitResponseArguments.at(0);
666 QVERIFY(transmitResponseVariant.canConvert<QByteArray>());
667
668 const IfdTransmitResponse transmitResponse(IfdMessage::parseByteArray(transmitResponseVariant.toByteArray()));
669 QVERIFY(!transmitResponse.isIncomplete());
670 QCOMPARE(transmitResponse.getType(), IfdMessageType::IFDTransmitResponse);
671 QCOMPARE(transmitResponse.getContextHandle(), contextHandle);
672 QCOMPARE(transmitResponse.getSlotHandle(), connectResponse.getSlotHandle());
673 QVERIFY(!transmitResponse.resultHasError());
674 QCOMPARE(transmitResponse.getResultMinor(), ECardApiResult::Minor::null);
675 QCOMPARE(displayTextSpy.count(), sendProgressMessage ? 1 : 0);
676
677 removeReaderAndConsumeMessages(QStringLiteral("test-reader"));
678 }
679
680
605681 void ifdEstablishPACEChannelWithBasicReaderNameSendsAL_Unknown_Error()
606682 {
607683 const bool pinpadModeToSave = Env::getSingleton<AppSettings>()->getRemoteServiceSettings().getPinPadMode();
7070 void testPinPadMode()
7171 {
7272 RemoteServiceSettings settings;
73 QCOMPARE(settings.getPinPadMode(), true);
74 settings.setPinPadMode(false);
7375 QCOMPARE(settings.getPinPadMode(), false);
74 QCOMPARE(settings.getPinPadMode(), false);
76 }
77
78
79 void testShowAccessRights()
80 {
81 RemoteServiceSettings settings;
82 QCOMPARE(settings.getShowAccessRights(), false);
7583 settings.setPinPadMode(true);
7684 QCOMPARE(settings.getPinPadMode(), true);
7785 }
88 #include "ApplicationModel.h"
99
1010 #include "MockActivationContext.h"
11 #include "MockIfdServer.h"
1112 #include "context/AuthContext.h"
1213 #include "context/ChangePinContext.h"
14 #include "context/IfdServiceContext.h"
1315 #include "context/SelfAuthContext.h"
1416 #if __has_include("context/PersonalizationContext.h")
1517 #include "context/PersonalizationContext.h"
5759 QTest::addRow("No Context") << QSharedPointer<WorkflowContext>() << ApplicationModel::Workflow::WORKFLOW_NONE;
5860 QTest::addRow("AuthContext") << QSharedPointer<WorkflowContext>(new AuthContext(QSharedPointer<MockActivationContext>::create())) << ApplicationModel::Workflow::WORKFLOW_AUTHENTICATION;
5961 QTest::addRow("ChangePinContext") << QSharedPointer<WorkflowContext>(new ChangePinContext()) << ApplicationModel::Workflow::WORKFLOW_CHANGE_PIN;
62 QTest::addRow("IfdServiceContext") << QSharedPointer<WorkflowContext>(new IfdServiceContext(QSharedPointer<MockIfdServer>::create())) << ApplicationModel::Workflow::WORKFLOW_REMOTE_SERVICE;
6063 QTest::addRow("SelfAuthContext") << QSharedPointer<WorkflowContext>(new SelfAuthContext()) << ApplicationModel::Workflow::WORKFLOW_SELF_AUTHENTICATION;
6164 #if __has_include("context/PersonalizationContext.h")
6265 QTest::addRow("PersonalizationContext") << QSharedPointer<WorkflowContext>(new PersonalizationContext(QString())) << ApplicationModel::Workflow::WORKFLOW_SMART;
77
88 #include "CertificateDescriptionModel.h"
99
10 #include "MockIfdServer.h"
1011 #include "TestAuthContext.h"
1112 #include "TestFileHelper.h"
13 #include "context/IfdServiceContext.h"
1214
1315 #include <QDebug>
1416 #include <QtTest>
2527 private:
2628 CertificateDescriptionModel* mModel = nullptr;
2729 QSharedPointer<AuthContext> mContext;
30
31 static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId)
32 {
33 const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F");
34 const QByteArray certDescription = QByteArray::fromHex("30 8202A4"
35 " 06 0A 04007F00070301030103"
36 " A1 0E 0C0C442D547275737420476D6248"
37 " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E"
38 " A5 820248"
39 " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978");
40
41 return EstablishPaceChannel(pinId, chat, certDescription);
42 }
2843
2944 private Q_SLOTS:
3045 void init()
97112 }
98113
99114
115 void test_IfdContext()
116 {
117 auto ifdContext = QSharedPointer<IfdServiceContext>::create(QSharedPointer<MockIfdServer>::create());
118 mModel->resetContext(ifdContext);
119 const auto& establishPaceChannel = createDataToParse(PacePasswordId::PACE_PIN);
120 ifdContext->setEstablishPaceChannel(QSharedPointer<IfdEstablishPaceChannel>::create(QString(), establishPaceChannel, 6));
121
122 QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider"));
123 QCOMPARE(mModel->data(mModel->index(0), CertificateDescriptionModel::UserRoles::TEXT), QString("Gesamtverband der deutschen Versicherungswirtschaft e.V.\n"));
124 QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::LABEL), QString("Certificate issuer"));
125 QCOMPARE(mModel->data(mModel->index(1), CertificateDescriptionModel::UserRoles::TEXT), QString("D-Trust GmbH\n"));
126 QCOMPARE(mModel->data(mModel->index(2), CertificateDescriptionModel::UserRoles::LABEL), QString("Provider information"));
127 }
128
129
100130 };
101131
102132 QTEST_GUILESS_MAIN(test_CertificateDescriptionModel)
0 /**
1 * Copyright (c) 2023 Governikus GmbH & Co. KG, Germany
2 */
3
4 /*!
5 * \brief Unit tests for \ref RemoteDeviceModel
6 */
7
8 #include "RemoteDeviceFilterModel.h"
9
10 #include "RemoteDeviceModel.h"
11
12 #include <QtTest>
13
14
15 using namespace governikus;
16
17
18 class test_RemoteDeviceFilterModel
19 : public QObject
20 {
21 Q_OBJECT
22
23 private Q_SLOTS:
24 void test_FilterAcceptsRow()
25 {
26 QSharedPointer<RemoteDeviceModel> sourceModel = QSharedPointer<RemoteDeviceModel>::create();
27 QSharedPointer<RemoteDeviceFilterModel> filterModelAvail = QSharedPointer<RemoteDeviceFilterModel>::create(sourceModel.data(), RemoteDeviceFilterModel::showAvailableAndPaired);
28 QSharedPointer<RemoteDeviceFilterModel> filterModelUnavail = QSharedPointer<RemoteDeviceFilterModel>::create(sourceModel.data(), RemoteDeviceFilterModel::showUnavailableAndPaired);
29 QSharedPointer<RemoteDeviceFilterModel> filterModelAvailPair = QSharedPointer<RemoteDeviceFilterModel>::create(sourceModel.data(), RemoteDeviceFilterModel::showActivePairingMode);
30
31 const RemoteDeviceModelEntry availableEntry(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr);
32 const RemoteDeviceModelEntry unavailableEntry(QString("reader 2"), QString("test id"), false, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr);
33 const RemoteDeviceModelEntry availablePairingEntry(QString("reader 2"), QString("test id"), true, false, true, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), nullptr);
34
35 sourceModel->mAllRemoteReaders.insert(0, availableEntry);
36 sourceModel->mAllRemoteReaders.insert(1, unavailableEntry);
37 sourceModel->mAllRemoteReaders.insert(2, availablePairingEntry);
38
39 QCOMPARE(filterModelAvail->filterAcceptsRow(0, QModelIndex()), true);
40 QCOMPARE(filterModelAvail->filterAcceptsRow(1, QModelIndex()), false);
41
42 QCOMPARE(filterModelUnavail->filterAcceptsRow(0, QModelIndex()), false);
43 QCOMPARE(filterModelUnavail->filterAcceptsRow(1, QModelIndex()), true);
44
45 QCOMPARE(filterModelAvailPair->filterAcceptsRow(0, QModelIndex()), false);
46 QCOMPARE(filterModelAvailPair->filterAcceptsRow(1, QModelIndex()), false);
47 QCOMPARE(filterModelAvailPair->filterAcceptsRow(2, QModelIndex()), true);
48 }
49
50
51 };
52
53 QTEST_MAIN(test_RemoteDeviceFilterModel)
54 #include "test_RemoteDeviceFilterModel.moc"
11 * Copyright (c) 2018-2023 Governikus GmbH & Co. KG, Germany
22 */
33
4 #include "AppSettings.h"
5 #include "IfdDescriptor.h"
46 #include "RemoteDeviceModel.h"
57
68 #include <QtTest>
4143 }
4244
4345
46 void test_IsPairing()
47 {
48 QVERIFY(!mEntry->isPairing());
49 mEntry->setIsPairing(true);
50 QVERIFY(mEntry->isPairing());
51 }
52
53
4454 void test_DeviceNameEscaped()
4555 {
4656 QCOMPARE(mEntry->getDeviceNameEscaped(), mName);
7585 RemoteDeviceModelEntry entry1(name);
7686 const IfdDescriptor descriptor = IfdDescriptor();
7787 QSharedPointer<IfdListEntry> pointer(new IfdListEntry(descriptor));
78 RemoteDeviceModelEntry entry2(name, id, true, true, true, time, pointer);
88 RemoteDeviceModelEntry entry2(name, id, true, true, true, true, time, pointer);
7989
8090 QVERIFY(!entry1.isSupported());
8191 QVERIFY(entry2.isSupported());
8595 void test_RemoteDeviceListEntry()
8696 {
8797 const QString name = QStringLiteral("name");
88
98 const QString id = QStringLiteral("id");
8999 RemoteDeviceModelEntry entry1(name);
90100 QCOMPARE(entry1.getRemoteDeviceListEntry(), nullptr);
91101
92 const IfdDescriptor descriptor = IfdDescriptor();
93 QSharedPointer<IfdListEntry> pointer(new IfdListEntry(descriptor));
94 const QString id = QStringLiteral("id");
95 RemoteDeviceModelEntry entry2(name, id, pointer);
96 QCOMPARE(entry2.getRemoteDeviceListEntry(), pointer);
102 const IfdDescriptor defaultDescriptor = IfdDescriptor();
103 QSharedPointer<IfdListEntry> listEntry1(new IfdListEntry(defaultDescriptor));
104 RemoteDeviceModelEntry entry2(listEntry1);
105 QCOMPARE(entry2.getRemoteDeviceListEntry(), listEntry1);
106
107 const Discovery discovery = Discovery(name, id, 11111, {IfdVersion::supported()}, true);
108 const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true);
109 QSharedPointer<IfdListEntry> listEntry2(new IfdListEntry(descriptor));
110 RemoteDeviceModelEntry entry3(listEntry2);
111 QCOMPARE(entry3.getRemoteDeviceListEntry(), listEntry2);
112 QCOMPARE(entry3.getId(), id);
113 QCOMPARE(entry3.getDeviceNameEscaped(), name);
114 QVERIFY(entry3.isSupported());
97115 }
98116
99117
110128
111129 void test_RoleNames()
112130 {
131 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE));
132 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY));
133 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRING));
134 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED));
135 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED));
136 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE));
137 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID));
138 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED));
139 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_STATUS));
113140 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::REMOTE_DEVICE_NAME));
114 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::LAST_CONNECTED));
115 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::DEVICE_ID));
116 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE));
117 QVERIFY(mModel->roleNames().keys().contains(RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED));
118141
119142 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceName")));
143 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("remoteDeviceStatus")));
120144 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("lastConnected")));
121145 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("deviceId")));
122146 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isNetworkVisible")));
123147 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isSupported")));
148 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPaired")));
149 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isPairing")));
150 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("linkQualityInPercent")));
151 QVERIFY(mModel->roleNames().values().contains(QByteArrayLiteral("isLastAddedDevice")));
124152 }
125153
126154
138166 QCOMPARE(mModel->getStatus(entry), QString("Not paired"));
139167
140168 entry.setPaired(true);
141 QCOMPARE(mModel->getStatus(entry), QString("Paired, but unavailable"));
169 QCOMPARE(mModel->getStatus(entry), QString("Unavailable"));
142170
143171 entry.setNetworkVisible(true);
144172 QCOMPARE(mModel->getStatus(entry), QString("Available"));
145173
146174 entry.mSupported = false;
147175 QCOMPARE(mModel->getStatus(entry), QString("Paired, but unsupported"));
176
177 entry.setNetworkVisible(true);
178 entry.mSupported = true;
179 entry.mIsPairing = true;
180 QCOMPARE(mModel->getStatus(entry), QString("Click to pair"));
148181 }
149182
150183
165198
166199 void test_GetRemoteDeviceListEntryModelIndex()
167200 {
168 QSharedPointer<IfdListEntry> listEntry(new IfdListEntry(IfdDescriptor()));
169 RemoteDeviceModelEntry entry1(QString("entry 1"), QStringLiteral("01"), listEntry);
201 const Discovery discovery = Discovery(QStringLiteral("entry 1"), QStringLiteral("01"), 11111, {IfdVersion::supported()}, true);
202 const IfdDescriptor descriptor = IfdDescriptor(discovery, QHostAddress::LocalHost, true);
203 QSharedPointer<IfdListEntry> listEntry(new IfdListEntry(descriptor));
204 RemoteDeviceModelEntry entry1(listEntry);
205
170206 RemoteDeviceModelEntry entry2(QString("entry 2"));
171207 mModel->mAllRemoteReaders << entry1 << entry2;
172208
192228 QTest::newRow("network visible") << RemoteDeviceModel::SettingsRemoteRoles::IS_NETWORK_VISIBLE << 1 << 0 << QVariant(bool(false));
193229 QTest::newRow("supported") << RemoteDeviceModel::SettingsRemoteRoles::IS_SUPPORTED << 0 << 0 << QVariant(bool(true));
194230 QTest::newRow("paired") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true));
231 QTest::newRow("is pairing") << RemoteDeviceModel::SettingsRemoteRoles::IS_PAIRED << 0 << 0 << QVariant(bool(true));
195232 QTest::newRow("link quality") << RemoteDeviceModel::SettingsRemoteRoles::LINK_QUALITY << 0 << 0 << QVariant(int(0));
233 QTest::newRow("is last added device") << RemoteDeviceModel::SettingsRemoteRoles::IS_LAST_ADDED_DEVICE << 0 << 0 << QVariant(bool(false));
196234 }
197235
198236
205243
206244 QVector<RemoteDeviceModelEntry> readers;
207245 QSharedPointer<IfdListEntry> listEntry(new IfdListEntry(IfdDescriptor()));
208 const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry);
246 const RemoteDeviceModelEntry entry1(QString("reader 1"), QString("test id"), true, false, true, false, QDateTime(QDate(2019, 5, 14), QTime(0, 0)), listEntry);
209247 const RemoteDeviceModelEntry entry2(QString("reader 2"));
210248 readers << entry1 << entry2;
211249 mModel->mAllRemoteReaders = readers;
214252 }
215253
216254
255 void test_SetLastPairedReader()
256 {
257 const auto cert = QSslCertificate();
258
259 RemoteServiceSettings& settings = Env::getSingleton<AppSettings>()->getRemoteServiceSettings();
260 settings.addTrustedCertificate(cert);
261
262 const auto dName = QStringLiteral("myDeviceName");
263 const auto dId = QStringLiteral("myDeviceId");
264 const auto disco = Discovery(dName, dId, 12345, {IfdVersion::Version::latest}, false);
265 const auto ifdDesc = IfdDescriptor(disco, QHostAddress(QStringLiteral("127.0.0.1")));
266 const QSharedPointer<IfdListEntry> remoteDeviceListEntry(new IfdListEntry(ifdDesc));
267
268 mModel->addOrUpdateReader(RemoteDeviceModelEntry(remoteDeviceListEntry));
269
270 QSignalSpy spy(mModel.get(), &RemoteDeviceModel::dataChanged);
271 mModel->setLastPairedReader(cert);
272 QTRY_COMPARE(spy.size(), 1);
273 QVERIFY(mModel->data(mModel->index(0), RemoteDeviceModel::IS_LAST_ADDED_DEVICE).toBool());
274 }
275
276
217277 };
218278
219279 QTEST_MAIN(test_RemoteDeviceModel)
2626 private:
2727 RemoteServiceModel* mModel = nullptr;
2828 QSharedPointer<IfdServiceContext> mContext;
29
30 static EstablishPaceChannel createDataToParse(const PacePasswordId& pinId)
31 {
32 const QByteArray chat = QByteArray::fromHex("7F4C12060904007F00070301020253050000000F0F");
33 const QByteArray certDescription = QByteArray::fromHex("30 8202A4"
34 " 06 0A 04007F00070301030103"
35 " A1 0E 0C0C442D547275737420476D6248"
36 " A3 3A 0C38476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E"
37 " A5 820248"
38 " 04 820244 4E616D652C20416E7363687269667420756E6420452D4D61696C2D4164726573736520646573204469656E737465616E626965746572733A0D0A476573616D7476657262616E64206465722064657574736368656E20566572736963686572756E67737769727473636861667420652E562E0D0A57696C68656C6D73747261C39F652034332F3433670D0A3130313137204265726C696E0D0A6265726C696E406764762E64650D0A0D0A4765736368C3A46674737A7765636B3A0D0A2D52656769737472696572756E6720756E64204C6F67696E20616D204744562D4D616B6C6572706F7274616C2D0D0A0D0A48696E7765697320617566206469652066C3BC722064656E204469656E737465616E626965746572207A757374C3A46E646967656E205374656C6C656E2C20646965206469652045696E68616C74756E672064657220566F7273636872696674656E207A756D20446174656E73636875747A206B6F6E74726F6C6C696572656E3A0D0A4265726C696E6572204265617566747261677465722066C3BC7220446174656E73636875747A20756E6420496E666F726D6174696F6E7366726569686569740D0A416E20646572205572616E696120342D31300D0A3130373837204265726C696E0D0A3033302F3133382038392D300D0A6D61696C626F7840646174656E73636875747A2D6265726C696E2E64650D0A687474703A2F2F7777772E646174656E73636875747A2D6265726C696E2E64650D0A416E737072656368706172746E65723A2044722E20416C6578616E64657220446978");
39
40 return EstablishPaceChannel(pinId, chat, certDescription);
41 }
4229
4330 private Q_SLOTS:
4431 void initTestCase()
152139 }
153140
154141
142 void test_TransactionInfo()
143 {
144 mModel->resetRemoteServiceContext(mContext);
145 QCOMPARE(mModel->getTransactionInfo(), QString());
146 }
147
148
149 void test_getSupportedReaderPlugInTypes()
150 {
151 QVector<ReaderManagerPlugInType> supportedPlugIns {ReaderManagerPlugInType::NFC};
152 #if __has_include("SmartManager.h")
153 supportedPlugIns << ReaderManagerPlugInType::SMART;
154 #endif
155 QCOMPARE(mModel->getSupportedReaderPlugInTypes(), supportedPlugIns);
156 }
157
158
159 void test_DisplayText_data()
160 {
161 QTest::addColumn<QString>("inputText");
162 QTest::addColumn<QString>("outputText");
163 QTest::addColumn<int>("expectedPercentage");
164
165 QTest::newRow("positive two digits") << "Dummy Text\n15%" << "Dummy Text" << 15;
166 QTest::newRow("positive two digits with space") << "Dummy Text\n15 %" << "Dummy Text" << 15;
167 QTest::newRow("negative two digits") << "Dummy Text\n-15%" << "Dummy Text\n-15%" << 0;
168 QTest::newRow("positive two digits with percentage") << "Dummy Text\n15%" << "Dummy Text" << 15;
169 QTest::newRow("Whitespace input") << " " << " " << 0;
170 QTest::newRow("Special characters") << "!@#$%^&*()" << "!@#$%^&*()" << 0;
171 QTest::newRow("Digits only") << "12345" << "12345" << 0;
172 QTest::newRow("Single Digit") << "Dummy Text\n1%" << "Dummy Text" << 1;
173 QTest::newRow("Triple Digit") << "Dummy Text\n111%" << "Dummy Text\n111%" << 0;
174 QTest::newRow("100 Percent") << "Dummy Text\n100%" << "Dummy Text" << 100;
175 QTest::newRow("Quadruple Digit") << "Dummy Text\n1111%" << "Dummy Text\n1111%" << 0;
176 QTest::newRow("Real Number") << "Dummy Text\n11.1%" << "Dummy Text\n11.1%" << 0;
177 QTest::newRow("Zero Digit without Space") << "%" << "%" << 0;
178 QTest::newRow("Single Digit without Space") << "1%" << "" << 1;
179 QTest::newRow("Double Digit without Space") << "42%" << "" << 42;
180 QTest::newRow("Triple Digit without Space") << "100%" << "" << 100;
181 QTest::newRow("Zero Digit with Space") << " %" << " %" << 0;
182 QTest::newRow("Single Digit with Space") << "1 %" << "" << 1;
183 QTest::newRow("Double Digit with Space") << "42 %" << "" << 42;
184 QTest::newRow("Triple Digit with Space") << "100 %" << "" << 100;
185
186 }
187
188
189 void test_DisplayText()
190 {
191 QFETCH(QString, inputText);
192 QFETCH(QString, outputText);
193 QFETCH(int, expectedPercentage);
194
195 QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged);
196
197 mModel->resetRemoteServiceContext(mContext);
198 mContext->setDisplayText(inputText);
199 QCOMPARE(spyDisplayTextChanged.count(), 1);
200 QCOMPARE(mModel->getDisplayText(), outputText);
201 QCOMPARE(mModel->getPercentage(), expectedPercentage);
202 }
203
204
205 void test_DisplayTextSignals()
206 {
207 QSignalSpy spyDisplayTextChanged(mModel, &RemoteServiceModel::fireDisplayTextChanged);
208
209 QCOMPARE(mModel->getDisplayText(), "");
210 QCOMPARE(mModel->getPercentage(), 0);
211
212 mModel->resetRemoteServiceContext(mContext);
213 QCOMPARE(spyDisplayTextChanged.count(), 0);
214 mContext->setDisplayText("Dummy");
215 QCOMPARE(spyDisplayTextChanged.count(), 1);
216 mContext->setDisplayText("Dummy");
217 QCOMPARE(spyDisplayTextChanged.count(), 1);
218
219 }
220
221
155222 };
156223
157224 QTEST_MAIN(test_RemoteServiceModel)
77
88 #include "WorkflowModel.h"
99
10 #include "Env.h"
1011 #include "MockCardConnectionWorker.h"
12 #include "MockReaderManagerPlugIn.h"
13 #include "ReaderManager.h"
1114 #include "TestWorkflowContext.h"
1215
1316 #include <QDebug>
1417 #include <QtTest>
1518
19 Q_IMPORT_PLUGIN(MockReaderManagerPlugIn)
1620
1721 using namespace governikus;
1822
108112 }
109113
110114
115 void test_startScanExplicitly()
116 {
117 const auto readerManager = Env::getSingleton<ReaderManager>();
118 readerManager->init();
119 readerManager->isScanRunning(); // just to wait until initialization finished
120
121 QSharedPointer<WorkflowContext> context(new TestWorkflowContext());
122 QSignalSpy spy(context.data(), &WorkflowContext::fireReaderPlugInTypesChanged);
123
124 WorkflowModel model;
125 model.resetWorkflowContext(context);
126
127 model.startScanExplicitly();
128 QTRY_COMPARE(spy.count(), 1);
129 QCOMPARE(spy.takeFirst().at(0).toBool(), true);
130 }
131
132
133 void test_hasCard()
134 {
135 const auto readerManager = Env::getSingleton<ReaderManager>();
136 readerManager->init();
137 readerManager->isScanRunning(); // just to wait until initialization finished
138
139 WorkflowModel model;
140 QCOMPARE(model.hasCard(), false);
141
142 QSharedPointer<WorkflowContext> context(new TestWorkflowContext());
143 model.resetWorkflowContext(context);
144 QCOMPARE(model.hasCard(), false);
145
146 auto mockReader = MockReaderManagerPlugIn::getInstance().addReader("SomeReaderWithCard");
147 auto info = mockReader->getReaderInfo();
148 info.setCardInfo(CardInfo(CardType::EID_CARD, QSharedPointer<EFCardAccess>(), 3, false, false, false));
149 mockReader->setReaderInfo(info);
150 model.setReaderPlugInType(ReaderManagerPlugInType::MOCK);
151 QCOMPARE(model.hasCard(), true);
152 }
153
154
111155 };
112156
113157 QTEST_MAIN(test_WorkflowModel)
272272 }
273273
274274
275 void test_setInterruptRequested()
276 {
277 QVERIFY(!mContext->interruptRequested());
278
279 mContext->setInterruptRequested(true);
280 QVERIFY(mContext->interruptRequested());
281
282 mContext->setInterruptRequested(false);
283 QVERIFY(!mContext->interruptRequested());
284 }
285
286
275287 };
276288
277289 QTEST_GUILESS_MAIN(test_WorkflowContext)
3737 {
3838 Q_UNUSED(pSlotHandle)
3939 Q_UNUSED(pResponseApdu)
40 }
41
42
43 void setAllowedCardTypes(const QVector<ReaderManagerPlugInType>& pAllowedCardTypes) override
44 {
45 Q_UNUSED(pAllowedCardTypes)
4046 }
4147
4248
3434 const QSharedPointer<IfdServiceContext> context(new IfdServiceContext(mIfdServer));
3535 StateProcessIfdMessages state(context);
3636 state.run();
37 QCOMPARE(state.mConnections.size(), 4);
38 QCOMPARE(state.mMessageConnections.size(), 6);
37 QCOMPARE(state.mConnections.size(), 1);
38 QCOMPARE(state.mMessageConnections.size(), 7);
3939 }
4040
4141
4949 QCOMPARE(state.mMessageConnections.size(), 0);
5050
5151 state.onMessageHandlerAdded(messageHandler);
52 QCOMPARE(state.mMessageConnections.size(), 6);
52 QCOMPARE(state.mMessageConnections.size(), 7);
5353 }
5454
5555
114114 }
115115
116116
117 void test_OnDisplayTextChanged()
118 {
119 const QSharedPointer<IfdServiceContext> context(new IfdServiceContext(mIfdServer));
120 StateProcessIfdMessages state(context);
121 QSignalSpy spy(context.data(), &IfdServiceContext::fireDisplayTextChanged);
122
123 state.onDisplayTextChanged(QStringLiteral("dummy text"));
124 QCOMPARE(spy.count(), 1);
125 QCOMPARE(context->getDisplayText(), QStringLiteral("dummy text"));
126 state.onCardDisconnected();
127 QCOMPARE(spy.count(), 2);
128 QCOMPARE(context->getDisplayText(), QStringLiteral(""));
129 }
130
131
117132 };
118133
119134 QTEST_GUILESS_MAIN(test_StateProcessIfdMessages)
9696 mAuthContext->setCardConnection(connection);
9797 mAuthContext->setEstablishPaceChannelType(PacePasswordId::PACE_PIN);
9898
99 QCOMPARE(mAuthContext->getProgressValue(), 0);
100 QCOMPARE(mAuthContext->getProgressMessage(), QString());
99101 QTest::ignoreMessage(QtDebugMsg, "Establish connection using PACE_PIN");
100102 mState->run();
101103 QCOMPARE(mAuthContext->getEstablishPaceChannelType(), PacePasswordId::PACE_PIN);
102104 QCOMPARE(mState->mPasswordId, PacePasswordId::PACE_PIN);
105 QCOMPARE(mAuthContext->getProgressValue(), 0);
106 QCOMPARE(mAuthContext->getProgressMessage(), tr("The secure channel is opened"));
103107 }
104108
105109
130130 QCOMPARE(spy.count(), 1);
131131
132132 const auto& failureCode = mState->getContext()->getFailureCode();
133 QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Ssl_Error);
133 QCOMPARE(failureCode, FailureCode::Reason::Generic_Provider_Communication_Tls_Error);
134134 QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Network_Error], mState->mReply->errorString());
135135 QCOMPARE(failureCode->getFailureInfoMap()[FailureCode::Info::Ssl_Errors], TlsChecker::sslErrorsToString(errorList));
136136 }
9090 QTRY_COMPARE(spyAbort.count(), isValid ? 0 : 1); // clazy:exclude=qstring-allocations
9191 if (!isValid)
9292 {
93 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired);
93 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired);
9494 }
9595 }
9696
103103 mAuthContext->setStateApproved();
104104
105105 QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations
106 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired);
106 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired);
107107 }
108108
109109
115115 mAuthContext->setStateApproved();
116116
117117 QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations
118 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Chain);
118 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Chain);
119119 }
120120
121121
135135 mAuthContext->setStateApproved();
136136
137137 QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations
138 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Invalid_Certificate_Signature);
138 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Invalid_Certificate_Signature);
139139 }
140140
141141
147147 mAuthContext->setStateApproved();
148148
149149 QTRY_COMPARE(spy.count(), 1); // clazy:exclude=qstring-allocations
150 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verfication_Certificate_Expired);
150 QCOMPARE(mAuthContext->getFailureCode(), FailureCode::Reason::Pre_Verification_Certificate_Expired);
151151 }
152152
153153