summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2021-12-06 07:57:52 -0500
committerB. Stack <bgstack15@gmail.com>2021-12-06 07:57:52 -0500
commit226ac347c51e21440d1740d85b5e9912d1ce08e5 (patch)
tree2999df8f80b28d0f7f60a84b7f75d613e280bba1
parentMerge branch 'b11.14' into 'master' (diff)
downloadFreeFileSync-226ac347c51e21440d1740d85b5e9912d1ce08e5.tar.gz
FreeFileSync-226ac347c51e21440d1740d85b5e9912d1ce08e5.tar.bz2
FreeFileSync-226ac347c51e21440d1740d85b5e9912d1ce08e5.zip
add upstream 11.15
-rw-r--r--Changelog.txt11
-rw-r--r--FreeFileSync/Build/Resources/Languages.zipbin507711 -> 507742 bytes
-rw-r--r--FreeFileSync/Build/Resources/bell.wavbin143370 -> 102500 bytes
-rw-r--r--FreeFileSync/Build/Resources/cacert.pem102
-rw-r--r--FreeFileSync/Build/Resources/fail.wavbin0 -> 35092 bytes
-rw-r--r--FreeFileSync/Build/Resources/fail2.wavbin0 -> 50454 bytes
-rw-r--r--FreeFileSync/Build/Resources/remind.wavbin0 -> 59894 bytes
-rw-r--r--FreeFileSync/Source/Makefile1
-rw-r--r--FreeFileSync/Source/RealTimeSync/Makefile1
-rw-r--r--FreeFileSync/Source/RealTimeSync/folder_selector2.cpp1
-rw-r--r--FreeFileSync/Source/RealTimeSync/main_dlg.cpp1
-rw-r--r--FreeFileSync/Source/afs/abstract.h1
-rw-r--r--FreeFileSync/Source/afs/ftp.cpp17
-rw-r--r--FreeFileSync/Source/application.cpp4
-rw-r--r--FreeFileSync/Source/base/dir_lock.cpp6
-rw-r--r--FreeFileSync/Source/config.cpp63
-rw-r--r--FreeFileSync/Source/config.h1
-rw-r--r--FreeFileSync/Source/ui/batch_status_handler.cpp12
-rw-r--r--FreeFileSync/Source/ui/batch_status_handler.h2
-rw-r--r--FreeFileSync/Source/ui/cfg_grid.cpp2
-rw-r--r--FreeFileSync/Source/ui/file_grid.cpp2
-rw-r--r--FreeFileSync/Source/ui/gui_generated.cpp51
-rw-r--r--FreeFileSync/Source/ui/gui_generated.h62
-rw-r--r--FreeFileSync/Source/ui/gui_status_handler.cpp24
-rw-r--r--FreeFileSync/Source/ui/gui_status_handler.h11
-rw-r--r--FreeFileSync/Source/ui/main_dlg.cpp32
-rw-r--r--FreeFileSync/Source/ui/small_dlgs.cpp33
-rw-r--r--FreeFileSync/Source/ui/tree_grid.cpp2
-rw-r--r--FreeFileSync/Source/version/version.h2
-rw-r--r--License.txt304
-rw-r--r--wx+/popup_dlg.cpp25
-rw-r--r--wx+/popup_dlg.h3
-rw-r--r--wx+/std_button_layout.h61
-rw-r--r--xBRZ/src/xbrz.cpp10
-rw-r--r--zen/file_access.cpp65
-rw-r--r--zen/file_access.h9
-rw-r--r--zen/file_path.cpp79
-rw-r--r--zen/file_path.h27
-rw-r--r--zen/http.cpp1
-rw-r--r--zen/resolve_path.cpp3
-rw-r--r--zen/symlink_target.h15
-rw-r--r--zen/zstring.h4
42 files changed, 698 insertions, 352 deletions
diff --git a/Changelog.txt b/Changelog.txt
index b6984b1d..0e2924dc 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,14 @@
+FreeFileSync 11.15 [2021-12-03]
+-------------------------------
+Play sound reminder when waiting for user confirmation
+Enhanced crash diagnostics with known triggers
+Defer reporting third-party incompatibilities until after crashing
+Support running FreeFileSync from Dokany-based encrypted volumes
+Fixed Server 2019 not being detected for log file
+Use native representation for modified config (macOS)
+Improved WinMerge detection for external app integration
+
+
FreeFileSync 11.14 [2021-09-20]
-------------------------------
Authenticate (S)FTP connections using OpenSSL 3.0
diff --git a/FreeFileSync/Build/Resources/Languages.zip b/FreeFileSync/Build/Resources/Languages.zip
index 156bfa90..9044f9bc 100644
--- a/FreeFileSync/Build/Resources/Languages.zip
+++ b/FreeFileSync/Build/Resources/Languages.zip
Binary files differ
diff --git a/FreeFileSync/Build/Resources/bell.wav b/FreeFileSync/Build/Resources/bell.wav
index 9d66acf9..5c3e245a 100644
--- a/FreeFileSync/Build/Resources/bell.wav
+++ b/FreeFileSync/Build/Resources/bell.wav
Binary files differ
diff --git a/FreeFileSync/Build/Resources/cacert.pem b/FreeFileSync/Build/Resources/cacert.pem
index fdb454dc..0bf312fe 100644
--- a/FreeFileSync/Build/Resources/cacert.pem
+++ b/FreeFileSync/Build/Resources/cacert.pem
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Mon Jul 5 21:35:54 2021 GMT
+## Certificate data from Mozilla as of: Tue Oct 26 03:12:05 2021 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.28.
-## SHA256: c8f6733d1ff4e6a4769c182971a1234f95ae079247a9c439a13423fe8ba5c24f
+## SHA256: bb36818a81feaa4cca61101e6d6276cd09e972efcb08112dfed846918ca41d7f
##
@@ -381,26 +381,6 @@ mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
-----END CERTIFICATE-----
-DST Root CA X3
-==============
------BEGIN CERTIFICATE-----
-MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
-ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
-DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
-cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
-rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
-UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
-xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
-utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
-AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
-MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
-dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
-GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
-RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
-fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
------END CERTIFICATE-----
-
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
@@ -3172,3 +3152,81 @@ WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj
OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck
bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
-----END CERTIFICATE-----
+
+TunTrust Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG
+A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj
+dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw
+NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD
+ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz
+2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b
+bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7
+NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd
+gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW
+VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f
+Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ
+juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas
+DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS
+VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI
+04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
+90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl
+0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd
+Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY
+YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp
+adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x
+xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP
+jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM
+MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z
+ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r
+AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
+-----END CERTIFICATE-----
+
+HARICA TLS RSA Root CA 2021
+===========================
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG
+EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
+cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz
+OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl
+bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB
+IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN
+JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu
+a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y
+Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K
+5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv
+dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR
+0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH
+GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm
+haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ
+CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU
+EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq
+QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD
+QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR
+j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5
+vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0
+qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6
+Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/
+PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn
+kf3/W9b3raYvAwtt41dU63ZTGI0RmLo=
+-----END CERTIFICATE-----
+
+HARICA TLS ECC Root CA 2021
+===========================
+-----BEGIN CERTIFICATE-----
+MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH
+UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD
+QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX
+DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj
+IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv
+b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l
+AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b
+ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW
+0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi
+rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw
+CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
+-----END CERTIFICATE-----
diff --git a/FreeFileSync/Build/Resources/fail.wav b/FreeFileSync/Build/Resources/fail.wav
new file mode 100644
index 00000000..50a8d08a
--- /dev/null
+++ b/FreeFileSync/Build/Resources/fail.wav
Binary files differ
diff --git a/FreeFileSync/Build/Resources/fail2.wav b/FreeFileSync/Build/Resources/fail2.wav
new file mode 100644
index 00000000..1b6a8c38
--- /dev/null
+++ b/FreeFileSync/Build/Resources/fail2.wav
Binary files differ
diff --git a/FreeFileSync/Build/Resources/remind.wav b/FreeFileSync/Build/Resources/remind.wav
new file mode 100644
index 00000000..d5b47041
--- /dev/null
+++ b/FreeFileSync/Build/Resources/remind.wav
Binary files differ
diff --git a/FreeFileSync/Source/Makefile b/FreeFileSync/Source/Makefile
index 987362b6..1d422d02 100644
--- a/FreeFileSync/Source/Makefile
+++ b/FreeFileSync/Source/Makefile
@@ -80,6 +80,7 @@ cppFiles+=ui/version_check.cpp
cppFiles+=../../libcurl/rest.cpp
cppFiles+=../../zen/file_access.cpp
cppFiles+=../../zen/file_io.cpp
+cppFiles+=../../zen/file_path.cpp
cppFiles+=../../zen/file_traverser.cpp
cppFiles+=../../zen/http.cpp
cppFiles+=../../zen/zstring.cpp
diff --git a/FreeFileSync/Source/RealTimeSync/Makefile b/FreeFileSync/Source/RealTimeSync/Makefile
index 716bbf1b..3a69ce60 100644
--- a/FreeFileSync/Source/RealTimeSync/Makefile
+++ b/FreeFileSync/Source/RealTimeSync/Makefile
@@ -34,6 +34,7 @@ cppFiles+=../../../xBRZ/src/xbrz.cpp
cppFiles+=../../../zen/dir_watcher.cpp
cppFiles+=../../../zen/file_access.cpp
cppFiles+=../../../zen/file_io.cpp
+cppFiles+=../../../zen/file_path.cpp
cppFiles+=../../../zen/file_traverser.cpp
cppFiles+=../../../zen/format_unit.cpp
cppFiles+=../../../zen/legacy_compiler.cpp
diff --git a/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp b/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
index f9897c61..d8478473 100644
--- a/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
+++ b/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
@@ -7,6 +7,7 @@
#include "folder_selector2.h"
#include <zen/thread.h>
#include <zen/file_access.h>
+#include <zen/file_path.h>
#include <wx/dirdlg.h>
#include <wx/scrolwin.h>
#include <wx+/popup_dlg.h>
diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
index 0e4c21df..dc7238bf 100644
--- a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
+++ b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
@@ -12,6 +12,7 @@
#include <wx+/popup_dlg.h>
#include <wx+/image_resources.h>
#include <zen/file_access.h>
+#include <zen/file_path.h>
#include <zen/build_info.h>
#include <zen/time.h>
#include "config.h"
diff --git a/FreeFileSync/Source/afs/abstract.h b/FreeFileSync/Source/afs/abstract.h
index a507a152..cd5aa1a6 100644
--- a/FreeFileSync/Source/afs/abstract.h
+++ b/FreeFileSync/Source/afs/abstract.h
@@ -257,6 +257,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
//Note: it MAY happen that copyFileTransactional() leaves temp files behind, e.g. temporary network drop.
// => clean them up at an appropriate time (automatically set sync directions to delete them). They have the following ending:
static inline const Zchar* const TEMP_FILE_ENDING = Zstr(".ffs_tmp"); //don't use Zstring as global constant: avoid static initialization order problem in global namespace!
+ // caveat: ending is hard-coded by RealTimeSync
struct FileCopyResult
{
diff --git a/FreeFileSync/Source/afs/ftp.cpp b/FreeFileSync/Source/afs/ftp.cpp
index bedd811f..ce5aaa02 100644
--- a/FreeFileSync/Source/afs/ftp.cpp
+++ b/FreeFileSync/Source/afs/ftp.cpp
@@ -17,6 +17,10 @@
#include <glib.h>
#include <fcntl.h>
+warn_static("remove after test (including openssl-headers set for ftp.cpp")
+//#include <openssl/ssl.h> //SSL_OP_IGNORE_UNEXPECTED_EOF
+
+
using namespace zen;
using namespace fff;
using AFS = AbstractFileSystem;
@@ -454,6 +458,19 @@ public:
{
options.emplace_back(CURLOPT_USE_SSL, CURLUSESSL_ALL); //require SSL for both control and data
options.emplace_back(CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS); //try TLS first, then SSL (currently: CURLFTPAUTH_DEFAULT == CURLFTPAUTH_SSL)
+
+
+ warn_static("remove after test")
+#if 0
+ using SslContextCbType = CURLcode (*)(CURL* curl, SSL_CTX* ssl_ctx, void* userptr); //needed for cdecl function pointer cast
+ SslContextCbType onSslContextWrapper = [](CURL* curl, SSL_CTX* ssl_ctx, void* userptr)
+ {
+ assert((::SSL_CTX_get_options(ssl_ctx) & SSL_OP_IGNORE_UNEXPECTED_EOF) == 0);
+ ::SSL_CTX_set_options(ssl_ctx, SSL_OP_IGNORE_UNEXPECTED_EOF); //does not set, but *adds* options; no-fail
+ return CURLE_OK;
+ };
+ options.emplace_back(CURLOPT_SSL_CTX_FUNCTION, onSslContextWrapper);
+#endif
}
//let's not hold our breath until Curl adds a reasonable PASV handling => patch libcurl accordingly!
diff --git a/FreeFileSync/Source/application.cpp b/FreeFileSync/Source/application.cpp
index 16f82c8a..00c5281b 100644
--- a/FreeFileSync/Source/application.cpp
+++ b/FreeFileSync/Source/application.cpp
@@ -7,6 +7,7 @@
#include "application.h"
#include <memory>
#include <zen/file_access.h>
+#include <zen/file_path.h>
#include <zen/perf.h>
#include <zen/shutdown.h>
#include <zen/process_exec.h>
@@ -39,8 +40,6 @@ IMPLEMENT_APP(Application)
namespace
{
-
-
std::vector<Zstring> getCommandlineArgs(const wxApp& app)
{
std::vector<Zstring> args;
@@ -593,6 +592,7 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
batchCfg.mainCfg.autoRetryCount,
batchCfg.mainCfg.autoRetryDelay,
globalCfg.soundFileSyncFinished,
+ globalCfg.soundFileAlertPending,
globalCfg.dpiLayouts[getDpiScalePercent()].progressDlg.dlgSize,
globalCfg.dpiLayouts[getDpiScalePercent()].progressDlg.isMaximized,
batchCfg.batchExCfg.autoCloseSummary,
diff --git a/FreeFileSync/Source/base/dir_lock.cpp b/FreeFileSync/Source/base/dir_lock.cpp
index ba3b7974..b449f976 100644
--- a/FreeFileSync/Source/base/dir_lock.cpp
+++ b/FreeFileSync/Source/base/dir_lock.cpp
@@ -3,6 +3,7 @@
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
+
#include "dir_lock.h"
#include <map>
#include <memory>
@@ -12,6 +13,7 @@
#include <zen/scope_guard.h>
#include <zen/guid.h>
#include <zen/file_access.h>
+#include <zen/file_path.h>
#include <zen/file_io.h>
#include <zen/sys_info.h>
@@ -500,8 +502,8 @@ public:
tidyUp();
//optimization: check if we already own a lock for this path
- auto itGuid = guidByPath_.find(lockFilePath);
- if (itGuid != guidByPath_.end())
+ if (auto itGuid = guidByPath_.find(lockFilePath);
+ itGuid != guidByPath_.end())
if (const std::shared_ptr<SharedDirLock>& activeLock = getActiveLock(itGuid->second)) //returns null-lock if not found
return activeLock; //SharedDirLock is still active -> enlarge circle of shared ownership
diff --git a/FreeFileSync/Source/config.cpp b/FreeFileSync/Source/config.cpp
index 111ba57a..e5cb92c7 100644
--- a/FreeFileSync/Source/config.cpp
+++ b/FreeFileSync/Source/config.cpp
@@ -23,21 +23,21 @@ using namespace fff; //functionally needed for correct overload resolution!!!
namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
-const int XML_FORMAT_GLOBAL_CFG = 22; //2021-07-31
+const int XML_FORMAT_GLOBAL_CFG = 23; //2021-12-02
const int XML_FORMAT_SYNC_CFG = 17; //2020-10-14
//-------------------------------------------------------------------------------------------------------------------------------
}
const ExternalApp fff::extCommandFileBrowse
- //"xdg-open \"%parent_path%\"" -> not good enough: we need %local_path% for proper MTP/Google Drive handling
- {L"Browse directory", "xdg-open \"$(dirname \"%local_path%\")\""};
- //mark for extraction: _("Browse directory") Linux doesn't use the term "folder"
+//"xdg-open \"%parent_path%\"" -> not good enough: we need %local_path% for proper MTP/Google Drive handling
+{L"Browse directory", "xdg-open \"$(dirname \"%local_path%\")\""};
+//mark for extraction: _("Browse directory") Linux doesn't use the term "folder"
const ExternalApp fff::extCommandOpenDefault
- //"xdg-open \"%parent_path%\"" -> not good enough: we need %local_path% for proper MTP/Google Drive handling
- {L"Open with default application", "xdg-open \"%local_path%\""};
+//"xdg-open \"%parent_path%\"" -> not good enough: we need %local_path% for proper MTP/Google Drive handling
+{L"Open with default application", "xdg-open \"%local_path%\""};
XmlType getXmlTypeNoThrow(const XmlDoc& doc) //throw()
@@ -87,8 +87,11 @@ void setXmlType(XmlDoc& doc, XmlType type) //throw()
}
+
+
XmlGlobalSettings::XmlGlobalSettings() :
- soundFileSyncFinished(getResourceDirPf() + Zstr("bell.wav"))
+ soundFileSyncFinished(getResourceDirPf() + Zstr("bell.wav")),
+ soundFileAlertPending(getResourceDirPf() + Zstr("remind.wav"))
{
}
@@ -1502,8 +1505,6 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
in2["VerifyCopiedFiles" ].attribute("Enabled", cfg.verifyFileCopy);
in2["LogFiles" ].attribute("MaxAge", cfg.logfilesMaxAgeDays);
in2["LogFiles" ].attribute("Format", cfg.logFormat);
- in2["NotificationSound" ].attribute("CompareFinished", cfg.soundFileCompareFinished);
- in2["NotificationSound" ].attribute("SyncFinished", cfg.soundFileSyncFinished);
//TODO: remove old parameter after migration! 2021-03-06
if (formatVer < 21)
@@ -1515,18 +1516,6 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
in2["ProgressDialog"].attribute("AutoClose", cfg.progressDlgAutoClose);
- //TODO: remove if parameter migration after some time! 2019-05-29
- if (formatVer < 13)
- {
- if (!cfg.soundFileCompareFinished.empty()) cfg.soundFileCompareFinished = getResourceDirPf() + cfg.soundFileCompareFinished;
- if (!cfg.soundFileSyncFinished .empty()) cfg.soundFileSyncFinished = getResourceDirPf() + cfg.soundFileSyncFinished;
- }
- else
- {
- cfg.soundFileCompareFinished = resolveFfsResourceMacro(cfg.soundFileCompareFinished);
- cfg.soundFileSyncFinished = resolveFfsResourceMacro(cfg.soundFileSyncFinished);
- }
-
//TODO: remove if parameter migration after some time! 2018-08-13
if (formatVer < 14)
if (cfg.logfilesMaxAgeDays == 14) //default value was too small
@@ -1574,6 +1563,32 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inOpt["WarnVersioningFolderPartOfSync"].attribute("Show", cfg.warnDlgs.warnVersioningFolderPartOfSync);
}
+ //TODO: remove after migration! 2021-12-02
+ if (formatVer < 23)
+ {
+ in2["NotificationSound"].attribute("CompareFinished", cfg.soundFileCompareFinished);
+ in2["NotificationSound"].attribute("SyncFinished", cfg.soundFileSyncFinished);
+ }
+ else
+ {
+ in2["Sounds"]["CompareFinished"].attribute("Path", cfg.soundFileCompareFinished);
+ in2["Sounds"]["SyncFinished" ].attribute("Path", cfg.soundFileSyncFinished);
+ in2["Sounds"]["AlertPending" ].attribute("Path", cfg.soundFileAlertPending);
+ }
+
+ //TODO: remove if parameter migration after some time! 2019-05-29
+ if (formatVer < 13)
+ {
+ if (!cfg.soundFileCompareFinished.empty()) cfg.soundFileCompareFinished = getResourceDirPf() + cfg.soundFileCompareFinished;
+ if (!cfg.soundFileSyncFinished .empty()) cfg.soundFileSyncFinished = getResourceDirPf() + cfg.soundFileSyncFinished;
+ }
+ else
+ {
+ cfg.soundFileCompareFinished = resolveFfsResourceMacro(cfg.soundFileCompareFinished);
+ cfg.soundFileSyncFinished = resolveFfsResourceMacro(cfg.soundFileSyncFinished);
+ cfg.soundFileAlertPending = resolveFfsResourceMacro(cfg.soundFileAlertPending);
+ }
+
XmlIn inMainWin = in["MainDialog"];
//TODO: remove old parameter after migration! 2020-12-03
@@ -2329,8 +2344,6 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
out["VerifyCopiedFiles" ].attribute("Enabled", cfg.verifyFileCopy);
out["LogFiles" ].attribute("MaxAge", cfg.logfilesMaxAgeDays);
out["LogFiles" ].attribute("Format", cfg.logFormat);
- out["NotificationSound" ].attribute("CompareFinished", substituteFfsResourcePath(cfg.soundFileCompareFinished));
- out["NotificationSound" ].attribute("SyncFinished", substituteFfsResourcePath(cfg.soundFileSyncFinished));
out["ProgressDialog"].attribute("AutoClose", cfg.progressDlgAutoClose);
@@ -2352,6 +2365,10 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
outOpt["WarnDirectoryLockFailed" ].attribute("Show", cfg.warnDlgs.warnDirectoryLockFailed);
outOpt["WarnVersioningFolderPartOfSync"].attribute("Show", cfg.warnDlgs.warnVersioningFolderPartOfSync);
+ out["Sounds"]["CompareFinished"].attribute("Path", substituteFfsResourcePath(cfg.soundFileCompareFinished));
+ out["Sounds"]["SyncFinished" ].attribute("Path", substituteFfsResourcePath(cfg.soundFileSyncFinished));
+ out["Sounds"]["AlertPending" ].attribute("Path", substituteFfsResourcePath(cfg.soundFileAlertPending));
+
//gui specific global settings (optional)
XmlOut outMainWin = out["MainDialog"];
diff --git a/FreeFileSync/Source/config.h b/FreeFileSync/Source/config.h
index 4278ebf1..9e366cb9 100644
--- a/FreeFileSync/Source/config.h
+++ b/FreeFileSync/Source/config.h
@@ -166,6 +166,7 @@ struct XmlGlobalSettings
Zstring soundFileCompareFinished;
Zstring soundFileSyncFinished;
+ Zstring soundFileAlertPending;
ConfirmationDialogs confirmDlgs;
WarningDialogs warnDlgs;
diff --git a/FreeFileSync/Source/ui/batch_status_handler.cpp b/FreeFileSync/Source/ui/batch_status_handler.cpp
index 7950f76d..3e5ee9a5 100644
--- a/FreeFileSync/Source/ui/batch_status_handler.cpp
+++ b/FreeFileSync/Source/ui/batch_status_handler.cpp
@@ -25,6 +25,7 @@ BatchStatusHandler::BatchStatusHandler(bool showProgress,
size_t autoRetryCount,
std::chrono::seconds autoRetryDelay,
const Zstring& soundFileSyncComplete,
+ const Zstring& soundFileAlertPending,
wxSize progressDlgSize, bool dlgMaximize,
bool autoCloseDialog,
PostSyncAction postSyncAction,
@@ -34,6 +35,7 @@ BatchStatusHandler::BatchStatusHandler(bool showProgress,
autoRetryCount_(autoRetryCount),
autoRetryDelay_(autoRetryDelay),
soundFileSyncComplete_(soundFileSyncComplete),
+ soundFileAlertPending_(soundFileAlertPending),
progressDlg_(SyncProgressDialog::create(progressDlgSize, dlgMaximize, [this] { userRequestAbort(); }, *this, nullptr /*parentWindow*/, showProgress, autoCloseDialog,
{jobName}, startTime, ignoreErrors, autoRetryCount, [&]
{
@@ -195,7 +197,7 @@ BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& post
if (!autoClose) //only play when showing results dialog
if (!soundFileSyncComplete_.empty())
{
- //wxWidgets shows modal error dialog by default => NO!
+ //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
@@ -285,6 +287,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& msg, bool& warningAct
bool dontWarnAgain = false;
switch (showQuestionDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::warning,
PopupDialogCfg().setDetailInstructions(msg + L"\n\n" + _("You can switch to FreeFileSync's main window to resolve this issue.")).
+ remindWhenPending(soundFileAlertPending_).
setCheckBox(dontWarnAgain, _("&Don't show this warning again"), static_cast<ConfirmationButton3>(QuestionButton2::no)),
_("&Ignore"), _("&Switch")))
{
@@ -339,7 +342,8 @@ ProcessCallback::Response BatchStatusHandler::reportError(const ErrorInfo& error
forceUiUpdateNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::error,
- PopupDialogCfg().setDetailInstructions(errorInfo.msg),
+ PopupDialogCfg().setDetailInstructions(errorInfo.msg).
+ remindWhenPending(soundFileAlertPending_),
_("&Ignore"), _("Ignore &all"), _("&Retry")))
{
case ConfirmationButton3::accept: //ignore
@@ -388,8 +392,8 @@ void BatchStatusHandler::reportFatalError(const std::wstring& msg)
forceUiUpdateNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::error,
- PopupDialogCfg().setTitle(_("Error")).
- setDetailInstructions(msg),
+ PopupDialogCfg().setDetailInstructions(msg).
+ remindWhenPending(soundFileAlertPending_),
_("&Ignore"), _("Ignore &all")))
{
case ConfirmationButton2::accept: //ignore
diff --git a/FreeFileSync/Source/ui/batch_status_handler.h b/FreeFileSync/Source/ui/batch_status_handler.h
index 91c1d78d..80a5baf4 100644
--- a/FreeFileSync/Source/ui/batch_status_handler.h
+++ b/FreeFileSync/Source/ui/batch_status_handler.h
@@ -27,6 +27,7 @@ public:
size_t autoRetryCount,
std::chrono::seconds autoRetryDelay,
const Zstring& soundFileSyncComplete,
+ const Zstring& soundFileAlertPending,
wxSize progressDlgSize, bool dlgMaximize,
bool autoCloseDialog,
PostSyncAction postSyncAction,
@@ -67,6 +68,7 @@ private:
const size_t autoRetryCount_;
const std::chrono::seconds autoRetryDelay_;
const Zstring soundFileSyncComplete_;
+ const Zstring soundFileAlertPending_;
SyncProgressDialog* progressDlg_; //managed to have the same lifetime as this handler!
zen::ErrorLog errorLog_; //list of non-resolved errors and warnings
diff --git a/FreeFileSync/Source/ui/cfg_grid.cpp b/FreeFileSync/Source/ui/cfg_grid.cpp
index 2f1f1776..b9f0a2f2 100644
--- a/FreeFileSync/Source/ui/cfg_grid.cpp
+++ b/FreeFileSync/Source/ui/cfg_grid.cpp
@@ -572,7 +572,7 @@ private:
if (!item->isLastRunCfg &&
!AFS::isNullPath(item->cfgItem.logFilePath))
- return getSyncResultLabel(item->cfgItem.logResult) + SPACED_DASH + AFS::getDisplayPath(item->cfgItem.logFilePath);
+ return getSyncResultLabel(item->cfgItem.logResult) + L"\n" + AFS::getDisplayPath(item->cfgItem.logFilePath);
break;
}
return std::wstring();
diff --git a/FreeFileSync/Source/ui/file_grid.cpp b/FreeFileSync/Source/ui/file_grid.cpp
index 38d2518d..01a30d48 100644
--- a/FreeFileSync/Source/ui/file_grid.cpp
+++ b/FreeFileSync/Source/ui/file_grid.cpp
@@ -483,7 +483,7 @@ private:
break;
case ColumnTypeRim::size:
- visitFSObject(*fsObj, [&](const FolderPair& folder) { value = L'<' + _("Folder") + L'>'; },
+ visitFSObject(*fsObj, [&](const FolderPair& folder) { /*value = L'<' + _("Folder") + L'>'; -> redundant!? */ },
[&](const FilePair& file) { value = formatNumber(file.getFileSize<side>()); },
//[&](const FilePair& file) { value = numberTo<std::wstring>(file.getFilePrint<side>()); }, // -> test file id
[&](const SymlinkPair& symlink) { value = L'<' + _("Symlink") + L'>'; });
diff --git a/FreeFileSync/Source/ui/gui_generated.cpp b/FreeFileSync/Source/ui/gui_generated.cpp
index 19160a24..9827af12 100644
--- a/FreeFileSync/Source/ui/gui_generated.cpp
+++ b/FreeFileSync/Source/ui/gui_generated.cpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Oct 26 2018)
+// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -3879,12 +3879,12 @@ SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWind
bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL );
- m_checkBoxAutoClose = new wxCheckBox( this, wxID_ANY, _("Auto-close"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizerStdButtons->Add( m_checkBoxAutoClose, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
-
bSizerStdButtons->Add( 0, 0, 1, wxEXPAND, 5 );
+ m_checkBoxAutoClose = new wxCheckBox( this, wxID_ANY, _("Auto-close"), wxDefaultPosition, wxDefaultSize, 0 );
+ bSizerStdButtons->Add( m_checkBoxAutoClose, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
+
m_buttonClose = new wxButton( this, wxID_OK, _("Close"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
m_buttonClose->SetDefault();
@@ -4672,6 +4672,32 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
ffgSizer11->Add( bSizer2901, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+ m_bitmapAlertPending = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ ffgSizer11->Add( m_bitmapAlertPending, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_staticText17111 = new wxStaticText( m_panel39, wxID_ANY, _("Alert pending:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText17111->Wrap( -1 );
+ m_staticText17111->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
+
+ ffgSizer11->Add( m_staticText17111, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ wxBoxSizer* bSizer29011;
+ bSizer29011 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_bpButtonPlayAlertPending = new wxBitmapButton( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
+ bSizer29011->Add( m_bpButtonPlayAlertPending, 0, wxEXPAND, 5 );
+
+ m_textCtrlSoundPathAlertPending = new wxTextCtrl( m_panel39, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
+ bSizer29011->Add( m_textCtrlSoundPathAlertPending, 1, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_buttonSelectSoundAlertPending = new wxButton( m_panel39, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_buttonSelectSoundAlertPending->SetToolTip( _("Select a folder") );
+
+ bSizer29011->Add( m_buttonSelectSoundAlertPending, 0, wxEXPAND, 5 );
+
+
+ ffgSizer11->Add( bSizer29011, 1, wxEXPAND, 5 );
+
bSizer301->Add( ffgSizer11, 1, wxALL, 5 );
@@ -4819,9 +4845,9 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
// Columns
m_gridCustomCommand->EnableDragColMove( false );
m_gridCustomCommand->EnableDragColSize( true );
- m_gridCustomCommand->SetColLabelSize( -1 );
m_gridCustomCommand->SetColLabelValue( 0, _("Description") );
m_gridCustomCommand->SetColLabelValue( 1, _("Command line") );
+ m_gridCustomCommand->SetColLabelSize( -1 );
m_gridCustomCommand->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
@@ -4886,6 +4912,9 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
m_bpButtonPlaySyncDone->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onPlaySyncDone ), NULL, this );
m_textCtrlSoundPathSyncDone->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( OptionsDlgGenerated::onChangeSoundFilePath ), NULL, this );
m_buttonSelectSoundSyncDone->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onSelectSoundSyncDone ), NULL, this );
+ m_bpButtonPlayAlertPending->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onPlayAlertPending ), NULL, this );
+ m_textCtrlSoundPathAlertPending->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( OptionsDlgGenerated::onChangeSoundFilePath ), NULL, this );
+ m_buttonSelectSoundAlertPending->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onSelectSoundAlertPending ), NULL, this );
m_bpButtonAddRow->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onAddRow ), NULL, this );
m_bpButtonRemoveRow->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onRemoveRow ), NULL, this );
m_buttonDefault->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::onDefault ), NULL, this );
@@ -5635,24 +5664,18 @@ WarnAccessRightsMissingDlgGenerated::WarnAccessRightsMissingDlgGenerated( wxWind
m_staticline36 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer95->Add( m_staticline36, 0, wxEXPAND, 5 );
- wxBoxSizer* bSizer25;
- bSizer25 = new wxBoxSizer( wxVERTICAL );
-
m_checkBoxDontShowAgain = new wxCheckBox( this, wxID_ANY, _("&Don't show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer25->Add( m_checkBoxDontShowAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
+ bSizer95->Add( m_checkBoxDontShowAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL );
m_buttonClose = new wxButton( this, wxID_OK, _("Close"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
m_buttonClose->SetDefault();
- bSizerStdButtons->Add( m_buttonClose, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
-
-
- bSizer25->Add( bSizerStdButtons, 0, wxALIGN_RIGHT, 5 );
+ bSizerStdButtons->Add( m_buttonClose, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
- bSizer95->Add( bSizer25, 0, wxEXPAND, 5 );
+ bSizer95->Add( bSizerStdButtons, 0, wxALIGN_RIGHT, 5 );
bSizer330->Add( bSizer95, 1, wxEXPAND, 5 );
diff --git a/FreeFileSync/Source/ui/gui_generated.h b/FreeFileSync/Source/ui/gui_generated.h
index e06c4489..35a19b5c 100644
--- a/FreeFileSync/Source/ui/gui_generated.h
+++ b/FreeFileSync/Source/ui/gui_generated.h
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Oct 26 2018)
+// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -10,6 +10,8 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
+namespace zen { class BitmapTextButton; }
+
#include "wx+/bitmap_button.h"
#include "folder_history_box.h"
#include "wx+/grid.h"
@@ -210,7 +212,7 @@ protected:
wxStaticBitmap* m_bitmapDeleteRight;
wxStaticText* m_staticTextDeleteRight;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onConfigNew( wxCommandEvent& event ) { event.Skip(); }
virtual void onConfigLoad( wxCommandEvent& event ) { event.Skip(); }
@@ -312,6 +314,7 @@ public:
wxBitmapButton* m_bpButtonSelectAltFolderRight;
FolderPairPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 698, 67 ), long style = 0, const wxString& name = wxEmptyString );
+
~FolderPairPanelGenerated();
};
@@ -488,7 +491,7 @@ protected:
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onListBoxKeyEvent( wxKeyEvent& event ) { event.Skip(); }
virtual void onSelectFolderPair( wxCommandEvent& event ) { event.Skip(); }
@@ -546,6 +549,7 @@ public:
wxChoice* m_choicePostSyncCondition;
ConfigDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Synchronization Settings"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER );
+
~ConfigDlgGenerated();
};
@@ -638,7 +642,7 @@ protected:
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onConnectionGdrive( wxCommandEvent& event ) { event.Skip(); }
virtual void onConnectionSftp( wxCommandEvent& event ) { event.Skip(); }
@@ -660,6 +664,7 @@ protected:
public:
CloudSetupDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Access Online Storage"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+
~CloudSetupDlgGenerated();
};
@@ -680,7 +685,7 @@ protected:
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onExpandNode( wxTreeEvent& event ) { event.Skip(); }
virtual void onOkay( wxCommandEvent& event ) { event.Skip(); }
@@ -690,6 +695,7 @@ protected:
public:
AbstractFolderPickerGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select a folder"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER );
+
~AbstractFolderPickerGenerated();
};
@@ -733,7 +739,7 @@ protected:
wxButton* m_buttonStartSync;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onStartSync( wxCommandEvent& event ) { event.Skip(); }
virtual void onCancel( wxCommandEvent& event ) { event.Skip(); }
@@ -742,6 +748,7 @@ protected:
public:
SyncConfirmationDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+
~SyncConfirmationDlgGenerated();
};
@@ -784,6 +791,7 @@ public:
wxStaticBitmap* m_bitmapIgnoreErrors;
CompareProgressDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxBORDER_RAISED, const wxString& name = wxEmptyString );
+
~CompareProgressDlgGenerated();
};
@@ -846,6 +854,7 @@ public:
wxButton* m_buttonStop;
SyncProgressPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
+
~SyncProgressPanelGenerated();
};
@@ -863,7 +872,7 @@ protected:
zen::ToggleButton* m_bpButtonInfo;
wxStaticLine* m_staticline13;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onErrors( wxCommandEvent& event ) { event.Skip(); }
virtual void onWarnings( wxCommandEvent& event ) { event.Skip(); }
virtual void onInfo( wxCommandEvent& event ) { event.Skip(); }
@@ -873,6 +882,7 @@ public:
zen::Grid* m_gridMessages;
LogPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
+
~LogPanelGenerated();
};
@@ -908,7 +918,7 @@ protected:
wxButton* m_buttonSaveAs;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onToggleRunMinimized( wxCommandEvent& event ) { event.Skip(); }
virtual void onToggleIgnoreErrors( wxCommandEvent& event ) { event.Skip(); }
@@ -921,6 +931,7 @@ public:
wxChoice* m_choicePostSyncAction;
BatchDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Save as a Batch Job"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+
~BatchDlgGenerated();
};
@@ -945,7 +956,7 @@ protected:
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onUseRecycler( wxCommandEvent& event ) { event.Skip(); }
virtual void onOkay( wxCommandEvent& event ) { event.Skip(); }
@@ -955,6 +966,7 @@ protected:
public:
DeleteDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Delete Items"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER );
+
~DeleteDlgGenerated();
};
@@ -981,7 +993,7 @@ protected:
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onOkay( wxCommandEvent& event ) { event.Skip(); }
virtual void onCancel( wxCommandEvent& event ) { event.Skip(); }
@@ -992,6 +1004,7 @@ public:
wxBitmapButton* m_bpButtonSelectAltTargetFolder;
CopyToDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Copy Items"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER );
+
~CopyToDlgGenerated();
};
@@ -1052,6 +1065,11 @@ protected:
wxBitmapButton* m_bpButtonPlaySyncDone;
wxTextCtrl* m_textCtrlSoundPathSyncDone;
wxButton* m_buttonSelectSoundSyncDone;
+ wxStaticBitmap* m_bitmapAlertPending;
+ wxStaticText* m_staticText17111;
+ wxBitmapButton* m_bpButtonPlayAlertPending;
+ wxTextCtrl* m_textCtrlSoundPathAlertPending;
+ wxButton* m_buttonSelectSoundAlertPending;
wxStaticLine* m_staticline3611;
wxStaticBitmap* m_bitmapConsole;
wxStaticText* m_staticText85;
@@ -1073,7 +1091,7 @@ protected:
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onRestoreDialogs( wxCommandEvent& event ) { event.Skip(); }
virtual void onShowLogFolder( wxHyperlinkEvent& event ) { event.Skip(); }
@@ -1083,6 +1101,8 @@ protected:
virtual void onSelectSoundCompareDone( wxCommandEvent& event ) { event.Skip(); }
virtual void onPlaySyncDone( wxCommandEvent& event ) { event.Skip(); }
virtual void onSelectSoundSyncDone( wxCommandEvent& event ) { event.Skip(); }
+ virtual void onPlayAlertPending( wxCommandEvent& event ) { event.Skip(); }
+ virtual void onSelectSoundAlertPending( wxCommandEvent& event ) { event.Skip(); }
virtual void onAddRow( wxCommandEvent& event ) { event.Skip(); }
virtual void onRemoveRow( wxCommandEvent& event ) { event.Skip(); }
virtual void onDefault( wxCommandEvent& event ) { event.Skip(); }
@@ -1093,6 +1113,7 @@ protected:
public:
OptionsDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+
~OptionsDlgGenerated();
};
@@ -1111,6 +1132,7 @@ public:
wxStaticText* m_staticTextMain;
TooltipDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+
~TooltipDlgGenerated();
};
@@ -1131,7 +1153,7 @@ protected:
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onChangeSelectionFrom( wxCalendarEvent& event ) { event.Skip(); }
virtual void onChangeSelectionTo( wxCalendarEvent& event ) { event.Skip(); }
@@ -1142,6 +1164,7 @@ protected:
public:
SelectTimespanDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Select Time Span"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+
~SelectTimespanDlgGenerated();
};
@@ -1190,7 +1213,7 @@ protected:
wxBoxSizer* bSizerStdButtons;
wxButton* m_buttonClose;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onDonate( wxCommandEvent& event ) { event.Skip(); }
virtual void onShowDonationDetails( wxCommandEvent& event ) { event.Skip(); }
@@ -1204,6 +1227,7 @@ protected:
public:
AboutDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("About"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+
~AboutDlgGenerated();
};
@@ -1224,13 +1248,14 @@ protected:
wxBoxSizer* bSizerStdButtons;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onCancel( wxCommandEvent& event ) { event.Skip(); }
public:
DownloadProgressDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0 );
+
~DownloadProgressDlgGenerated();
};
@@ -1268,7 +1293,7 @@ protected:
wxBoxSizer* bSizerStdButtons;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onActivateOnline( wxCommandEvent& event ) { event.Skip(); }
virtual void onCopyUrl( wxCommandEvent& event ) { event.Skip(); }
@@ -1280,6 +1305,7 @@ protected:
public:
ActivationDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("dummy"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+
~ActivationDlgGenerated();
};
@@ -1300,7 +1326,7 @@ protected:
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onOkay( wxCommandEvent& event ) { event.Skip(); }
virtual void onCancel( wxCommandEvent& event ) { event.Skip(); }
@@ -1309,6 +1335,7 @@ protected:
public:
CfgHighlightDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Highlight Configurations"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+
~CfgHighlightDlgGenerated();
};
@@ -1339,7 +1366,7 @@ protected:
wxBoxSizer* bSizerStdButtons;
wxButton* m_buttonClose;
- // Virtual event handlers, overide them in your derived class
+ // Virtual event handlers, override them in your derived class
virtual void onClose( wxCloseEvent& event ) { event.Skip(); }
virtual void onShowAppBundle( wxCommandEvent& event ) { event.Skip(); }
virtual void onOpenSecuritySettings( wxCommandEvent& event ) { event.Skip(); }
@@ -1350,6 +1377,7 @@ protected:
public:
WarnAccessRightsMissingDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Grant Full Disk Access"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+
~WarnAccessRightsMissingDlgGenerated();
};
diff --git a/FreeFileSync/Source/ui/gui_status_handler.cpp b/FreeFileSync/Source/ui/gui_status_handler.cpp
index 861ea810..71f201f1 100644
--- a/FreeFileSync/Source/ui/gui_status_handler.cpp
+++ b/FreeFileSync/Source/ui/gui_status_handler.cpp
@@ -29,11 +29,13 @@ StatusHandlerTemporaryPanel::StatusHandlerTemporaryPanel(MainDialog& dlg,
const std::chrono::system_clock::time_point& startTime,
bool ignoreErrors,
size_t autoRetryCount,
- std::chrono::seconds autoRetryDelay) :
+ std::chrono::seconds autoRetryDelay,
+ const Zstring& soundFileAlertPending) :
mainDlg_(dlg),
ignoreErrors_(ignoreErrors),
autoRetryCount_(autoRetryCount),
autoRetryDelay_(autoRetryDelay),
+ soundFileAlertPending_(soundFileAlertPending),
startTime_(startTime)
{
mainDlg_.compareStatus_->init(*this, ignoreErrors_, autoRetryCount_); //clear old values before showing panel
@@ -210,6 +212,7 @@ void StatusHandlerTemporaryPanel::reportWarning(const std::wstring& msg, bool& w
bool dontWarnAgain = false;
switch (showConfirmationDialog(&mainDlg_, DialogInfoType::warning,
PopupDialogCfg().setDetailInstructions(msg).
+ remindWhenPending(soundFileAlertPending_).
setCheckBox(dontWarnAgain, _("&Don't show this warning again")),
_("&Ignore")))
{
@@ -249,7 +252,8 @@ ProcessCallback::Response StatusHandlerTemporaryPanel::reportError(const ErrorIn
forceUiUpdateNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(&mainDlg_, DialogInfoType::error,
- PopupDialogCfg().setDetailInstructions(errorInfo.msg),
+ PopupDialogCfg().setDetailInstructions(errorInfo.msg).
+ remindWhenPending(soundFileAlertPending_),
_("&Ignore"), _("Ignore &all"), _("&Retry")))
{
case ConfirmationButton3::accept: //ignore
@@ -289,8 +293,8 @@ void StatusHandlerTemporaryPanel::reportFatalError(const std::wstring& msg)
forceUiUpdateNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(&mainDlg_, DialogInfoType::error,
- PopupDialogCfg().setTitle(_("Error")).
- setDetailInstructions(msg),
+ PopupDialogCfg().setDetailInstructions(msg).
+ remindWhenPending(soundFileAlertPending_),
_("&Ignore"), _("Ignore &all")))
{
case ConfirmationButton2::accept: //ignore
@@ -345,6 +349,7 @@ StatusHandlerFloatingDialog::StatusHandlerFloatingDialog(wxFrame* parentDlg,
size_t autoRetryCount,
std::chrono::seconds autoRetryDelay,
const Zstring& soundFileSyncComplete,
+ const Zstring& soundFileAlertPending,
const wxSize& progressDlgSize, bool dlgMaximize,
bool autoCloseDialog) :
jobNames_(jobNames),
@@ -352,6 +357,7 @@ StatusHandlerFloatingDialog::StatusHandlerFloatingDialog(wxFrame* parentDlg,
autoRetryCount_(autoRetryCount),
autoRetryDelay_(autoRetryDelay),
soundFileSyncComplete_(soundFileSyncComplete),
+ soundFileAlertPending_(soundFileAlertPending),
progressDlg_(SyncProgressDialog::create(progressDlgSize, dlgMaximize, [this] { userRequestAbort(); }, *this, parentDlg, true /*showProgress*/, autoCloseDialog,
jobNames, startTime, ignoreErrors, autoRetryCount, PostSyncAction2::none)) {}
@@ -497,7 +503,7 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(c
if (!autoClose) //only play when showing results dialog
if (!soundFileSyncComplete_.empty())
{
- //wxWidgets shows modal error dialog by default => NO!
+ //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
@@ -570,6 +576,7 @@ void StatusHandlerFloatingDialog::reportWarning(const std::wstring& msg, bool& w
bool dontWarnAgain = false;
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::warning,
PopupDialogCfg().setDetailInstructions(msg).
+ remindWhenPending(soundFileAlertPending_).
setCheckBox(dontWarnAgain, _("&Don't show this warning again")),
_("&Ignore")))
{
@@ -609,7 +616,8 @@ ProcessCallback::Response StatusHandlerFloatingDialog::reportError(const ErrorIn
forceUiUpdateNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::error,
- PopupDialogCfg().setDetailInstructions(errorInfo.msg),
+ PopupDialogCfg().setDetailInstructions(errorInfo.msg).
+ remindWhenPending(soundFileAlertPending_),
_("&Ignore"), _("Ignore &all"), _("&Retry")))
{
case ConfirmationButton3::accept: //ignore
@@ -649,8 +657,8 @@ void StatusHandlerFloatingDialog::reportFatalError(const std::wstring& msg)
forceUiUpdateNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::error,
- PopupDialogCfg().setTitle(_("Error")).
- setDetailInstructions(msg),
+ PopupDialogCfg().setDetailInstructions(msg).
+ remindWhenPending(soundFileAlertPending_),
_("&Ignore"), _("Ignore &all")))
{
case ConfirmationButton2::accept: //ignore
diff --git a/FreeFileSync/Source/ui/gui_status_handler.h b/FreeFileSync/Source/ui/gui_status_handler.h
index 8f74e77d..3fe20e97 100644
--- a/FreeFileSync/Source/ui/gui_status_handler.h
+++ b/FreeFileSync/Source/ui/gui_status_handler.h
@@ -22,7 +22,12 @@ namespace fff
class StatusHandlerTemporaryPanel : private wxEvtHandler, public StatusHandler
{
public:
- StatusHandlerTemporaryPanel(MainDialog& dlg, const std::chrono::system_clock::time_point& startTime, bool ignoreErrors, size_t autoRetryCount, std::chrono::seconds autoRetryDelay);
+ StatusHandlerTemporaryPanel(MainDialog& dlg,
+ const std::chrono::system_clock::time_point& startTime,
+ bool ignoreErrors,
+ size_t autoRetryCount,
+ std::chrono::seconds autoRetryDelay,
+ const Zstring& soundFileAlertPending);
~StatusHandlerTemporaryPanel();
void initNewPhase (int itemsTotal, int64_t bytesTotal, ProcessPhase phaseID) override; //
@@ -50,6 +55,8 @@ private:
const bool ignoreErrors_;
const size_t autoRetryCount_;
const std::chrono::seconds autoRetryDelay_;
+ const Zstring soundFileAlertPending_;
+
const std::chrono::system_clock::time_point startTime_;
const std::chrono::steady_clock::time_point startTimeSteady_ = std::chrono::steady_clock::now();
};
@@ -66,6 +73,7 @@ public:
size_t autoRetryCount,
std::chrono::seconds autoRetryDelay,
const Zstring& soundFileSyncComplete,
+ const Zstring& soundFileAlertPending,
const wxSize& progressDlgSize, bool dlgMaximize,
bool autoCloseDialog); //noexcept!
~StatusHandlerFloatingDialog();
@@ -105,6 +113,7 @@ private:
const size_t autoRetryCount_;
const std::chrono::seconds autoRetryDelay_;
const Zstring soundFileSyncComplete_;
+ const Zstring soundFileAlertPending_;
SyncProgressDialog* progressDlg_; //managed to have the same lifetime as this handler!
zen::ErrorLog errorLog_;
diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp
index 550a8557..ffbb35c5 100644
--- a/FreeFileSync/Source/ui/main_dlg.cpp
+++ b/FreeFileSync/Source/ui/main_dlg.cpp
@@ -7,6 +7,7 @@
#include "main_dlg.h"
#include <zen/format_unit.h>
#include <zen/file_access.h>
+#include <zen/file_path.h>
#include <zen/file_io.h>
#include <zen/thread.h>
#include <zen/process_exec.h>
@@ -1422,7 +1423,8 @@ void MainDialog::copyToAlternateFolder(const std::vector<FileSystemObject*>& sel
StatusHandlerTemporaryPanel statusHandler(*this, std::chrono::system_clock::now() /*startTime*/,
false /*ignoreErrors*/,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay); //handle status display and error messages
+ guiCfg.mainCfg.autoRetryDelay,
+ globalCfg_.soundFileAlertPending);
try
{
fff::copyToAlternateFolder(selectionL, selectionR,
@@ -1468,7 +1470,8 @@ void MainDialog::deleteSelectedFiles(const std::vector<FileSystemObject*>& selec
StatusHandlerTemporaryPanel statusHandler(*this, std::chrono::system_clock::now() /*startTime*/,
false /*ignoreErrors*/,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay); //handle status display and error messages
+ guiCfg.mainCfg.autoRetryDelay,
+ globalCfg_.soundFileAlertPending);
try
{
deleteFromGridAndHD(selectionL, selectionR,
@@ -1710,7 +1713,8 @@ void MainDialog::openExternalApplication(const Zstring& commandLinePhrase, bool
StatusHandlerTemporaryPanel statusHandler(*this, std::chrono::system_clock::now() /*startTime*/,
false /*ignoreErrors*/,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay); //handle status display and error messages
+ guiCfg.mainCfg.autoRetryDelay,
+ globalCfg_.soundFileAlertPending);
try
{
tempFileBuf_.createTempFiles(nonNativeFiles, statusHandler); //throw AbortProcess
@@ -2996,6 +3000,10 @@ void MainDialog::updateUnsavedCfgStatus()
}
SetTitle(title);
+
+ //macOS-only:
+ OSXSetModified(haveUnsavedCfg);
+ SetRepresentedFilename(utfTo<wxString>(activeCfgFilePath));
}
@@ -4065,7 +4073,8 @@ void MainDialog::onCompare(wxCommandEvent& event)
StatusHandlerTemporaryPanel statusHandler(*this, startTime,
guiCfg.mainCfg.ignoreErrors,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay);
+ guiCfg.mainCfg.autoRetryDelay,
+ globalCfg_.soundFileAlertPending);
try
{
//GUI mode: place directory locks on directories isolated(!) during both comparison and synchronization
@@ -4105,7 +4114,7 @@ void MainDialog::onCompare(wxCommandEvent& event)
//play (optional) sound notification
if (!globalCfg_.soundFileCompareFinished.empty())
{
- //wxWidgets shows modal error dialog by default => NO!
+ //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
@@ -4113,7 +4122,7 @@ void MainDialog::onCompare(wxCommandEvent& event)
}
if (!IsActive())
- RequestUserAttention();
+ RequestUserAttention(); //this == toplevel win, so we also get the taskbar flash!
//remember folder history (except when cancelled by user)
for (const FolderPairCfg& fpCfg : fpCfgList)
@@ -4306,6 +4315,7 @@ void MainDialog::onStartSync(wxCommandEvent& event)
guiCfg.mainCfg.autoRetryCount,
guiCfg.mainCfg.autoRetryDelay,
globalCfg_.soundFileSyncFinished,
+ globalCfg_.soundFileAlertPending,
globalCfg_.dpiLayouts[getDpiScalePercent()].progressDlg.dlgSize,
globalCfg_.dpiLayouts[getDpiScalePercent()].progressDlg.isMaximized,
globalCfg_.progressDlgAutoClose);
@@ -4518,7 +4528,8 @@ void MainDialog::startSyncForSelecction(const std::vector<FileSystemObject*>& se
StatusHandlerTemporaryPanel statusHandler(*this, syncStartTime,
guiCfg.mainCfg.ignoreErrors,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay); //handle status display and error messages
+ guiCfg.mainCfg.autoRetryDelay,
+ globalCfg_.soundFileAlertPending);
try
{
//let's report here rather than before comparison (user might have changed global settings in the meantime!)
@@ -4732,6 +4743,7 @@ void MainDialog::onGridLabelLeftClickC(GridLabelClickEvent& event)
}
}
+
void MainDialog::onSwapSides(wxCommandEvent& event)
{
if (globalCfg_.confirmDlgs.confirmSwapSides)
@@ -4800,7 +4812,8 @@ void MainDialog::onSwapSides(wxCommandEvent& event)
StatusHandlerTemporaryPanel statusHandler(*this, std::chrono::system_clock::now() /*startTime*/,
false /*ignoreErrors*/,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay); //handle status display and error messages
+ guiCfg.mainCfg.autoRetryDelay,
+ Zstr("") /*soundFileAlertPending*/);
try
{
statusHandler.initNewPhase(-1, -1, ProcessPhase::none);
@@ -5048,7 +5061,8 @@ void MainDialog::applySyncDirections()
StatusHandlerTemporaryPanel statusHandler(*this, std::chrono::system_clock::now() /*startTime*/,
false /*ignoreErrors*/,
guiCfg.mainCfg.autoRetryCount,
- guiCfg.mainCfg.autoRetryDelay); //handle status display and error messages
+ guiCfg.mainCfg.autoRetryDelay,
+ Zstr("") /*soundFileAlertPending*/);
try
{
statusHandler.initNewPhase(-1, -1, ProcessPhase::none);
diff --git a/FreeFileSync/Source/ui/small_dlgs.cpp b/FreeFileSync/Source/ui/small_dlgs.cpp
index 8ce5a325..52ab1c0f 100644
--- a/FreeFileSync/Source/ui/small_dlgs.cpp
+++ b/FreeFileSync/Source/ui/small_dlgs.cpp
@@ -7,6 +7,7 @@
#include "small_dlgs.h"
#include <variant>
#include <zen/time.h>
+#include <zen/file_path.h>
#include <zen/format_unit.h>
#include <zen/build_info.h>
#include <zen/stl_tools.h>
@@ -1137,14 +1138,16 @@ private:
void onShowLogFolder (wxHyperlinkEvent& event) override;
void onToggleLogfilesLimit(wxCommandEvent& event) override { updateGui(); }
- void onSelectSoundCompareDone(wxCommandEvent& event) override { selectSound(*m_textCtrlSoundPathCompareDone); }
- void onSelectSoundSyncDone (wxCommandEvent& event) override { selectSound(*m_textCtrlSoundPathSyncDone); }
+ void onSelectSoundCompareDone (wxCommandEvent& event) override { selectSound(*m_textCtrlSoundPathCompareDone); }
+ void onSelectSoundSyncDone (wxCommandEvent& event) override { selectSound(*m_textCtrlSoundPathSyncDone); }
+ void onSelectSoundAlertPending(wxCommandEvent& event) override { selectSound(*m_textCtrlSoundPathAlertPending); }
void selectSound(wxTextCtrl& txtCtrl);
void onChangeSoundFilePath(wxCommandEvent& event) override { updateGui(); }
- void onPlayCompareDone(wxCommandEvent& event) override { playSoundWithDiagnostics(trimCpy(m_textCtrlSoundPathCompareDone->GetValue())); }
- void onPlaySyncDone (wxCommandEvent& event) override { playSoundWithDiagnostics(trimCpy(m_textCtrlSoundPathSyncDone ->GetValue())); }
+ void onPlayCompareDone (wxCommandEvent& event) override { playSoundWithDiagnostics(trimCpy(m_textCtrlSoundPathCompareDone ->GetValue())); }
+ void onPlaySyncDone (wxCommandEvent& event) override { playSoundWithDiagnostics(trimCpy(m_textCtrlSoundPathSyncDone ->GetValue())); }
+ void onPlayAlertPending(wxCommandEvent& event) override { playSoundWithDiagnostics(trimCpy(m_textCtrlSoundPathAlertPending->GetValue())); }
void playSoundWithDiagnostics(const wxString& filePath);
void onResize(wxSizeEvent& event);
@@ -1193,8 +1196,10 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
m_bitmapConsole ->SetBitmap (loadImage("command_line", fastFromDIP(20)));
m_bitmapCompareDone ->SetBitmap (loadImage("compare_sicon"));
m_bitmapSyncDone ->SetBitmap (loadImage("start_sync_sicon"));
+ m_bitmapAlertPending ->SetBitmap (loadImage("msg_error", loadImage("compare_sicon").GetSize().x));
m_bpButtonPlayCompareDone ->SetBitmapLabel(loadImage("play_sound"));
m_bpButtonPlaySyncDone ->SetBitmapLabel(loadImage("play_sound"));
+ m_bpButtonPlayAlertPending->SetBitmapLabel(loadImage("play_sound"));
m_bpButtonAddRow ->SetBitmapLabel(loadImage("item_add"));
m_bpButtonRemoveRow ->SetBitmapLabel(loadImage("item_remove"));
@@ -1222,8 +1227,9 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
break;
}
- m_textCtrlSoundPathCompareDone->ChangeValue(utfTo<wxString>(globalSettings.soundFileCompareFinished));
- m_textCtrlSoundPathSyncDone ->ChangeValue(utfTo<wxString>(globalSettings.soundFileSyncFinished));
+ m_textCtrlSoundPathCompareDone ->ChangeValue(utfTo<wxString>(globalSettings.soundFileCompareFinished));
+ m_textCtrlSoundPathSyncDone ->ChangeValue(utfTo<wxString>(globalSettings.soundFileSyncFinished));
+ m_textCtrlSoundPathAlertPending->ChangeValue(utfTo<wxString>(globalSettings.soundFileAlertPending));
//--------------------------------------------------------------------------------
bSizerLockedFiles->Show(false);
@@ -1284,8 +1290,9 @@ void OptionsDlg::updateGui()
m_spinCtrlLogFilesMaxAge->Enable(m_checkBoxLogFilesMaxAge->GetValue());
- m_bpButtonPlayCompareDone->Enable(!trimCpy(m_textCtrlSoundPathCompareDone->GetValue()).empty());
- m_bpButtonPlaySyncDone ->Enable(!trimCpy(m_textCtrlSoundPathSyncDone ->GetValue()).empty());
+ m_bpButtonPlayCompareDone ->Enable(!trimCpy(m_textCtrlSoundPathCompareDone ->GetValue()).empty());
+ m_bpButtonPlaySyncDone ->Enable(!trimCpy(m_textCtrlSoundPathSyncDone ->GetValue()).empty());
+ m_bpButtonPlayAlertPending->Enable(!trimCpy(m_textCtrlSoundPathAlertPending->GetValue()).empty());
}
@@ -1349,8 +1356,9 @@ void OptionsDlg::onDefault(wxCommandEvent& event)
break;
}
- m_textCtrlSoundPathCompareDone->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileCompareFinished));
- m_textCtrlSoundPathSyncDone ->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileSyncFinished));
+ m_textCtrlSoundPathCompareDone ->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileCompareFinished));
+ m_textCtrlSoundPathSyncDone ->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileSyncFinished));
+ m_textCtrlSoundPathAlertPending->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileAlertPending));
setExtApp(defaultCfg_.externalApps);
@@ -1368,8 +1376,9 @@ void OptionsDlg::onOkay(wxCommandEvent& event)
globalCfgOut_.logfilesMaxAgeDays = m_checkBoxLogFilesMaxAge->GetValue() ? m_spinCtrlLogFilesMaxAge->GetValue() : -1;
globalCfgOut_.logFormat = m_radioBtnLogHtml->GetValue() ? LogFileFormat::html : LogFileFormat::text;
- globalCfgOut_.soundFileCompareFinished = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathCompareDone->GetValue()));
- globalCfgOut_.soundFileSyncFinished = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathSyncDone ->GetValue()));
+ globalCfgOut_.soundFileCompareFinished = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathCompareDone ->GetValue()));
+ globalCfgOut_.soundFileSyncFinished = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathSyncDone ->GetValue()));
+ globalCfgOut_.soundFileAlertPending = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathAlertPending->GetValue()));
globalCfgOut_.externalApps = getExtApp();
diff --git a/FreeFileSync/Source/ui/tree_grid.cpp b/FreeFileSync/Source/ui/tree_grid.cpp
index 76d4c95b..13a96295 100644
--- a/FreeFileSync/Source/ui/tree_grid.cpp
+++ b/FreeFileSync/Source/ui/tree_grid.cpp
@@ -730,7 +730,7 @@ private:
return dirRight;
else if (dirRight.empty())
return dirLeft;
- return dirLeft + L' ' + EN_DASH + L'\n' + dirRight;
+ return dirLeft + /*L' ' + EM_DASH + */ L'\n' + dirRight;
}
break;
diff --git a/FreeFileSync/Source/version/version.h b/FreeFileSync/Source/version/version.h
index 6c2e91e9..4a4de811 100644
--- a/FreeFileSync/Source/version/version.h
+++ b/FreeFileSync/Source/version/version.h
@@ -3,7 +3,7 @@
namespace fff
{
-const char ffsVersion[] = "11.14"; //internal linkage!
+const char ffsVersion[] = "11.15"; //internal linkage!
const char FFS_VERSION_SEPARATOR = '.';
}
diff --git a/License.txt b/License.txt
index db3fc4ce..7c78f826 100644
--- a/License.txt
+++ b/License.txt
@@ -1,8 +1,10 @@
A. GNU GENERAL PUBLIC LICENSE
-B. OpenSSL and SSLeay License
-C. cURL License
+B. OpenSSL License
+C. curl License
D. libssh2 License
+====================================================================
+
A. GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
@@ -623,127 +625,192 @@ an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
-
-B. OpenSSL and SSLeay License
-
-OpenSSL License
-
====================================================================
-Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
-3. All advertising materials mentioning features or use of this
- software must display the following acknowledgment:
- "This product includes software developed by the OpenSSL Project
- for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
-
-4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- endorse or promote products derived from this software without
- prior written permission. For written permission, please contact
- openssl-core@openssl.org.
-
-5. Products derived from this software may not be called "OpenSSL"
- nor may "OpenSSL" appear in their names without prior written
- permission of the OpenSSL Project.
-
-6. Redistributions of any form whatsoever must retain the following
- acknowledgment:
- "This product includes software developed by the OpenSSL Project
- for use in the OpenSSL Toolkit (http://www.openssl.org/)"
-
-THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
-EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
-ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-OF THE POSSIBILITY OF SUCH DAMAGE.
-====================================================================
-
-This product includes cryptographic software written by Eric Young
-(eay@cryptsoft.com). This product includes software written by Tim
-Hudson (tjh@cryptsoft.com).
-Original SSLeay License
+B. OpenSSL License
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
-Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
-All rights reserved.
+====================================================================
-This package is an SSL implementation written
-by Eric Young (eay@cryptsoft.com).
-The implementation was written so as to conform with Netscapes SSL.
-
-This library is free for commercial and non-commercial use as long as
-the following conditions are aheared to. The following conditions
-apply to all code found in this distribution, be it the RC4, RSA,
-lhash, DES, etc., code; not just the SSL code. The SSL documentation
-included with this distribution is covered by the same copyright terms
-except that the holder is Tim Hudson (tjh@cryptsoft.com).
-
-Copyright remains Eric Young's, and as such any Copyright notices in
-the code are not to be removed.
-If this package is used in a product, Eric Young should be given attribution
-as the author of the parts of the library used.
-This can be in the form of a textual message at program startup or
-in documentation (online or textual) provided with the package.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- "This product includes cryptographic software written by
- Eric Young (eay@cryptsoft.com)"
- The word 'cryptographic' can be left out if the rouines from the library
- being used are not cryptographic related :-).
-4. If you include any Windows specific code (or a derivative thereof) from
- the apps directory (application code) you must include an acknowledgement:
- "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
-
-THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
-The licence and distribution terms for any publically available version or
-derivative of this code cannot be changed. i.e. this code cannot simply be
-copied and put under another distribution licence
-[including the GNU Public Licence.]
-
-
-C. cURL License
+C. curl License
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2018, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2021, Daniel Stenberg, daniel@haxx.se, and many
contributors, see the THANKS file.
All rights reserved.
@@ -764,6 +831,7 @@ Except as contained in this notice, the name of a copyright holder shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization of the copyright holder.
+====================================================================
D. libssh2 License
@@ -771,8 +839,10 @@ Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
Copyright (c) 2005,2006 Mikhail Gusarov <dottedmag@dottedmag.net>
Copyright (c) 2006-2007 The Written Word, Inc.
Copyright (c) 2007 Eli Fant <elifantu@mail.ru>
-Copyright (c) 2009-2014 Daniel Stenberg
+Copyright (c) 2009-2021 Daniel Stenberg
Copyright (C) 2008, 2009 Simon Josefsson
+Copyright (c) 2000 Markus Friedl
+Copyright (c) 2015 Microsoft Corp.
All rights reserved.
Redistribution and use in source and binary forms,
diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp
index 88ed590b..3d4077c3 100644
--- a/wx+/popup_dlg.cpp
+++ b/wx+/popup_dlg.cpp
@@ -6,14 +6,17 @@
#include "popup_dlg.h"
#include <zen/basic_math.h>
+#include <zen/utf.h>
#include <wx/app.h>
#include <wx/display.h>
+#include <wx/sound.h>
#include "no_flicker.h"
#include "font_size.h"
#include "image_resources.h"
#include "popup_dlg_generated.h"
#include "std_button_layout.h"
#include "taskbar.h"
+ #include "window_tools.h"
using namespace zen;
@@ -194,6 +197,27 @@ public:
Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& event) { onLocalKeyEvent(event); }); //dialog-specific local key events
+ //play sound reminder when waiting for user confirmation
+ if (!cfg.soundFileAlertPending.empty())
+ {
+ timer_.Bind(wxEVT_TIMER, [this, parent, alertSoundPath = cfg.soundFileAlertPending](wxTimerEvent& event)
+ {
+ //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+ wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
+ ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
+
+ wxSound::Play(utfTo<wxString>(alertSoundPath), wxSOUND_ASYNC);
+
+ RequestUserAttention(wxUSER_ATTENTION_INFO);
+ /* wxUSER_ATTENTION_INFO: flashes window 3 times, unconditionally
+ wxUSER_ATTENTION_ERROR: flashes without limit, but *only* if not in foreground (FLASHW_TIMERNOFG) :( */
+ if (parent)
+ if (auto tlw = dynamic_cast<wxTopLevelWindow*>(&getRootWindow(*parent)))
+ tlw->RequestUserAttention(wxUSER_ATTENTION_INFO); //top-level window needed for the taskbar flash!
+ });
+ timer_.Start(60'000 /*unit: [ms]*/);
+ }
+
//------------------------------------------------------------------------------
StdButtons stdBtns;
stdBtns.setAffirmative(m_buttonAccept);
@@ -312,6 +336,7 @@ private:
bool* checkBoxValue_;
const ConfirmationButton3 buttonToDisableWhenChecked_;
std::unique_ptr<Taskbar> taskbar_;
+ wxTimer timer_;
};
//########################################################################################
diff --git a/wx+/popup_dlg.h b/wx+/popup_dlg.h
index bb7ba51b..11e96e3b 100644
--- a/wx+/popup_dlg.h
+++ b/wx+/popup_dlg.h
@@ -8,6 +8,7 @@
#define POPUP_DLG_H_820780154723456
#include <set>
+#include <zen/zstring.h>
#include <wx/window.h>
#include <wx/bitmap.h>
#include <wx/string.h>
@@ -68,6 +69,7 @@ struct PopupDialogCfg
PopupDialogCfg& setMainInstructions (const wxString& label) { textMain = label; return *this; } //set at least one of these!
PopupDialogCfg& setDetailInstructions(const wxString& label) { textDetail = label; return *this; } //
PopupDialogCfg& disableButton(ConfirmationButton3 button) { disabledButtons.insert(button); return *this; }
+ PopupDialogCfg& remindWhenPending(const Zstring& soundFilePath) { soundFileAlertPending = soundFilePath; return *this; }
PopupDialogCfg& setCheckBox(bool& value, const wxString& label, ConfirmationButton3 disableWhenChecked = ConfirmationButton3::cancel)
{
checkBoxValue = &value;
@@ -84,6 +86,7 @@ private:
wxString textMain;
wxString textDetail;
std::set<ConfirmationButton3> disabledButtons;
+ Zstring soundFileAlertPending;
bool* checkBoxValue = nullptr; //in/out
wxString checkBoxLabel;
ConfirmationButton3 buttonToDisableWhenChecked = ConfirmationButton3::cancel;
diff --git a/wx+/std_button_layout.h b/wx+/std_button_layout.h
index 25745132..e84b0c78 100644
--- a/wx+/std_button_layout.h
+++ b/wx+/std_button_layout.h
@@ -47,6 +47,11 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons)
{
assert(sizer.GetOrientation() == wxHORIZONTAL);
+ //GNOME Human Interface Guidelines: https://developer.gnome.org/hig-book/3.2/hig-book.html#alert-spacing
+ const int spaceH = fastFromDIP( 6); //OK
+ const int spaceRimH = fastFromDIP(12); //OK
+ const int spaceRimV = fastFromDIP(12); //OK
+
StdButtons buttonsTmp = buttons;
auto detach = [&](wxButton*& btn)
@@ -54,15 +59,11 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons)
if (btn)
{
assert(btn->GetContainingSizer() == &sizer);
- if (btn->IsShown())
- {
- bool rv = sizer.Detach(btn);
- assert(rv);
- if (!rv)
- btn = nullptr;
- }
- else
- btn = nullptr;
+ if (btn->IsShown() && sizer.Detach(btn))
+ return;
+
+ assert(false); //why is it hidden!?
+ btn = nullptr;
}
};
@@ -71,10 +72,30 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons)
detach(buttonsTmp.btnNo);
detach(buttonsTmp.btnCancel);
- //GNOME Human Interface Guidelines: https://developer.gnome.org/hig-book/3.2/hig-book.html#alert-spacing
- const int spaceH = fastFromDIP( 6); //OK
- const int spaceRimH = fastFromDIP(12); //OK
- const int spaceRimV = fastFromDIP(12); //OK
+
+ //"All your fixed-size spacers are belong to us!" => have a clean slate: consider repeated setStandardButtonLayout() calls
+ for (size_t pos = sizer.GetItemCount(); pos-- > 0;)
+ if (wxSizerItem& item = *sizer.GetItem(pos);
+ item.IsSpacer() && item.GetProportion() == 0 && item.GetSize().y == 0)
+ {
+ [[maybe_unused]] bool rv = sizer.Detach(pos);
+ assert(rv);
+ }
+
+ //set border on left considering existing items
+ if (!sizer.IsEmpty()) //for yet another retarded reason wxWidgets will have wxSizer::GetItem(0) cause an assert rather than just return nullptr as documented
+ if (wxSizerItem& item = *sizer.GetItem(static_cast<size_t>(0));
+ item.IsShown())
+ {
+ assert(item.GetBorder() <= spaceRimV); //pragmatic check: other controls in the sizer should not have a larger border
+
+ if (const int flag = item.GetFlag();
+ flag & wxLEFT)
+ item.SetFlag(flag & ~wxLEFT);
+
+ sizer.Prepend(spaceRimH, 0);
+ }
+
bool settingFirstButton = true;
auto attach = [&](wxButton* btn)
@@ -93,20 +114,6 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons)
}
};
- //set border on left considering existing items
- if (sizer.GetChildren().GetCount() > 0) //for yet another retarded reason wxWidgets will have wxSizer::GetItem(0) cause an assert rather than just return nullptr as documented
- if (wxSizerItem* item = sizer.GetItem(static_cast<size_t>(0)))
- {
- assert(item->GetBorder() <= spaceRimV); //pragmatic check: other controls in the sizer should not have a larger border
- int flag = item->GetFlag();
- if (flag & wxLEFT)
- {
- flag &= ~wxLEFT;
- item->SetFlag(flag);
- }
- sizer.Insert(static_cast<size_t>(0), spaceRimH, 0);
- }
-
sizer.Add(spaceRimH, 0);
attach(buttonsTmp.btnNo);
attach(buttonsTmp.btnCancel);
diff --git a/xBRZ/src/xbrz.cpp b/xBRZ/src/xbrz.cpp
index 659614fd..9cf4b8e9 100644
--- a/xBRZ/src/xbrz.cpp
+++ b/xBRZ/src/xbrz.cpp
@@ -475,10 +475,7 @@ public:
void readPonm(Kernel_4x4& ker, int x) const //(x, y) is at kernel position E
{
-#if __has_cpp_attribute(likely)
- [[likely]]
-#endif
- if (const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
+ [[likely]] if (const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
{
ker.p = s_m1 ? s_m1[x_p2] : 0;
ker.o = s_0 ? s_0 [x_p2] : 0;
@@ -691,10 +688,7 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
addTopR(blend_xy1, res.blend_h); //set 2nd known corner for (x, y + 1)
preProcBuf[x] = blend_xy1; //store on current buffer position for use on next row
-#if __has_cpp_attribute(likely)
- [[likely]]
-#endif
- if (x + 1 < srcWidth)
+ [[likely]] if (x + 1 < srcWidth)
{
//blend_xy1 -> blend_x1y1
clearAddTopL(blend_xy1, res.blend_i); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index db4f2505..6940b22f 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -29,71 +29,8 @@
using namespace zen;
-std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
-{
- auto doParse = [&](int sepCountVolumeRoot, bool rootWithSep) -> std::optional<PathComponents>
- {
- const Zstring itemPathFmt = appendSeparator(itemPath); //simplify analysis of root without separator, e.g. \\server-name\share
- int sepCount = 0;
- for (auto it = itemPathFmt.begin(); it != itemPathFmt.end(); ++it)
- if (*it == FILE_NAME_SEPARATOR)
- if (++sepCount == sepCountVolumeRoot)
- {
- Zstring rootPath(itemPathFmt.begin(), rootWithSep ? it + 1 : it);
-
- Zstring relPath(it + 1, itemPathFmt.end());
- trim(relPath, true, true, [](Zchar c) { return c == FILE_NAME_SEPARATOR; });
-
- return PathComponents({rootPath, relPath});
- }
- return {};
- };
-
- std::optional<PathComponents> pc; //"/media/zenju/" and "/Volumes/" should not fail to parse
-
- if (!pc && startsWith(itemPath, "/mnt/")) //e.g. /mnt/DEVICE_NAME
- pc = doParse(3 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
-
- if (!pc && startsWith(itemPath, "/media/")) //Ubuntu: e.g. /media/zenju/DEVICE_NAME
- if (const char* username = ::getenv("USER"))
- if (startsWith(itemPath, std::string("/media/") + username + "/"))
- pc = doParse(4 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
-
- if (!pc && startsWith(itemPath, "/run/media/")) //CentOS, Suse: e.g. /run/media/zenju/DEVICE_NAME
- if (const char* username = ::getenv("USER"))
- if (startsWith(itemPath, std::string("/run/media/") + username + "/"))
- pc = doParse(5 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
-
- if (!pc && startsWith(itemPath, "/run/user/")) //Ubuntu, e.g.: /run/user/1000/gvfs/smb-share:server=192.168.62.145,share=folder
- {
- Zstring tmp(itemPath.begin() + strLength("/run/user/"), itemPath.end());
- tmp = beforeFirst(tmp, "/gvfs/", IfNotFoundReturn::none);
- if (!tmp.empty() && std::all_of(tmp.begin(), tmp.end(), [](char c) { return isDigit(c); }))
- /**/pc = doParse(6 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
- }
-
-
- if (!pc && startsWith(itemPath, "/"))
- pc = doParse(1 /*sepCountVolumeRoot*/, true /*rootWithSep*/);
-
- return pc;
-}
-
-
-std::optional<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
+namespace
{
- if (const std::optional<PathComponents> comp = parsePathComponents(itemPath))
- {
- if (comp->relPath.empty())
- return std::nullopt;
-
- const Zstring parentRelPath = beforeLast(comp->relPath, FILE_NAME_SEPARATOR, IfNotFoundReturn::none);
- if (parentRelPath.empty())
- return comp->rootPath;
- return appendSeparator(comp->rootPath) + parentRelPath;
- }
- assert(false);
- return std::nullopt;
}
diff --git a/zen/file_access.h b/zen/file_access.h
index f3ea6c00..691a8df9 100644
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -17,15 +17,6 @@ namespace zen
{
//note: certain functions require COM initialization! (vista_file_op.h)
-struct PathComponents
-{
- Zstring rootPath; //itemPath = rootPath + (FILE_NAME_SEPARATOR?) + relPath
- Zstring relPath; //
-};
-std::optional<PathComponents> parsePathComponents(const Zstring& itemPath); //no value on failure
-
-std::optional<Zstring> getParentFolderPath(const Zstring& itemPath);
-
//POSITIVE existence checks; if false: 1. item not existing 2. different type 3.device access error or similar
bool fileAvailable(const Zstring& filePath); //noexcept
bool dirAvailable (const Zstring& dirPath ); //
diff --git a/zen/file_path.cpp b/zen/file_path.cpp
new file mode 100644
index 00000000..d846e804
--- /dev/null
+++ b/zen/file_path.cpp
@@ -0,0 +1,79 @@
+// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#include "file_path.h"
+
+using namespace zen;
+
+
+std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
+{
+ auto doParse = [&](int sepCountVolumeRoot, bool rootWithSep) -> std::optional<PathComponents>
+ {
+ const Zstring itemPathFmt = appendSeparator(itemPath); //simplify analysis of root without separator, e.g. \\server-name\share
+ int sepCount = 0;
+ for (auto it = itemPathFmt.begin(); it != itemPathFmt.end(); ++it)
+ if (*it == FILE_NAME_SEPARATOR)
+ if (++sepCount == sepCountVolumeRoot)
+ {
+ Zstring rootPath(itemPathFmt.begin(), rootWithSep ? it + 1 : it);
+
+ Zstring relPath(it + 1, itemPathFmt.end());
+ trim(relPath, true, true, [](Zchar c) { return c == FILE_NAME_SEPARATOR; });
+
+ return PathComponents({rootPath, relPath});
+ }
+ return {};
+ };
+
+ std::optional<PathComponents> pc; //"/media/zenju/" and "/Volumes/" should not fail to parse
+
+ if (!pc && startsWith(itemPath, "/mnt/")) //e.g. /mnt/DEVICE_NAME
+ pc = doParse(3 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+
+ if (!pc && startsWith(itemPath, "/media/")) //Ubuntu: e.g. /media/zenju/DEVICE_NAME
+ if (const char* username = ::getenv("USER"))
+ if (startsWith(itemPath, std::string("/media/") + username + "/"))
+ pc = doParse(4 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+
+ if (!pc && startsWith(itemPath, "/run/media/")) //CentOS, Suse: e.g. /run/media/zenju/DEVICE_NAME
+ if (const char* username = ::getenv("USER"))
+ if (startsWith(itemPath, std::string("/run/media/") + username + "/"))
+ pc = doParse(5 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+
+ if (!pc && startsWith(itemPath, "/run/user/")) //Ubuntu, e.g.: /run/user/1000/gvfs/smb-share:server=192.168.62.145,share=folder
+ {
+ Zstring tmp(itemPath.begin() + strLength("/run/user/"), itemPath.end());
+ tmp = beforeFirst(tmp, "/gvfs/", IfNotFoundReturn::none);
+ if (!tmp.empty() && std::all_of(tmp.begin(), tmp.end(), [](char c) { return isDigit(c); }))
+ /**/pc = doParse(6 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+ }
+
+
+ if (!pc && startsWith(itemPath, "/"))
+ pc = doParse(1 /*sepCountVolumeRoot*/, true /*rootWithSep*/);
+
+ return pc;
+}
+
+
+std::optional<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
+{
+ if (const std::optional<PathComponents> comp = parsePathComponents(itemPath))
+ {
+ if (comp->relPath.empty())
+ return std::nullopt;
+
+ const Zstring parentRelPath = beforeLast(comp->relPath, FILE_NAME_SEPARATOR, IfNotFoundReturn::none);
+ if (parentRelPath.empty())
+ return comp->rootPath;
+ return appendSeparator(comp->rootPath) + parentRelPath;
+ }
+ assert(false);
+ return std::nullopt;
+}
+
+
diff --git a/zen/file_path.h b/zen/file_path.h
new file mode 100644
index 00000000..e328fa8e
--- /dev/null
+++ b/zen/file_path.h
@@ -0,0 +1,27 @@
+// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#ifndef FILE_PATH_H_3984678473567247567
+#define FILE_PATH_H_3984678473567247567
+
+#include "zstring.h"
+
+
+namespace zen
+{
+struct PathComponents
+{
+ Zstring rootPath; //itemPath = rootPath + (FILE_NAME_SEPARATOR?) + relPath
+ Zstring relPath; //
+};
+std::optional<PathComponents> parsePathComponents(const Zstring& itemPath); //no value on failure
+
+std::optional<Zstring> getParentFolderPath(const Zstring& itemPath);
+
+
+}
+
+#endif //FILE_PATH_H_3984678473567247567
diff --git a/zen/http.cpp b/zen/http.cpp
index f8fb24a3..05ed81d1 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -5,7 +5,6 @@
// *****************************************************************************
#include "http.h"
-
#include "socket.h"
#include "open_ssl.h"
diff --git a/zen/resolve_path.cpp b/zen/resolve_path.cpp
index 4eab76ee..0a45646e 100644
--- a/zen/resolve_path.cpp
+++ b/zen/resolve_path.cpp
@@ -8,6 +8,7 @@
#include "time.h"
#include "thread.h"
#include "file_access.h"
+#include "file_path.h"
#include <stdlib.h> //getenv()
#include <unistd.h> //getcwd()
@@ -44,7 +45,7 @@ Zstring resolveRelativePath(const Zstring& relativePath)
assert(runningOnMainThread());
/* MSDN: "Multithreaded applications and shared library code should not use the GetFullPathName function
and should avoid using relative path names. The current directory state written by the
- SetCurrentDirectory function is stored as a global variable in each process,
+ SetCurrentDirectory function is stored as a global variable in each process,
therefore multithreaded applications cannot reliably use this value without possible data corruption from other threads, [...]"
=> Just plain wrong, there is no data corruption. What MSDN really means: GetFullPathName() is *perfectly* thread-safe, but depends
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 32b1211d..60353292 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -9,6 +9,7 @@
#include "scope_guard.h"
#include "file_error.h"
+#include "file_path.h"
#include <unistd.h>
#include <stdlib.h> //realpath
@@ -58,11 +59,15 @@ zen::SymlinkRawContent getSymlinkRawContent_impl(const Zstring& linkPath) //thro
Zstring getResolvedSymlinkPath_impl(const Zstring& linkPath) //throw FileError
{
using namespace zen;
- char* targetPath = ::realpath(linkPath.c_str(), nullptr);
- if (!targetPath)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), "realpath");
- ZEN_ON_SCOPE_EXIT(::free(targetPath));
- return targetPath;
+ try
+ {
+ char* targetPath = ::realpath(linkPath.c_str(), nullptr);
+ if (!targetPath)
+ THROW_LAST_SYS_ERROR("realpath");
+ ZEN_ON_SCOPE_EXIT(::free(targetPath));
+ return targetPath;
+ }
+ catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), e.toString()); }
}
}
diff --git a/zen/zstring.h b/zen/zstring.h
index de90c324..1afebe58 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -136,9 +136,9 @@ Zstring getFileExtension(const Zstring& filePath)
//common unicode characters
-const wchar_t EM_DASH = L'\u2014';
const wchar_t EN_DASH = L'\u2013';
-const wchar_t* const SPACED_DASH = L" \u2013 "; //using 'EN DASH'
+const wchar_t EM_DASH = L'\u2014';
+const wchar_t* const SPACED_DASH = L" \u2014 "; //using 'EM DASH'
const wchar_t LTR_MARK = L'\u200E'; //UTF-8: E2 80 8E
const wchar_t* const ELLIPSIS = L"\u2026"; //"..."
const wchar_t MULT_SIGN = L'\u00D7'; //fancy "x"
bgstack15