summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2018-09-09 18:53:23 -0400
committerB Stack <bgstack15@gmail.com>2018-09-09 18:53:23 -0400
commiteb5d3e5df99de2c3d8da2e8bc7b12ed427465dba (patch)
tree0f0441755ff0e6d65e12222d4502c648bffd6a7c
parent10.3 (diff)
downloadFreeFileSync-eb5d3e5df99de2c3d8da2e8bc7b12ed427465dba.tar.gz
FreeFileSync-eb5d3e5df99de2c3d8da2e8bc7b12ed427465dba.tar.bz2
FreeFileSync-eb5d3e5df99de2c3d8da2e8bc7b12ed427465dba.zip
pull in latest 10.4 from upstream
-rwxr-xr-xChangelog.txt12
-rwxr-xr-xFreeFileSync/Build/Help/images/comparison-settings.pngbin16588 -> 27085 bytes
-rwxr-xr-xFreeFileSync/Build/Help/images/synchronization-settings.pngbin29684 -> 33975 bytes
-rwxr-xr-xFreeFileSync/Build/Languages/arabic.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/bulgarian.lng83
-rwxr-xr-xFreeFileSync/Build/Languages/chinese_simple.lng77
-rwxr-xr-xFreeFileSync/Build/Languages/chinese_traditional.lng83
-rwxr-xr-xFreeFileSync/Build/Languages/croatian.lng85
-rwxr-xr-xFreeFileSync/Build/Languages/czech.lng87
-rwxr-xr-xFreeFileSync/Build/Languages/danish.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/dutch.lng83
-rwxr-xr-xFreeFileSync/Build/Languages/english_uk.lng77
-rwxr-xr-xFreeFileSync/Build/Languages/french.lng413
-rwxr-xr-xFreeFileSync/Build/Languages/german.lng94
-rwxr-xr-xFreeFileSync/Build/Languages/greek.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/hebrew.lng77
-rwxr-xr-xFreeFileSync/Build/Languages/hindi.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/hungarian.lng83
-rwxr-xr-xFreeFileSync/Build/Languages/italian.lng79
-rwxr-xr-xFreeFileSync/Build/Languages/japanese.lng73
-rwxr-xr-xFreeFileSync/Build/Languages/korean.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/lithuanian.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/norwegian.lng87
-rwxr-xr-xFreeFileSync/Build/Languages/polish.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/portuguese.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/portuguese_br.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/romanian.lng73
-rwxr-xr-xFreeFileSync/Build/Languages/russian.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/slovak.lng75
-rwxr-xr-xFreeFileSync/Build/Languages/slovenian.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/spanish.lng89
-rwxr-xr-xFreeFileSync/Build/Languages/swedish.lng71
-rwxr-xr-xFreeFileSync/Build/Languages/turkish.lng73
-rwxr-xr-xFreeFileSync/Build/Languages/ukrainian.lng73
-rwxr-xr-xFreeFileSync/Build/Resources.zipbin319245 -> 318024 bytes
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/folder_selector2.cpp9
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/gui_generated.cpp2
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/monitor.cpp101
-rwxr-xr-xFreeFileSync/Source/base/algorithm.cpp16
-rwxr-xr-xFreeFileSync/Source/base/algorithm.h4
-rwxr-xr-xFreeFileSync/Source/base/application.cpp31
-rwxr-xr-xFreeFileSync/Source/base/comparison.cpp12
-rwxr-xr-xFreeFileSync/Source/base/comparison.h2
-rwxr-xr-xFreeFileSync/Source/base/dir_exist_async.h4
-rwxr-xr-xFreeFileSync/Source/base/dir_lock.cpp13
-rwxr-xr-xFreeFileSync/Source/base/file_hierarchy.cpp40
-rwxr-xr-xFreeFileSync/Source/base/file_hierarchy.h6
-rwxr-xr-xFreeFileSync/Source/base/generate_logfile.cpp32
-rwxr-xr-xFreeFileSync/Source/base/generate_logfile.h14
-rwxr-xr-xFreeFileSync/Source/base/icon_buffer.cpp12
-rwxr-xr-xFreeFileSync/Source/base/icon_buffer.h3
-rwxr-xr-xFreeFileSync/Source/base/localization.cpp48
-rwxr-xr-xFreeFileSync/Source/base/parallel_scan.cpp10
-rwxr-xr-xFreeFileSync/Source/base/parallel_scan.h2
-rwxr-xr-xFreeFileSync/Source/base/parse_lng.h183
-rwxr-xr-xFreeFileSync/Source/base/perf_check.cpp35
-rwxr-xr-xFreeFileSync/Source/base/perf_check.h10
-rwxr-xr-xFreeFileSync/Source/base/process_xml.cpp140
-rwxr-xr-xFreeFileSync/Source/base/process_xml.h36
-rwxr-xr-xFreeFileSync/Source/base/resolve_path.cpp21
-rwxr-xr-xFreeFileSync/Source/base/status_handler.h10
-rwxr-xr-xFreeFileSync/Source/base/status_handler_impl.h18
-rwxr-xr-xFreeFileSync/Source/base/structures.cpp11
-rwxr-xr-xFreeFileSync/Source/base/structures.h19
-rwxr-xr-xFreeFileSync/Source/base/synchronization.cpp203
-rwxr-xr-xFreeFileSync/Source/base/synchronization.h2
-rwxr-xr-xFreeFileSync/Source/base/versioning.cpp75
-rwxr-xr-xFreeFileSync/Source/base/versioning.h1
-rwxr-xr-xFreeFileSync/Source/fs/abstract.cpp102
-rwxr-xr-xFreeFileSync/Source/fs/abstract.h23
-rwxr-xr-xFreeFileSync/Source/fs/concrete_impl.h4
-rwxr-xr-xFreeFileSync/Source/fs/native.cpp12
-rwxr-xr-xFreeFileSync/Source/fs/native.h3
-rwxr-xr-xFreeFileSync/Source/ui/batch_config.cpp57
-rwxr-xr-xFreeFileSync/Source/ui/batch_status_handler.cpp26
-rwxr-xr-xFreeFileSync/Source/ui/batch_status_handler.h13
-rwxr-xr-xFreeFileSync/Source/ui/cfg_grid.cpp38
-rwxr-xr-xFreeFileSync/Source/ui/cfg_grid.h15
-rwxr-xr-xFreeFileSync/Source/ui/file_grid.cpp13
-rwxr-xr-xFreeFileSync/Source/ui/file_view.cpp4
-rwxr-xr-xFreeFileSync/Source/ui/file_view.h5
-rwxr-xr-xFreeFileSync/Source/ui/folder_pair.h14
-rwxr-xr-xFreeFileSync/Source/ui/folder_selector.cpp10
-rwxr-xr-xFreeFileSync/Source/ui/gui_generated.cpp230
-rwxr-xr-xFreeFileSync/Source/ui/gui_generated.h46
-rwxr-xr-xFreeFileSync/Source/ui/gui_status_handler.cpp14
-rwxr-xr-xFreeFileSync/Source/ui/gui_status_handler.h12
-rwxr-xr-xFreeFileSync/Source/ui/log_panel.cpp10
-rwxr-xr-xFreeFileSync/Source/ui/main_dlg.cpp103
-rwxr-xr-xFreeFileSync/Source/ui/main_dlg.h6
-rwxr-xr-xFreeFileSync/Source/ui/progress_indicator.cpp28
-rwxr-xr-xFreeFileSync/Source/ui/small_dlgs.cpp6
-rwxr-xr-xFreeFileSync/Source/ui/sync_cfg.cpp110
-rwxr-xr-xFreeFileSync/Source/ui/sync_cfg.h15
-rwxr-xr-xFreeFileSync/Source/ui/tree_grid.cpp2
-rwxr-xr-xFreeFileSync/Source/ui/tree_grid.h1
-rwxr-xr-xFreeFileSync/Source/ui/version_check.cpp6
-rwxr-xr-xFreeFileSync/Source/version/version.h2
-rwxr-xr-xwx+/choice_enum.h4
-rwxr-xr-xwx+/dc.h11
-rwxr-xr-xwx+/focus.h29
-rwxr-xr-xwx+/graph.cpp4
-rwxr-xr-xwx+/graph.h29
-rwxr-xr-xwx+/grid.cpp56
-rwxr-xr-xwx+/grid.h27
-rwxr-xr-xwx+/image_resources.cpp4
-rwxr-xr-xwx+/image_tools.cpp149
-rwxr-xr-xwx+/image_tools.h2
-rwxr-xr-xwx+/rtl.h5
-rwxr-xr-xxBRZ/src/xbrz.cpp4
-rwxr-xr-xzen/file_access.cpp24
-rwxr-xr-xzen/file_access.h8
-rwxr-xr-xzen/format_unit.h1
-rwxr-xr-xzen/legacy_compiler.h71
-rwxr-xr-xzen/optional.h114
-rwxr-xr-xzen/recycler.cpp2
-rwxr-xr-xzen/ring_buffer.h2
-rwxr-xr-xzen/shell_execute.h2
-rwxr-xr-xzen/socket.h2
-rwxr-xr-xzen/stl_tools.h30
-rwxr-xr-xzen/thread.h15
-rwxr-xr-xzen/utf.h23
-rwxr-xr-xzen/zstring.cpp4
-rwxr-xr-xzen/zstring.h2
-rwxr-xr-xzenXml/zenxml/cvrt_struc.h26
-rwxr-xr-xzenXml/zenxml/cvrt_text.h37
-rwxr-xr-xzenXml/zenxml/dom.h8
127 files changed, 2884 insertions, 2594 deletions
diff --git a/Changelog.txt b/Changelog.txt
index 81106189..90955af9 100755
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,15 @@
+FreeFileSync 10.4 [2018-09-09]
+------------------------------
+Allow overriding log folder path for gui and batch runs
+Fixed RealTimeSync not triggering when using volume path by name
+Fixed reading FTP folders including wildcard chars
+Fixed image overlay graphics glitch (Linux)
+Don't show error if versioning folder is not yet existing
+Fixed crash when removing folder pair just before comparison (F5)
+Fixed crash when parent folder of newly-moved file is deleted after comparison
+Fixed statistics when folder containing moved files is found missing
+
+
FreeFileSync 10.3 [2018-08-07]
------------------------------
New log panel showing details about the last operation
diff --git a/FreeFileSync/Build/Help/images/comparison-settings.png b/FreeFileSync/Build/Help/images/comparison-settings.png
index 242f558a..9f638a4e 100755
--- a/FreeFileSync/Build/Help/images/comparison-settings.png
+++ b/FreeFileSync/Build/Help/images/comparison-settings.png
Binary files differ
diff --git a/FreeFileSync/Build/Help/images/synchronization-settings.png b/FreeFileSync/Build/Help/images/synchronization-settings.png
index 501b3db1..ae2b4be3 100755
--- a/FreeFileSync/Build/Help/images/synchronization-settings.png
+++ b/FreeFileSync/Build/Help/images/synchronization-settings.png
Binary files differ
diff --git a/FreeFileSync/Build/Languages/arabic.lng b/FreeFileSync/Build/Languages/arabic.lng
index d6250172..97143023 100755
--- a/FreeFileSync/Build/Languages/arabic.lng
+++ b/FreeFileSync/Build/Languages/arabic.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>ملف الخيارات العام:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>أي عدد من ملفات تكوين FreeFileSync بامتداد .ffs_gui أو/و .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>أي عدد من ملفات تكوين FreeFileSync بامتداد "ffs_gui" أو/و "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>أي عدد من أزواج المسارات البديلة من أجل ملف خيارات واحد.</target>
@@ -342,6 +342,9 @@
<source>Update attributes on right</source>
<target>تحديث السمات على اليسار</target>
+<source>Warning</source>
+<target>تحذير</target>
+
<source>Items processed:</source>
<target>معالجة العناصر:</target>
@@ -351,6 +354,9 @@
<source>Total time:</source>
<target>مجموع الوقت:</target>
+<source>Stopped</source>
+<target>توقف</target>
+
<source>Cleaning up log files:</source>
<target>تنظيف ملفات السجل:</target>
@@ -394,6 +400,15 @@
<source>Unable to connect to %x.</source>
<target>لا يمكن الاتصال بـ %x.</target>
+<source>Completed successfully</source>
+<target>تم بنجاح</target>
+
+<source>Completed with warnings</source>
+<target>تم بتحذيرات</target>
+
+<source>Completed with errors</source>
+<target>تم بأخطاء</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>لا يمكن الوصول إلى خدمة "نسخ الظل لوحدة التخزين".</target>
@@ -702,8 +717,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. اضغط على 'ابدأ'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>للبدء قم باستيراد ملف .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>للبدء قم باستيراد ملف "ffs_batch".</target>
<source>Folders to watch:</source>
<target>المجلدات للمتابعة:</target>
@@ -785,24 +800,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>النظام: إيقاف التشغيل</target>
-<source>Stopped</source>
-<target>توقف</target>
-
-<source>Completed with errors</source>
-<target>تم بأخطاء</target>
-
-<source>Completed with warnings</source>
-<target>تم بتحذيرات</target>
-
-<source>Warning</source>
-<target>تحذير</target>
-
<source>Nothing to synchronize</source>
<target>لا يوجد شيء للمزامنة</target>
-<source>Completed successfully</source>
-<target>تم بنجاح</target>
-
<source>Executing command %x</source>
<target>تنفيذ الأمر %x</target>
@@ -858,6 +858,9 @@ The command is triggered if:
<source>Last sync</source>
<target>أخر مزامنة</target>
+<source>Log</source>
+<target>السجل</target>
+
<source>Folder</source>
<target>المجلد</target>
@@ -933,6 +936,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>&حفظ كمهمة دفعية...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>بدأ الم&قارنة</target>
@@ -1331,6 +1337,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>إعادة إظهار جميع التنبهات و نوافذ الحوار التي تم إخفاؤها</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>تخصيص القائمة المحلية:</target>
@@ -1421,6 +1430,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>تمييز التكوينات</target>
+<source>Info</source>
+<target>معلومات</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>اختيار الجميع</target>
+
<source>&Options</source>
<target>&خيارات</target>
@@ -1674,21 +1692,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>مقارنة المحتوى...</target>
-<source>Info</source>
-<target>معلومات</target>
-
-<source>Select all</source>
-<target>اختيار الجميع</target>
-
<source>&Continue</source>
<target>&مواصلة</target>
<source>Progress</source>
<target>التقدم</target>
-<source>Log</source>
-<target>السجل</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>شكرا لك، %x, للتبرع والدعم.</target>
@@ -1926,6 +1935,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>تعذر التسجيل لاستقبال رسائل النظام.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>خيار التحميل %x متوفر فقط فى نسخة التبرعات من FreeFileSync.</target>
+
<source>Cannot find system function %x.</source>
<target>لا يمكن العثور على وظيفة نظام %x.</target>
@@ -2090,9 +2102,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>الرجاء اختيار نوع التثبيت المحلي أو اختيار مجلد آخر للتثبيت.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>خيار التحميل %x متوفر فقط فى نسخة التبرعات من FreeFileSync.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>احصل على نسخة التبرعات بالميزات الأضافية وساعد ليكون FreeFileSync خالى من الأعلانات.</target>
diff --git a/FreeFileSync/Build/Languages/bulgarian.lng b/FreeFileSync/Build/Languages/bulgarian.lng
index 7ee65a5c..935fa43f 100755
--- a/FreeFileSync/Build/Languages/bulgarian.lng
+++ b/FreeFileSync/Build/Languages/bulgarian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>глобален конфигурационен файл:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Произволен брой FreeFileSync-конфигурационни-файлове .ffs_gui и/или .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Произволен брой FreeFileSync-конфигурационни-файлове "ffs_gui" и/или "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Произволен брой алтернативни двойки директории за най-много един конфигурационен файл.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Актуализирай атрибутите на десния елемент</target>
+<source>Warning</source>
+<target>Предупреждение</target>
+
<source>Items processed:</source>
<target>Обработени елементи:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Общо време:</target>
+<source>Stopped</source>
+<target>Спряно</target>
+
<source>Cleaning up log files:</source>
<target>Почистване на log-файловете:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Не може да се свърже със %x.</target>
+<source>Completed successfully</source>
+<target>Завърши успешно</target>
+
+<source>Completed with warnings</source>
+<target>Завърши с предупреждения</target>
+
+<source>Completed with errors</source>
+<target>Завърши с грешки</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Не може да получи достъп до услуга Volume Shadow Copy.</target>
@@ -457,12 +472,6 @@
<source>Creating a Volume Shadow Copy for %x...</source>
<target>Създава се Volume Shadow Copy за %x...</target>
-<source>Searching for excess file versions:</source>
-<target>Търси излишни файлови версии:</target>
-
-<source>Removing excess file versions:</source>
-<target>Премахва излишни файлови версии:</target>
-
<source>Cannot find folder %x.</source>
<target>Не е намерена папка %x.</target>
@@ -514,6 +523,12 @@
<source>Generating database...</source>
<target>Създава база данни...</target>
+<source>Searching for excess file versions:</source>
+<target>Търси излишни файлови версии:</target>
+
+<source>Removing excess file versions:</source>
+<target>Премахва излишни файлови версии:</target>
+
<source>Unable to create time stamp for versioning:</source>
<target>Не може да маркира времето на версиите:</target>
@@ -678,8 +693,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Натиснете 'Старт'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>За старт просто импортирайте файл .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>За старт просто импортирайте файл "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Папки за следене:</target>
@@ -761,24 +776,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>Система: Изключване</target>
-<source>Stopped</source>
-<target>Спряно</target>
-
-<source>Completed with errors</source>
-<target>Завърши с грешки</target>
-
-<source>Completed with warnings</source>
-<target>Завърши с предупреждения</target>
-
-<source>Warning</source>
-<target>Предупреждение</target>
-
<source>Nothing to synchronize</source>
<target>Няма нищо за синхронизиране</target>
-<source>Completed successfully</source>
-<target>Завърши успешно</target>
-
<source>Executing command %x</source>
<target>Изпълнява команда %x</target>
@@ -830,6 +830,9 @@ The command is triggered if:
<source>Last sync</source>
<target>Последна синхронизация</target>
+<source>Log</source>
+<target>Протокол</target>
+
<source>Folder</source>
<target>Папка</target>
@@ -905,6 +908,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>Запази &като пакетна задача...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Почни &сравняване</target>
@@ -1303,6 +1309,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Покажи всички постоянно скрити диалози и предупреждения отново</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Настрой контекстното меню:</target>
@@ -1393,6 +1402,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Маркирай Конфигурациите</target>
+<source>Info</source>
+<target>Информация</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Маркирай всичко</target>
+
<source>&Options</source>
<target>&Опции</target>
@@ -1630,21 +1648,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Сравнява съдържанието на файлове...</target>
-<source>Info</source>
-<target>Информация</target>
-
-<source>Select all</source>
-<target>Маркирай всичко</target>
-
<source>&Continue</source>
<target>&Продължи</target>
<source>Progress</source>
<target>Прогрес</target>
-<source>Log</source>
-<target>Протокол</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>%x, благодаря за Вашето дарение и подкрепа!</target>
@@ -1870,6 +1879,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Не се регистрира за получаване на системни съобщения.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Опцията %x инсталиране е възможна само за FreeFileSync Дарителско Издание.</target>
+
<source>Cannot find system function %x.</source>
<target>Не намира системната функция %x.</target>
@@ -2026,9 +2038,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Моля, изберете локален тип инсталация или пък друга папка за инсталация.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Опцията %x инсталиране е възможна само за FreeFileSync Дарителско Издание.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Вземете Дарителско Издание с бонуси и помогнете FreeFileSync да остане свободна.</target>
diff --git a/FreeFileSync/Build/Languages/chinese_simple.lng b/FreeFileSync/Build/Languages/chinese_simple.lng
index 223d2b7d..a4350d39 100755
--- a/FreeFileSync/Build/Languages/chinese_simple.lng
+++ b/FreeFileSync/Build/Languages/chinese_simple.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>全局配置文件:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>任意数目的 FreeFileSync .ffs_gui 和/或 .ffs_batch 配置文件.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>任意数目的 FreeFileSync "ffs_gui" 和/或 "ffs_batch" 配置文件.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>任意数目的替代目录对的最多一个配置文件.</target>
@@ -235,10 +235,10 @@
<target>数据库文件已损坏:</target>
<source>Cannot write file %x.</source>
-<target>无法写入文件 %x .</target>
+<target>无法写入文件 %x.</target>
<source>Cannot read file %x.</source>
-<target>无法读取文件 %x .</target>
+<target>无法读取文件 %x.</target>
<source>The database files do not yet contain information about the last synchronization.</source>
<target>此数据库文件并未包含 有关最后同步的信息.</target>
@@ -332,6 +332,9 @@
<source>Update attributes on right</source>
<target>更新右侧的文件属性</target>
+<source>Warning</source>
+<target>警告</target>
+
<source>Items processed:</source>
<target>已处理的项目:</target>
@@ -341,6 +344,9 @@
<source>Total time:</source>
<target>总共时间:</target>
+<source>Stopped</source>
+<target>已停止</target>
+
<source>Cleaning up log files:</source>
<target>正在清理日志文件:</target>
@@ -379,6 +385,15 @@
<source>Unable to connect to %x.</source>
<target>无法连接到 %x.</target>
+<source>Completed successfully</source>
+<target>成功完成</target>
+
+<source>Completed with warnings</source>
+<target>已完成但有警告</target>
+
+<source>Completed with errors</source>
+<target>已完成但有错误</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>无法访问卷影复制服务.</target>
@@ -672,8 +687,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. 点击'开始'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>要开始只需导入一个 .ffs_batch文件.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>要开始只需导入一个 "ffs_batch"文件.</target>
<source>Folders to watch:</source>
<target>要监视的文件夹:</target>
@@ -755,24 +770,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>系统: 关机</target>
-<source>Stopped</source>
-<target>已停止</target>
-
-<source>Completed with errors</source>
-<target>已完成但有错误</target>
-
-<source>Completed with warnings</source>
-<target>已完成但有警告</target>
-
-<source>Warning</source>
-<target>警告</target>
-
<source>Nothing to synchronize</source>
<target>没有什么可同步</target>
-<source>Completed successfully</source>
-<target>成功完成</target>
-
<source>Executing command %x</source>
<target>正在执行命令 %x</target>
@@ -823,6 +823,9 @@ The command is triggered if:
<source>Last sync</source>
<target>最后同步</target>
+<source>Log</source>
+<target>日志</target>
+
<source>Folder</source>
<target>文件夹</target>
@@ -898,6 +901,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>另存为批处理作业(&B)...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>开始比较(&C)</target>
@@ -1293,6 +1299,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>重新显示所有被永久性隐藏的 对话框和警告信息</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>自定义右键菜单:</target>
@@ -1383,6 +1392,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>突出显示配置文件</target>
+<source>Info</source>
+<target>信息</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>选择全部</target>
+
<source>&Options</source>
<target>选项(&O)</target>
@@ -1512,7 +1530,7 @@ This guarantees a consistent state even in case of a serious error.
<target>FreeFileSync批处理文件</target>
<source>Do you want to save changes to %x?</source>
-<target>是否要保存修改到 %x ?</target>
+<target>是否要保存修改到 %x?</target>
<source>Never save &changes</source>
<target>不再保存更改(&C)</target>
@@ -1616,21 +1634,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>正在比较文件内容...</target>
-<source>Info</source>
-<target>信息</target>
-
-<source>Select all</source>
-<target>选择全部</target>
-
<source>&Continue</source>
<target>继续(&C)</target>
<source>Progress</source>
<target>进度</target>
-<source>Log</source>
-<target>日志</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>谢谢你, %x , 对我们的捐款和支持!</target>
@@ -1853,6 +1862,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>无法注册以接收系统信息.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>安装选项 %x 只在 FreeFileSync 捐赠版有效.</target>
+
<source>Cannot find system function %x.</source>
<target>无法找到系统功能 %x.</target>
@@ -2007,9 +2019,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>请选择本地安装类型, 或选择用于安装的不同文件夹.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>安装选项 %x 只在 FreeFileSync 捐赠版有效.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>获取有额外功能的捐赠版本, 并帮助保持 FreeFileSync 无广告.</target>
diff --git a/FreeFileSync/Build/Languages/chinese_traditional.lng b/FreeFileSync/Build/Languages/chinese_traditional.lng
index c93a07a5..2dc930c4 100755
--- a/FreeFileSync/Build/Languages/chinese_traditional.lng
+++ b/FreeFileSync/Build/Languages/chinese_traditional.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>全域配置檔案:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>FreeFileSync .ffs_gui和(或).ffs_batch配置檔案的任意數量。</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>FreeFileSync "ffs_gui"和(或)"ffs_batch"配置檔案的任意數量。</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>任意數量的備用配對目錄為最多一個配置檔案。</target>
@@ -332,6 +332,9 @@
<source>Update attributes on right</source>
<target>更新右邊的屬性</target>
+<source>Warning</source>
+<target>警告</target>
+
<source>Items processed:</source>
<target>已處理項目:</target>
@@ -341,6 +344,9 @@
<source>Total time:</source>
<target>全部時間:</target>
+<source>Stopped</source>
+<target>已停止</target>
+
<source>Cleaning up log files:</source>
<target>清除日誌檔:</target>
@@ -379,6 +385,15 @@
<source>Unable to connect to %x.</source>
<target>無法連接到 %x。</target>
+<source>Completed successfully</source>
+<target>成功完成</target>
+
+<source>Completed with warnings</source>
+<target>已完成但有警告</target>
+
+<source>Completed with errors</source>
+<target>已完成但有錯誤</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>無法存取磁碟區陰影複製服務。</target>
@@ -454,12 +469,6 @@
<source>Creating a Volume Shadow Copy for %x...</source>
<target>正在建立磁碟區陰影複製為 %x…</target>
-<source>Searching for excess file versions:</source>
-<target>正在搜尋多餘的檔案版本:</target>
-
-<source>Removing excess file versions:</source>
-<target>正在刪除多餘的檔案版本:</target>
-
<source>Cannot find folder %x.</source>
<target>找不到資料夾 %x。</target>
@@ -511,6 +520,12 @@
<source>Generating database...</source>
<target>正在產生資料庫…</target>
+<source>Searching for excess file versions:</source>
+<target>正在搜尋多餘的檔案版本:</target>
+
+<source>Removing excess file versions:</source>
+<target>正在刪除多餘的檔案版本:</target>
+
<source>Unable to create time stamp for versioning:</source>
<target>無法建立時間戳記的版本控制:</target>
@@ -672,8 +687,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. 按下「開始」。</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>若要開始只要導入一個.ffs_batch檔。</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>若要開始只要導入一個"ffs_batch"檔。</target>
<source>Folders to watch:</source>
<target>要監看的資料夾:</target>
@@ -755,24 +770,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>系統:關機</target>
-<source>Stopped</source>
-<target>已停止</target>
-
-<source>Completed with errors</source>
-<target>已完成但有錯誤</target>
-
-<source>Completed with warnings</source>
-<target>已完成但有警告</target>
-
-<source>Warning</source>
-<target>警告</target>
-
<source>Nothing to synchronize</source>
<target>沒有東西可以同步</target>
-<source>Completed successfully</source>
-<target>成功完成</target>
-
<source>Executing command %x</source>
<target>執行命令 %x</target>
@@ -823,6 +823,9 @@ The command is triggered if:
<source>Last sync</source>
<target>上次同步</target>
+<source>Log</source>
+<target>日誌</target>
+
<source>Folder</source>
<target>資料夾</target>
@@ -898,6 +901,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>另存為批次工作(&B)…</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>開始比對(&C)</target>
@@ -1296,6 +1302,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>再次顯示所有永久 隱藏的對話框和警告訊息</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>自訂內容功能表:</target>
@@ -1386,6 +1395,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>突顯配置</target>
+<source>Info</source>
+<target>訊息</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>全選</target>
+
<source>&Options</source>
<target>選項(&O)</target>
@@ -1619,21 +1637,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>正在比對内容…</target>
-<source>Info</source>
-<target>訊息</target>
-
-<source>Select all</source>
-<target>全選</target>
-
<source>&Continue</source>
<target>繼續(&C)</target>
<source>Progress</source>
<target>進度</target>
-<source>Log</source>
-<target>日誌</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>%x, 感謝您的贊助與支持!</target>
@@ -1856,6 +1865,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>無法註冊以接收系統訊息。</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x 安裝選項僅在FreeFileSync贊助版可用。</target>
+
<source>Cannot find system function %x.</source>
<target>找不到系統功能 %x。</target>
@@ -2010,9 +2022,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>請選擇本機安裝類型或選擇不同的安裝資料夾。</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x 安裝選項僅在FreeFileSync贊助版可用。</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>取得贊助版的獎勵功能,並協助維持FreeFileSync無廣告。</target>
diff --git a/FreeFileSync/Build/Languages/croatian.lng b/FreeFileSync/Build/Languages/croatian.lng
index 85ce9399..78107ef3 100755
--- a/FreeFileSync/Build/Languages/croatian.lng
+++ b/FreeFileSync/Build/Languages/croatian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>globalna config datoteka:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Bilo koji broj FreeFileSync .ffs_gui i/ili .ffs_batch konfiguracijskih datoteka.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Bilo koji broj FreeFileSync "ffs_gui" i/ili "ffs_batch" konfiguracijskih datoteka.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Bilo koji broj alternativnih parova mapa za najmanje jednu config datoteku.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Osvježi atribute desno</target>
+<source>Warning</source>
+<target>Upozorenje</target>
+
<source>Items processed:</source>
<target>Obrađene stavke:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Ukupno vrijeme:</target>
+<source>Stopped</source>
+<target>Zaustavljeno</target>
+
<source>Cleaning up log files:</source>
<target>Brisanje log datoteka:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Nije moguće povezivanje na %x.</target>
+<source>Completed successfully</source>
+<target>Dovršeno uspješno</target>
+
+<source>Completed with warnings</source>
+<target>Dovršeno s upozorenjima</target>
+
+<source>Completed with errors</source>
+<target>Dovršeno s pogreškama</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Ne mogu pristupiti Voulme Shadow Copy servisu.</target>
@@ -460,12 +475,6 @@
<source>Creating a Volume Shadow Copy for %x...</source>
<target>Kreiranje Volume Shadow Copy za %x...</target>
-<source>Searching for excess file versions:</source>
-<target>Traženje višestrukih verzija datoteka:</target>
-
-<source>Removing excess file versions:</source>
-<target>Uklanjanje višestrukih verzija datoteka:</target>
-
<source>Cannot find folder %x.</source>
<target>Ne mogu pronaći mapu %x.</target>
@@ -517,6 +526,12 @@
<source>Generating database...</source>
<target>Izrađivanje baze podataka...</target>
+<source>Searching for excess file versions:</source>
+<target>Traženje višestrukih verzija datoteka:</target>
+
+<source>Removing excess file versions:</source>
+<target>Uklanjanje višestrukih verzija datoteka:</target>
+
<source>Unable to create time stamp for versioning:</source>
<target>Nije moguća izrada vremenske oznake za označavanje:</target>
@@ -684,8 +699,8 @@ Stvarno: %y bajta
<source>3. Press 'Start'.</source>
<target>3. Pretisnite 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Da biste započeli jednostavno uvezite .ffs_batch datoteku.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Da biste započeli jednostavno uvezite "ffs_batch" datoteku.</target>
<source>Folders to watch:</source>
<target>Mape za nadziranje:</target>
@@ -767,24 +782,9 @@ Naredba će biti pokrenuta ako se:
<source>System: Shut down</source>
<target>Sistem: Isključivanje</target>
-<source>Stopped</source>
-<target>Zaustavljeno</target>
-
-<source>Completed with errors</source>
-<target>Dovršeno s pogreškama</target>
-
-<source>Completed with warnings</source>
-<target>Dovršeno s upozorenjima</target>
-
-<source>Warning</source>
-<target>Upozorenje</target>
-
<source>Nothing to synchronize</source>
<target>Ništa za sinkronizirati</target>
-<source>Completed successfully</source>
-<target>Dovršeno uspješno</target>
-
<source>Executing command %x</source>
<target>Izvršavanje naredbe %x</target>
@@ -837,6 +837,9 @@ Naredba će biti pokrenuta ako se:
<source>Last sync</source>
<target>Zadnja sinkr</target>
+<source>Log</source>
+<target>Izvješće</target>
+
<source>Folder</source>
<target>Mapa</target>
@@ -912,6 +915,9 @@ Naredba će biti pokrenuta ako se:
<source>Save as &batch job...</source>
<target>Spremi kao &Slijedni zadatak...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Započni &usporedbu</target>
@@ -1137,7 +1143,7 @@ Naredba će biti pokrenuta ako se:
<target>Broj pokušaja:</target>
<source>Delay (in seconds):</source>
-<target>Odgoda (u sekundama) :</target>
+<target>Odgoda (u sekundama):</target>
<source>Run a command after synchronization:</source>
<target>Pokreni naredbu nakon sinkronizacije:</target>
@@ -1310,6 +1316,9 @@ Ovo garantira stabilno stanje čak u slučaju ozbiljne greške.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Prikaži sve trajno skrivene prozore i poruke upozorenja ponovno</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Prilagodite kontekstni izbornik:</target>
@@ -1400,6 +1409,15 @@ Ovo garantira stabilno stanje čak u slučaju ozbiljne greške.
<source>Highlight Configurations</source>
<target>Istakni postavke</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Odaberi sve</target>
+
<source>&Options</source>
<target>&Opcije</target>
@@ -1641,21 +1659,12 @@ Ovo garantira stabilno stanje čak u slučaju ozbiljne greške.
<source>Comparing content...</source>
<target>Uspoređujem sadržaj...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Odaberi sve</target>
-
<source>&Continue</source>
<target>&Nastavi</target>
<source>Progress</source>
<target>Napredak</target>
-<source>Log</source>
-<target>Izvješće</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Hvala Vam, %x, na vašoj donaciji i podršci!</target>
@@ -1884,6 +1893,9 @@ Ovo garantira stabilno stanje čak u slučaju ozbiljne greške.
<source>Unable to register to receive system messages.</source>
<target>Nije moguće registriranje za primanje sistemskih poruka.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x opcija instalacije je dostupna samo u FreeFileSync Donatorskoj verziji.</target>
+
<source>Cannot find system function %x.</source>
<target>Ne mogu pronaći sistemsku funkciju %x.</target>
@@ -2042,9 +2054,6 @@ Ovo garantira stabilno stanje čak u slučaju ozbiljne greške.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Molimo odaberite lokalnu instalaciju ili odaberite drugu mapu za instalaciju.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x opcija instalacije je dostupna samo u FreeFileSync Donatorskoj verziji.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Preuzmite donatorsku verziju sa bonus opcijama i pomognite da FreeFileSync ostane bez reklama.</target>
diff --git a/FreeFileSync/Build/Languages/czech.lng b/FreeFileSync/Build/Languages/czech.lng
index 7bf97103..3403389a 100755
--- a/FreeFileSync/Build/Languages/czech.lng
+++ b/FreeFileSync/Build/Languages/czech.lng
@@ -50,7 +50,7 @@
<target>Mazání symbolického odkazu %x</target>
<source>Checking recycle bin availability for folder %x...</source>
-<target>Kontrola Koše na složku %x ...</target>
+<target>Kontrola Koše na složku %x...</target>
<source>The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:</source>
<target>Pro některé složky nelze použít Koš a proto následující soubory budou odstraněny trvale, bez možnosti obnovy:</target>
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>konfigurační soubory:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Libovolný počet konfiguračních souborů FreeFileSync typu .ffs_gui a/nebo .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Libovolný počet konfiguračních souborů FreeFileSync typu "ffs_gui" a/nebo "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Libovolný počet alternativních párů adresářů na alespoň jednu konfiguraci.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Nastavit vlastnosti vpravo</target>
+<source>Warning</source>
+<target>Varování</target>
+
<source>Items processed:</source>
<target>Zpracováno položek:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Celkový čas:</target>
+<source>Stopped</source>
+<target>Zastaveno</target>
+
<source>Cleaning up log files:</source>
<target>Vyčištění žurnálů:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Nepodařilo se připojit k %x.</target>
+<source>Completed successfully</source>
+<target>Úspěšně dokončeno</target>
+
+<source>Completed with warnings</source>
+<target>Dokončeno s varováním</target>
+
+<source>Completed with errors</source>
+<target>Dokončeno s chybou</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Nepodařil se přístup ke službě Stínové kopie.</target>
@@ -460,12 +475,6 @@
<source>Creating a Volume Shadow Copy for %x...</source>
<target>Vytváření Stínové kopie pro %x...</target>
-<source>Searching for excess file versions:</source>
-<target>Hledání nadbytečných verzí:</target>
-
-<source>Removing excess file versions:</source>
-<target>Odstraňování nadbytečných verzí:</target>
-
<source>Cannot find folder %x.</source>
<target>Nelze najít složku %x.</target>
@@ -517,6 +526,12 @@
<source>Generating database...</source>
<target>Vytváření databáze...</target>
+<source>Searching for excess file versions:</source>
+<target>Hledání nadbytečných verzí:</target>
+
+<source>Removing excess file versions:</source>
+<target>Odstraňování nadbytečných verzí:</target>
+
<source>Unable to create time stamp for versioning:</source>
<target>Nelze vytvořit časové značky verzování:</target>
@@ -684,8 +699,8 @@ Aktuálně: %y b
<source>3. Press 'Start'.</source>
<target>3. Zmáčkněte 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Můžete načíst také konfigurační soubor .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Můžete načíst také konfigurační soubor "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Sledovaná složka:</target>
@@ -767,24 +782,9 @@ Příkaz je spuštěn když:
<source>System: Shut down</source>
<target>Vypnutí počítače</target>
-<source>Stopped</source>
-<target>Zastaveno</target>
-
-<source>Completed with errors</source>
-<target>Dokončeno s chybou</target>
-
-<source>Completed with warnings</source>
-<target>Dokončeno s varováním</target>
-
-<source>Warning</source>
-<target>Varování</target>
-
<source>Nothing to synchronize</source>
<target>Není co synchronizovat</target>
-<source>Completed successfully</source>
-<target>Úspěšně dokončeno</target>
-
<source>Executing command %x</source>
<target>Spuštění příkazu %x</target>
@@ -837,6 +837,9 @@ Příkaz je spuštěn když:
<source>Last sync</source>
<target>Naposledy</target>
+<source>Log</source>
+<target>Žurnál zpracování</target>
+
<source>Folder</source>
<target>Složka</target>
@@ -912,6 +915,9 @@ Příkaz je spuštěn když:
<source>Save as &batch job...</source>
<target>Uložit jako &dávku...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Začít &porovnání</target>
@@ -1307,6 +1313,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Zobrazit znovu všechny trvale skryté dialogy a varovná hlášení</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Přizpůsobit kontextovou nabídku:</target>
@@ -1397,6 +1406,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Zvýraznění položek</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Vybrat vše</target>
+
<source>&Options</source>
<target>Nastavení &programu</target>
@@ -1621,7 +1639,7 @@ This guarantees a consistent state even in case of a serious error.
<target>Seznam souborů exportován</target>
<source>Searching for program updates...</source>
-<target>Hledání aktualizací programu ...</target>
+<target>Hledání aktualizací programu...</target>
<source>Paused</source>
<target>Pauza</target>
@@ -1638,21 +1656,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Porovnávání obsahu...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Vybrat vše</target>
-
<source>&Continue</source>
<target>&Pokračovat</target>
<source>Progress</source>
<target>Průběh</target>
-<source>Log</source>
-<target>Žurnál zpracování</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Děkuji, %x, za příspěvek a podporu!</target>
@@ -1881,6 +1890,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Nepodařilo se zaregistrovat k odběru systémových zpráv.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x instalace je k dispozici pouze v předplacené verzi FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Nelze najít systémovou funkci %x.</target>
@@ -2039,9 +2051,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Prosím zvolte lokální typ instalace nebo vyberte jinou složku.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x instalace je k dispozici pouze v předplacené verzi FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Získat předplacenou verzi s funikcemi navíc a pomoci tím udržet FreeFileSync bez reklam.</target>
diff --git a/FreeFileSync/Build/Languages/danish.lng b/FreeFileSync/Build/Languages/danish.lng
index d2212c78..fe6ed455 100755
--- a/FreeFileSync/Build/Languages/danish.lng
+++ b/FreeFileSync/Build/Languages/danish.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>global indstillingsfil:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Vilkårligt antal FreeFileSync .ffs_gui og/eller .ffs_batch indstillingsfiler.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Vilkårligt antal FreeFileSync "ffs_gui" og/eller "ffs_batch" indstillingsfiler.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Vilkårligt antal alternative mappepar til højst en indstillingsfil.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Opdater attributter mod højre</target>
+<source>Warning</source>
+<target>Advarsel</target>
+
<source>Items processed:</source>
<target>Emner behandlet:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Samlet tid:</target>
+<source>Stopped</source>
+<target>Afbrudt</target>
+
<source>Cleaning up log files:</source>
<target>Rydder logfiler:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Kan ikke kontakte %x.</target>
+<source>Completed successfully</source>
+<target>Gennemført</target>
+
+<source>Completed with warnings</source>
+<target>Gennemført med advarsler</target>
+
+<source>Completed with errors</source>
+<target>Gennemført med fejl</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>VSS tjenesten er ikke tilgængelig.</target>
@@ -678,8 +693,8 @@ Aktuel: %y byte
<source>3. Press 'Start'.</source>
<target>3. Klik 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Importer en .ffs_batchfil (Fil > Åben...) for at komme igang.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Importer en "ffs_batch"fil (Fil > Åben...) for at komme igang.</target>
<source>Folders to watch:</source>
<target>Jobbets mapper:</target>
@@ -761,24 +776,9 @@ Kommandoen udføres hvis:
<source>System: Shut down</source>
<target>System: Luk</target>
-<source>Stopped</source>
-<target>Afbrudt</target>
-
-<source>Completed with errors</source>
-<target>Gennemført med fejl</target>
-
-<source>Completed with warnings</source>
-<target>Gennemført med advarsler</target>
-
-<source>Warning</source>
-<target>Advarsel</target>
-
<source>Nothing to synchronize</source>
<target>Alt er synkroniseret</target>
-<source>Completed successfully</source>
-<target>Gennemført</target>
-
<source>Executing command %x</source>
<target>Kører kommandoen %x</target>
@@ -830,6 +830,9 @@ Kommandoen udføres hvis:
<source>Last sync</source>
<target>Sidste synk</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Mappe</target>
@@ -905,6 +908,9 @@ Kommandoen udføres hvis:
<source>Save as &batch job...</source>
<target>Gem som &batchfil...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Start &analyse</target>
@@ -1303,6 +1309,9 @@ Sikrer processen ved alvorlige fejl.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Vis skjulte advarsler og beskeder igen</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Tilpas kontekstmenu:</target>
@@ -1393,6 +1402,15 @@ Sikrer processen ved alvorlige fejl.
<source>Highlight Configurations</source>
<target>Fremhæv indstillinger</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Vælg alt</target>
+
<source>&Options</source>
<target>&Indstillinger</target>
@@ -1630,21 +1648,12 @@ Sikrer processen ved alvorlige fejl.
<source>Comparing content...</source>
<target>Analyserer indhold...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Vælg alt</target>
-
<source>&Continue</source>
<target>&Fortsæt</target>
<source>Progress</source>
<target>Fremskridt</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Tak %x for donationen og støtten!</target>
@@ -1870,6 +1879,9 @@ Sikrer processen ved alvorlige fejl.
<source>Unable to register to receive system messages.</source>
<target>Kunne ikke registrere modtagelse af systembeskeder.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Installationsmuligheden %x er kun mulig i FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Kan ikke finde systemfunktionen %x.</target>
@@ -2026,9 +2038,6 @@ Sikrer processen ved alvorlige fejl.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Installer normalt, eller vælg en anden mappe.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Installationsmuligheden %x er kun mulig i FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Hent donationsudgave med flere funktioner, og hold FreeFileSync fri for annoncer.</target>
diff --git a/FreeFileSync/Build/Languages/dutch.lng b/FreeFileSync/Build/Languages/dutch.lng
index 8828441e..b68a5d70 100755
--- a/FreeFileSync/Build/Languages/dutch.lng
+++ b/FreeFileSync/Build/Languages/dutch.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>globaal configuratiebestand:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Een willekeurig aantal FreeFileSync. ffs_gui en/of .ffs_batch configuratiebestanden.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Een willekeurig aantal FreeFileSync. ffs_gui en/of "ffs_batch" configuratiebestanden.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Een willekeurig aantal alternatieve mapparen voor maximaal een configuratiebestand.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Update kenmerken aan de rechterzijde</target>
+<source>Warning</source>
+<target>Waarschuwing</target>
+
<source>Items processed:</source>
<target>Items verwerkt:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Totale tijd:</target>
+<source>Stopped</source>
+<target>Gestopt</target>
+
<source>Cleaning up log files:</source>
<target>Logbestanden opschonen:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Kan geen verbinding maken met %x.</target>
+<source>Completed successfully</source>
+<target>Succesvol voltooid</target>
+
+<source>Completed with warnings</source>
+<target>Voltooid met waarschuwingen</target>
+
+<source>Completed with errors</source>
+<target>Voltooid met fouten</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Kan geen toegang krijgen tot de Volume Shadow Copy Service.</target>
@@ -457,12 +472,6 @@
<source>Creating a Volume Shadow Copy for %x...</source>
<target>Maken van een volume schaduwkopie voor %x...</target>
-<source>Searching for excess file versions:</source>
-<target>Zoeken naar overtollige bestandsversies:</target>
-
-<source>Removing excess file versions:</source>
-<target>Overmatige bestandsversies verwijderen:</target>
-
<source>Cannot find folder %x.</source>
<target>Kan de map %x niet vinden.</target>
@@ -514,6 +523,12 @@
<source>Generating database...</source>
<target>Genereren database...</target>
+<source>Searching for excess file versions:</source>
+<target>Zoeken naar overtollige bestandsversies:</target>
+
+<source>Removing excess file versions:</source>
+<target>Overmatige bestandsversies verwijderen:</target>
+
<source>Unable to create time stamp for versioning:</source>
<target>Kan geen tijdstempel maken voor versiebeheer:</target>
@@ -678,8 +693,8 @@ Werkelijk: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Druk op 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Om te beginnen gewoon een .ffs_batch-bestand importeren.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Om te beginnen gewoon een "ffs_batch"-bestand importeren.</target>
<source>Folders to watch:</source>
<target>Mappen om te bekijken:</target>
@@ -761,24 +776,9 @@ De opdracht wordt geactiveerd als:
<source>System: Shut down</source>
<target>Systeem: Uitschakelen</target>
-<source>Stopped</source>
-<target>Gestopt</target>
-
-<source>Completed with errors</source>
-<target>Voltooid met fouten</target>
-
-<source>Completed with warnings</source>
-<target>Voltooid met waarschuwingen</target>
-
-<source>Warning</source>
-<target>Waarschuwing</target>
-
<source>Nothing to synchronize</source>
<target>Niets om te synchroniseren</target>
-<source>Completed successfully</source>
-<target>Succesvol voltooid</target>
-
<source>Executing command %x</source>
<target>Opdracht %x uitvoeren</target>
@@ -830,6 +830,9 @@ De opdracht wordt geactiveerd als:
<source>Last sync</source>
<target>Laatste synchronisatie</target>
+<source>Log</source>
+<target>Logboek</target>
+
<source>Folder</source>
<target>Map</target>
@@ -905,6 +908,9 @@ De opdracht wordt geactiveerd als:
<source>Save as &batch job...</source>
<target>Opslaan als &batchverwerking...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Start &vergelijking</target>
@@ -1303,6 +1309,9 @@ Dit garandeert een consistente status zelfs in het geval van een ernstige fout.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Alle permanent verborgen dialogen en waarschuwingsberichten opnieuw weergeven</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Contextmenu aanpassen:</target>
@@ -1393,6 +1402,15 @@ Dit garandeert een consistente status zelfs in het geval van een ernstige fout.
<source>Highlight Configurations</source>
<target>Markeer Configuraties</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Alles selecteren</target>
+
<source>&Options</source>
<target>&Opties</target>
@@ -1630,21 +1648,12 @@ Dit garandeert een consistente status zelfs in het geval van een ernstige fout.
<source>Comparing content...</source>
<target>Inhoud vergelijken...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Alles selecteren</target>
-
<source>&Continue</source>
<target>&Doorgaan</target>
<source>Progress</source>
<target>Voortgang</target>
-<source>Log</source>
-<target>Logboek</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Dank u, %x, voor uw donatie en ondersteuning!</target>
@@ -1870,6 +1879,9 @@ Dit garandeert een consistente status zelfs in het geval van een ernstige fout.
<source>Unable to register to receive system messages.</source>
<target>Niet in staat om de ontvangen systeemberichten te registreren.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>De %x installatieoptie is alleen beschikbaar in de FreeFileSync Donatie Editie.</target>
+
<source>Cannot find system function %x.</source>
<target>Kan de systeemfunctie %x niet vinden.</target>
@@ -2026,9 +2038,6 @@ Dit garandeert een consistente status zelfs in het geval van een ernstige fout.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Kies voor een lokale installatie of selecteer een andere map voor de installatie.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>De %x installatieoptie is alleen beschikbaar in de FreeFileSync Donatie Editie.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Ontvang de Donatie Editie met bonuseigenschappen en help FreeFileSync advertentie-vrij te houden.</target>
diff --git a/FreeFileSync/Build/Languages/english_uk.lng b/FreeFileSync/Build/Languages/english_uk.lng
index 5adc3a6d..23785c8e 100755
--- a/FreeFileSync/Build/Languages/english_uk.lng
+++ b/FreeFileSync/Build/Languages/english_uk.lng
@@ -7,6 +7,15 @@
<plural_definition>n == 1 ? 0 : 1</plural_definition>
</header>
+<source>No log entries</source>
+<target></target>
+
+<source>Remove old log files after x days:</source>
+<target></target>
+
+<source>Show &log</source>
+<target></target>
+
<source>Both sides have changed since last synchronization.</source>
<target>Both sides have changed since last synchronisation.</target>
@@ -100,8 +109,8 @@
<source>global config file:</source>
<target>global config file:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Any number of alternative directory pairs for at most one config file.</target>
@@ -127,6 +136,9 @@
<source>The folders are created automatically when needed.</source>
<target>The folders are created automatically when needed.</target>
+<source>Scanning:</source>
+<target>Scanning:</target>
+
<source>Comparison finished:</source>
<target>Comparison finished:</target>
@@ -331,6 +343,9 @@
<source>Update attributes on right</source>
<target>Update attributes on right</target>
+<source>Warning</source>
+<target>Warning</target>
+
<source>Items processed:</source>
<target>Elements processed:</target>
@@ -340,6 +355,9 @@
<source>Total time:</source>
<target>Total time:</target>
+<source>Stopped</source>
+<target>Stopped</target>
+
<source>Cleaning up log files:</source>
<target>Cleaning up log files:</target>
@@ -358,9 +376,6 @@
<pluralform>%x threads</pluralform>
</target>
-<source>Scanning:</source>
-<target>Scanning:</target>
-
<source>Cannot read directory %x.</source>
<target>Cannot read directory %x.</target>
@@ -382,6 +397,15 @@
<source>Unable to connect to %x.</source>
<target>Unable to connect to %x.</target>
+<source>Completed successfully</source>
+<target>Completed successfully</target>
+
+<source>Completed with warnings</source>
+<target>Completed with warnings</target>
+
+<source>Completed with errors</source>
+<target>Completed with errors</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Cannot access the Volume Shadow Copy Service.</target>
@@ -678,8 +702,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Press 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>To get started just import a .ffs_batch file.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>To get started just import a "ffs_batch" file.</target>
<source>Folders to watch:</source>
<target>Folders to watch:</target>
@@ -761,24 +785,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>System: Shut down</target>
-<source>Stopped</source>
-<target>Stopped</target>
-
-<source>Completed with errors</source>
-<target>Completed with errors</target>
-
-<source>Completed with warnings</source>
-<target>Completed with warnings</target>
-
-<source>Warning</source>
-<target>Warning</target>
-
<source>Nothing to synchronize</source>
<target>Nothing to synchronise</target>
-<source>Completed successfully</source>
-<target>Completed successfully</target>
-
<source>Executing command %x</source>
<target>Executing command %x</target>
@@ -830,6 +839,9 @@ The command is triggered if:
<source>Last sync</source>
<target>Last sync</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Folder</target>
@@ -1393,6 +1405,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Highlight Configurations</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>Select all</source>
+<target>Select all</target>
+
<source>&Options</source>
<target>&Options</target>
@@ -1630,21 +1648,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Comparing content...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Select all</target>
-
<source>&Continue</source>
<target>&Continue</target>
<source>Progress</source>
<target>Progress</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Thank you, %x, for your donation and support!</target>
@@ -1870,6 +1879,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Unable to register to receive system messages.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>The %x installation option is only available in the FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Cannot find system function %x.</target>
@@ -2026,9 +2038,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Please choose the local installation type or select a different folder for installation.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>The %x installation option is only available in the FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</target>
diff --git a/FreeFileSync/Build/Languages/french.lng b/FreeFileSync/Build/Languages/french.lng
index 69c779fd..fe53e352 100755
--- a/FreeFileSync/Build/Languages/french.lng
+++ b/FreeFileSync/Build/Languages/french.lng
@@ -11,7 +11,7 @@
<target>Les deux côtés ont changé depuis la dernière synchronisation.</target>
<source>Cannot determine sync-direction:</source>
-<target>Impossible de déterminer le sens de la synchronisation :</target>
+<target>Impossible de déterminer le sens de la synchronisation :</target>
<source>No change since last synchronization.</source>
<target>Aucun changement depuis la dernière synchronisation.</target>
@@ -20,7 +20,7 @@
<target>L'entrée de la base de données n'est pas en phase compte tenu des paramètres actuels.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
-<target>Directions de la synchronisation par défaut : les anciens fichiers seront remplacés par les nouveaux.</target>
+<target>Directions de la synchronisation par défaut : les anciens fichiers seront remplacés par les nouveaux.</target>
<source>Creating file %x</source>
<target>Création du fichier %x</target>
@@ -50,10 +50,10 @@
<target>Suppression du lien symbolique %x</target>
<source>Checking recycle bin availability for folder %x...</source>
-<target>Contrôle de la disponibilité de la Corbeille pour le dossier %x ...</target>
+<target>Contrôle de la disponibilité de la Corbeille pour le dossier %x ...</target>
<source>The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:</source>
-<target>La corbeille n'est pas supportée par les dossiers suivants. Les fichiers supprimés ou modifiés ne pourront pas être restaurés :</target>
+<target>La corbeille n'est pas supportée par les dossiers suivants. Les fichiers supprimés ou modifiés ne pourront pas être restaurés :</target>
<source>An exception occurred</source>
<target>Une erreur s'est produite</target>
@@ -89,19 +89,19 @@
<target>Ligne de commande</target>
<source>Syntax:</source>
-<target>Syntaxe :</target>
+<target>Syntaxe :</target>
<source>config files:</source>
-<target>fichier de configuration :</target>
+<target>fichier de configuration :</target>
<source>directory</source>
<target>répertoire</target>
<source>global config file:</source>
-<target>fichier de configuration globale :</target>
+<target>fichier de configuration globale :</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>N'importe quel nombre de fichiers FreeFileSync .ffs_gui et/ou .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>N'importe quel nombre de fichiers FreeFileSync "ffs_gui" et/ou "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>N'importe quel nombre de paires de répertoires distincts pour au plus un fichier de configuration.</target>
@@ -119,19 +119,19 @@
<target>Impossible de charger le fichier %x.</target>
<source>Cannot find the following folders:</source>
-<target>Impossible de trouver les dossiers suivants :</target>
+<target>Impossible de trouver les dossiers suivants :</target>
<source>The following folders do not yet exist:</source>
-<target>Les dossiers suivants n'existent plus :</target>
+<target>Les dossiers suivants n'existent plus :</target>
<source>The folders are created automatically when needed.</source>
<target>Les dossiers sont créés automatiquement quand cela est nécessaire.</target>
<source>Scanning:</source>
-<target>Lecture en cours :</target>
+<target>Lecture en cours :</target>
<source>Comparison finished:</source>
-<target>Comparaison terminée :</target>
+<target>Comparaison terminée :</target>
<source>
<pluralform>1 item found</pluralform>
@@ -146,13 +146,13 @@
<target>Le fichier %x a une date invalide.</target>
<source>Date:</source>
-<target>Date :</target>
+<target>Date :</target>
<source>Files have the same date but a different size.</source>
<target>Les fichiers ont la même date mais une taille différente.</target>
<source>Size:</source>
-<target>Taille :</target>
+<target>Taille :</target>
<source>Content comparison was skipped for excluded files.</source>
<target>La comparaison des contenus est sautée pour les fichiers exclus.</target>
@@ -167,7 +167,7 @@
<target>Comparaison du contenu des fichiers %x</target>
<source>Generating file list...</source>
-<target>Génération de la liste des fichiers...</target>
+<target>Génération de la liste des fichiers ...</target>
<source>Fail-safe file copy</source>
<target>Copie de fichiers sécurisée</target>
@@ -200,7 +200,7 @@
<target>Vérification de la copie des fichiers</target>
<source>Using non-default global settings:</source>
-<target>Utilisation des paramètres globaux particuliers :</target>
+<target>Utilisation des paramètres globaux particuliers :</target>
<source>A folder input field is empty.</source>
<target>Un champ dossier est vide.</target>
@@ -209,7 +209,7 @@
<target>Le dossier correspondant sera considéré comme vide.</target>
<source>Exclude:</source>
-<target>Exclure :</target>
+<target>Exclure :</target>
<source>One base folder of a folder pair is contained in the other one.</source>
<target>Un dossier défini dans la paire des dossiers est contenu dans l'autre.</target>
@@ -218,7 +218,7 @@
<target>Le dossier sera exclu de la synchronisation par le filtre.</target>
<source>Calculating sync directions...</source>
-<target>Evaluation du sens des synchronisations ...</target>
+<target>Evaluation du sens des synchronisations ...</target>
<source>Out of memory.</source>
<target>Mémoire insuffisante.</target>
@@ -227,13 +227,13 @@
<target>La base de données %x n'est pas compatible.</target>
<source>Initial synchronization:</source>
-<target>Première synchronisation :</target>
+<target>Première synchronisation :</target>
<source>Database file %x does not yet exist.</source>
<target>La base de données %x n'existe plus.</target>
<source>Database file is corrupted:</source>
-<target>La base de données est abîmée :</target>
+<target>La base de données est abîmée :</target>
<source>Cannot write file %x.</source>
<target>Impossible d'écrire le fichier %x.</target>
@@ -245,13 +245,13 @@
<target>La base de données ne contient plus aujourd'hui d'informations sur la dernière synchronisation.</target>
<source>Loading file %x...</source>
-<target>Chargement du fichier %x ...</target>
+<target>Chargement du fichier %x ...</target>
<source>Saving file %x...</source>
-<target>Enregistrement du fichier %x ...</target>
+<target>Enregistrement du fichier %x ...</target>
<source>Searching for folder %x...</source>
-<target>Recherche du dossier %x ...</target>
+<target>Recherche du dossier %x ...</target>
<source>Timeout while searching for folder %x.</source>
<target>La recherche du dossier %x a expirée.</target>
@@ -263,13 +263,13 @@
<target>Impossible de lire les attributs du fichier %x.</target>
<source>Waiting while directory is locked:</source>
-<target>En attente tant que le répertoire est verrouillé :</target>
+<target>En attente tant que le répertoire est verrouillé :</target>
<source>Lock owner:</source>
-<target>Propriétaire du verrou :</target>
+<target>Propriétaire du verrou :</target>
<source>Detecting abandoned lock...</source>
-<target>Détection de verrouillage abandonné ...</target>
+<target>Détection de verrouillage abandonné ...</target>
<source>
<pluralform>1 sec</pluralform>
@@ -334,23 +334,29 @@
<source>Update attributes on right</source>
<target>Mise à jour des attributs à droite</target>
+<source>Warning</source>
+<target>Attention</target>
+
<source>Items processed:</source>
-<target>Élements traités :</target>
+<target>Élements traités :</target>
<source>Items remaining:</source>
-<target>Élements restants :</target>
+<target>Élements restants :</target>
<source>Total time:</source>
-<target>Durée totale :</target>
+<target>Durée totale :</target>
+
+<source>Stopped</source>
+<target>Arrêté</target>
<source>Cleaning up log files:</source>
-<target>Nettoyage des journaux :</target>
+<target>Nettoyage des journaux :</target>
<source>Error parsing file %x, row %y, column %z.</source>
<target>Erreur lors de l'analyse du fichier %x, ligne %y, colonne %z.</target>
<source>Cannot set directory locks for the following folders:</source>
-<target>Impossible de verrouiller les répertoires des dossiers suivants :</target>
+<target>Impossible de verrouiller les répertoires des dossiers suivants :</target>
<source>
<pluralform>1 thread</pluralform>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Impossible de se connecter à %x.</target>
+<source>Completed successfully</source>
+<target>Terminé avec succès</target>
+
+<source>Completed with warnings</source>
+<target>Terminé avec observations</target>
+
+<source>Completed with errors</source>
+<target>Terminé avec erreurs</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Impossible d'accéder au service Volume Shadow Copy.</target>
@@ -416,7 +431,7 @@
<target>Personnaliser</target>
<source>Multiple...</source>
-<target>Multiple ...</target>
+<target>Multiple ...</target>
<source>Cannot write file attributes of %x.</source>
<target>Impossible d'écrire les attributs de fichier de %x.</target>
@@ -428,7 +443,7 @@
<target>%x et %y ont des contenus différents.</target>
<source>Data verification error:</source>
-<target>Erreur de contrôle des données :</target>
+<target>Erreur de contrôle des données :</target>
<source>Moving file %x to %y</source>
<target>Déplacement du fichier %x vers %y</target>
@@ -455,13 +470,7 @@
<target>L'élément source %x n'a pas été trouvé</target>
<source>Creating a Volume Shadow Copy for %x...</source>
-<target>Création d'un Volume Shadow Copy pour %x ...</target>
-
-<source>Searching for excess file versions:</source>
-<target>Recherche des versions de fichiers excédentaires :</target>
-
-<source>Removing excess file versions:</source>
-<target>Suppression des versions de fichiers excédentaires :</target>
+<target>Création d'un Volume Shadow Copy pour %x ...</target>
<source>Cannot find folder %x.</source>
<target>Dossier %x introuvable.</target>
@@ -479,19 +488,19 @@
<target>Veuillez entrer le dossier destinataire pour la gestion des versions.</target>
<source>The following items have unresolved conflicts and will not be synchronized:</source>
-<target>Les éléments suivants sont en conflits non résolus et ne seront pas synchronisés :</target>
+<target>Les éléments suivants sont en conflits non résolus et ne seront pas synchronisés :</target>
<source>The following folders are significantly different. Please check that the correct folders are selected for synchronization.</source>
<target>Les dossiers suivants sont assez différents. Veuillez contrôler que ce sont les bons dossiers qui sont sélectionnés pour la synchronisation.</target>
<source>Not enough free disk space available in:</source>
-<target>Espace disque insuffisant sur :</target>
+<target>Espace disque insuffisant sur :</target>
<source>Required:</source>
-<target>Requis :</target>
+<target>Requis :</target>
<source>Available:</source>
-<target>Disponible :</target>
+<target>Disponible :</target>
<source>Some files will be synchronized as part of multiple base folders.</source>
<target>Certains fichiers seront synchronisés comme éléments de plusieurs dossiers de base.</target>
@@ -500,22 +509,28 @@
<target>Pour éviter les conflits, configurez les filtres d'exclusion afin que chaque fichier mis à jour ne soit traité que par un seul dossier de base.</target>
<source>Versioning folder:</source>
-<target>Dossier de gestion des versions :</target>
+<target>Dossier de gestion des versions :</target>
<source>Base folder:</source>
-<target>Dossier de base :</target>
+<target>Dossier de base :</target>
<source>The versioning folder is contained in a base folder.</source>
<target>Le dossier de version est situé dans le dossier de base.</target>
<source>Synchronizing folder pair:</source>
-<target>Synchronisation de la paire de dossiers :</target>
+<target>Synchronisation de la paire de dossiers :</target>
<source>Generating database...</source>
-<target>Génération de la base de données...</target>
+<target>Génération de la base de données ...</target>
+
+<source>Searching for excess file versions:</source>
+<target>Recherche des versions de fichiers excédentaires :</target>
+
+<source>Removing excess file versions:</source>
+<target>Suppression des versions de fichiers excédentaires :</target>
<source>Unable to create time stamp for versioning:</source>
-<target>Impossible de générer l'horodatage pour la gestion des versions :</target>
+<target>Impossible de générer l'horodatage pour la gestion des versions :</target>
<source>
Unexpected size of data stream.
@@ -523,9 +538,9 @@ Expected: %x bytes
Actual: %y bytes
</source>
<target>
-Le flux de données a une taille inattendue :
-Attendu : %x octets
-Trouvé : %y octets
+Le flux de données a une taille inattendue :
+Attendu : %x octets
+Trouvé : %y octets
</target>
<source>Cannot write permissions of %x.</source>
@@ -577,7 +592,7 @@ Trouvé : %y octets
<target>Impossible de trouver le périphérique %x.</target>
<source>Type of item %x is not supported:</source>
-<target>Le type de l'élément %x n'est pas accepté :</target>
+<target>Le type de l'élément %x n'est pas accepté :</target>
<source>Cannot delete symbolic link %x.</source>
<target>Impossible de supprimer le lien symbolique %x.</target>
@@ -586,7 +601,7 @@ Trouvé : %y octets
<target>Impossible de calculer l'espace libre du disque %x.</target>
<source>Incorrect command line:</source>
-<target>Ligne de commande incorrecte :</target>
+<target>Ligne de commande incorrecte :</target>
<source>The server does not support authentication via %x.</source>
<target>Le serveur refuse l'authentification par %x.</target>
@@ -613,7 +628,7 @@ Trouvé : %y octets
</target>
<source>Active connections: %x</source>
-<target>Connexions actives : %x</target>
+<target>Connexions actives : %x</target>
<source>Failed to open SFTP channel number %x.</source>
<target>Impossible d'ouvrir le port SFTP %x.</target>
@@ -646,10 +661,10 @@ Trouvé : %y octets
<target>&Nouveau</target>
<source>&Open...</source>
-<target>&Ouvrir...</target>
+<target>&Ouvrir ...</target>
<source>Save &as...</source>
-<target>S&auvegarder sous...</target>
+<target>S&auvegarder sous ...</target>
<source>E&xit</source>
<target>&Quitter</target>
@@ -667,7 +682,7 @@ Trouvé : %y octets
<target>&Aide</target>
<source>Usage:</source>
-<target>Utilisation :</target>
+<target>Utilisation :</target>
<source>1. Select folders to watch.</source>
<target>1. Choisir les dossiers à examiner.</target>
@@ -678,11 +693,11 @@ Trouvé : %y octets
<source>3. Press 'Start'.</source>
<target>3. Cliquez sur 'Démarrer'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Pour démarrer, il faut importer un fichier .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Pour démarrer, il faut importer un fichier "ffs_batch".</target>
<source>Folders to watch:</source>
-<target>Dossiers à surveiller :</target>
+<target>Dossiers à surveiller :</target>
<source>Add folder</source>
<target>Ajout d'un dossier</target>
@@ -694,13 +709,13 @@ Trouvé : %y octets
<target>Parcourir</target>
<source>Idle time (in seconds):</source>
-<target>Durée d'inactivité (en secondes) :</target>
+<target>Durée d'inactivité (en secondes) :</target>
<source>Idle time between last detected change and execution of command</source>
<target>Délai entre le dernier changement détecté et la dernière exécution de la commande</target>
<source>Command line:</source>
-<target>Ligne de commande :</target>
+<target>Ligne de commande :</target>
<source>
The command is triggered if:
@@ -708,9 +723,9 @@ The command is triggered if:
- new folders arrive (e.g. USB stick insert)
</source>
<target>
-La commande est déclenchée si :
+La commande est déclenchée si :
- un fichier ou un dossier est modifié
-- un nouveau dossier apparait (par exemple : insertion d'une clé USB)
+- un nouveau dossier apparait (par exemple : insertion d'une clé USB)
</target>
<source>Start</source>
@@ -720,7 +735,7 @@ La commande est déclenchée si :
<target>A propos de</target>
<source>Build: %x</source>
-<target>Généré : %x</target>
+<target>Généré : %x</target>
<source>All files</source>
<target>Tous les fichiers</target>
@@ -729,13 +744,13 @@ La commande est déclenchée si :
<target>Synchronisation Automatique</target>
<source>The %x protocol does not support directory monitoring:</source>
-<target>Le protocole %x ne supporte pas le contrôle d'anuaire :</target>
+<target>Le protocole %x ne supporte pas le contrôle d'anuaire :</target>
<source>Directory monitoring active</source>
<target>Gestion des répertoires active</target>
<source>Waiting until directory is available:</source>
-<target>En attente de la disponibilité du répertoire :</target>
+<target>En attente de la disponibilité du répertoire :</target>
<source>&Restore</source>
<target>&Restaurer</target>
@@ -750,35 +765,20 @@ La commande est déclenchée si :
<target>&Réessayer</target>
<source>Loading...</source>
-<target>Chargement ...</target>
+<target>Chargement ...</target>
<source>job name</source>
<target>nom du job</target>
<source>System: Sleep</source>
-<target>Système : Mise en veille</target>
+<target>Système : Mise en veille</target>
<source>System: Shut down</source>
-<target>Système : Arrêt</target>
-
-<source>Stopped</source>
-<target>Arrêté</target>
-
-<source>Completed with errors</source>
-<target>Terminé avec erreurs</target>
-
-<source>Completed with warnings</source>
-<target>Terminé avec observations</target>
-
-<source>Warning</source>
-<target>Attention</target>
+<target>Système : Arrêt</target>
<source>Nothing to synchronize</source>
<target>Rien à synchroniser</target>
-<source>Completed successfully</source>
-<target>Terminé avec succès</target>
-
<source>Executing command %x</source>
<target>Exécution de la commande %x</target>
@@ -804,7 +804,7 @@ La commande est déclenchée si :
<target>&Tout ignorer</target>
<source>Retrying operation...</source>
-<target>Opération retentée ...</target>
+<target>Opération retentée ...</target>
<source>Serious Error</source>
<target>Erreur Grave</target>
@@ -830,6 +830,9 @@ La commande est déclenchée si :
<source>Last sync</source>
<target>Dernière synchro</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Dossier</target>
@@ -903,7 +906,10 @@ La commande est déclenchée si :
<target>&Sauvegarder</target>
<source>Save as &batch job...</source>
-<target>Enregistrer en tant que fichier de &commandes ...</target>
+<target>Enregistrer en tant que fichier de &commandes ...</target>
+
+<source>Show &log</source>
+<target></target>
<source>Start &comparison</source>
<target>Démarrer la &comparaison</target>
@@ -930,10 +936,10 @@ La commande est déclenchée si :
<target>&Langue</target>
<source>&Find...</source>
-<target>&Rechercher...</target>
+<target>&Rechercher ...</target>
<source>&Export file list...</source>
-<target>&Exportation de la liste des fichiers ...</target>
+<target>&Exportation de la liste des fichiers ...</target>
<source>&Reset layout</source>
<target>&Réinitialiser la disposition</target>
@@ -972,7 +978,7 @@ La commande est déclenchée si :
<target>Fermer la barre de recherche</target>
<source>Find:</source>
-<target>Rechercher :</target>
+<target>Rechercher :</target>
<source>Match case</source>
<target>Respect de la casse</target>
@@ -981,22 +987,22 @@ La commande est déclenchée si :
<target>Nouveau</target>
<source>Open...</source>
-<target>Ouvrir ...</target>
+<target>Ouvrir ...</target>
<source>Save</source>
<target>Sauvegarder</target>
<source>Save as...</source>
-<target>Sauvegarder sous ...</target>
+<target>Sauvegarder sous ...</target>
<source>View type:</source>
-<target>Type de vue :</target>
+<target>Type de vue :</target>
<source>Select view:</source>
-<target>Choisir la vue :</target>
+<target>Choisir la vue :</target>
<source>Statistics:</source>
-<target>Statistiques :</target>
+<target>Statistiques :</target>
<source>Number of files and folders that will be deleted</source>
<target>Nombre de fichiers et de dossiers qui seront supprimés</target>
@@ -1014,19 +1020,19 @@ La commande est déclenchée si :
<target>Coordonne la paire de dossiers</target>
<source>Folder pair:</source>
-<target>Paire de dossiers :</target>
+<target>Paire de dossiers :</target>
<source>Main settings:</source>
-<target>Paramètres principaux :</target>
+<target>Paramètres principaux :</target>
<source>Use local settings:</source>
-<target>Utiliser les paramètres locaux :</target>
+<target>Utiliser les paramètres locaux :</target>
<source>Select a variant:</source>
-<target>Choisir une variante :</target>
+<target>Choisir une variante :</target>
<source>Include &symbolic links:</source>
-<target>Inclure les liens &symboliques :</target>
+<target>Inclure les liens &symboliques :</target>
<source>&Follow</source>
<target>&Poursuivre</target>
@@ -1044,25 +1050,25 @@ La commande est déclenchée si :
<target>Liste des décalages de temps UTC à ignorer</target>
<source>Example:</source>
-<target>Exemple :</target>
+<target>Exemple :</target>
<source>Handle daylight saving time</source>
<target>Gérer l'heure d'été</target>
<source>Performance improvements:</source>
-<target>Amélioration des performances :</target>
+<target>Amélioration des performances :</target>
<source>Parallel file operations:</source>
-<target>Opérations sur les fichiers parallèles :</target>
+<target>Opérations sur les fichiers parallèles :</target>
<source>How to get best performance?</source>
-<target>Comment améliorer les performances ?</target>
+<target>Comment améliorer les performances ?</target>
<source>Local settings:</source>
-<target>Paramètres locaux :</target>
+<target>Paramètres locaux :</target>
<source>Include:</source>
-<target>Inclure :</target>
+<target>Inclure :</target>
<source>Show examples</source>
<target>Afficher les exemples</target>
@@ -1071,16 +1077,16 @@ La commande est déclenchée si :
<target>Choisissez les règles de filtrage pour exclure certains fichiers de la synchronisation. Entrez les chemins des fichiers par rapport à leur paire de dossiers.</target>
<source>File size:</source>
-<target>Taille du fichier :</target>
+<target>Taille du fichier :</target>
<source>Minimum:</source>
-<target>Minimum :</target>
+<target>Minimum :</target>
<source>Maximum:</source>
-<target>Maximum :</target>
+<target>Maximum :</target>
<source>Time span:</source>
-<target>Intervalle de temps :</target>
+<target>Intervalle de temps :</target>
<source>C&lear</source>
<target>&Effacer</target>
@@ -1100,7 +1106,7 @@ La commande est déclenchée si :
</target>
<source>Delete files:</source>
-<target>Supprimer les fichiers :</target>
+<target>Supprimer les fichiers :</target>
<source>&Recycle bin</source>
<target>&Corbeille</target>
@@ -1115,43 +1121,43 @@ La commande est déclenchée si :
<target>Déplacer les fichiers vers un dossier utilisateur</target>
<source>Naming convention:</source>
-<target>Convention de nommage :</target>
+<target>Convention de nommage :</target>
<source>Limit file versions:</source>
-<target>Limiter les versions de fichiers :</target>
+<target>Limiter les versions de fichiers :</target>
<source>Last x days:</source>
-<target>Derniers x jours :</target>
+<target>Derniers x jours :</target>
<source>Ignore errors</source>
<target>Ignorer les erreurs</target>
<source>Retry count:</source>
-<target>Nombre de tentatives :</target>
+<target>Nombre de tentatives :</target>
<source>Delay (in seconds):</source>
-<target>Délai (en secondes) :</target>
+<target>Délai (en secondes) :</target>
<source>Run a command after synchronization:</source>
-<target>Exécuter une commande après la synchronisation :</target>
+<target>Exécuter une commande après la synchronisation :</target>
<source>OK</source>
<target>OK</target>
<source>Enter your login details:</source>
-<target>Entrez vos identifiants :</target>
+<target>Entrez vos identifiants :</target>
<source>Connection type:</source>
-<target>Type de connexion :</target>
+<target>Type de connexion :</target>
<source>Server name or IP address:</source>
-<target>Nom du serveur ou adresse IP :</target>
+<target>Nom du serveur ou adresse IP :</target>
<source>Port:</source>
-<target>Port :</target>
+<target>Port :</target>
<source>Encryption:</source>
-<target>Cryptage :</target>
+<target>Cryptage :</target>
<source>&Disabled</source>
<target>&Désactivé</target>
@@ -1160,7 +1166,7 @@ La commande est déclenchée si :
<target>&Explicite SSL/TLS</target>
<source>Authentication:</source>
-<target>Authentication :</target>
+<target>Authentication :</target>
<source>&Password</source>
<target>Mot de &Passe</target>
@@ -1172,46 +1178,46 @@ La commande est déclenchée si :
<target>Agent &SSH</target>
<source>User name:</source>
-<target>Nom de l'utilisateur :</target>
+<target>Nom de l'utilisateur :</target>
<source>Private key file:</source>
-<target>Fichier clé personnel :</target>
+<target>Fichier clé personnel :</target>
<source>&Show password</source>
<target>&Afficher le mot de passe</target>
<source>Directory on server:</source>
-<target>Répertoire sur le serveur :</target>
+<target>Répertoire sur le serveur :</target>
<source>SFTP channels per connection:</source>
-<target>Ports SFTP par connexion :</target>
+<target>Ports SFTP par connexion :</target>
<source>Detect server limit</source>
<target>Détection des limites du serveur</target>
<source>Select a directory on the server:</source>
-<target>Choisir un répertoire sur le serveur :</target>
+<target>Choisir un répertoire sur le serveur :</target>
<source>Select Folder</source>
<target>Choisir un Dossier</target>
<source>Start synchronization now?</source>
-<target>Démarrer la synchronisation maintenant ?</target>
+<target>Démarrer la synchronisation maintenant ?</target>
<source>Variant:</source>
-<target>Variante :</target>
+<target>Variante :</target>
<source>&Don't show this dialog again</source>
<target>&Ne plus afficher cette boîte de dialogue</target>
<source>Items found:</source>
-<target>Élements trouvés :</target>
+<target>Élements trouvés :</target>
<source>Time remaining:</source>
-<target>Temps restant :</target>
+<target>Temps restant :</target>
<source>Time elapsed:</source>
-<target>Temps écoulé :</target>
+<target>Temps écoulé :</target>
<source>Bytes</source>
<target>Octets</target>
@@ -1220,13 +1226,13 @@ La commande est déclenchée si :
<target>Eléments</target>
<source>Synchronizing...</source>
-<target>Synchronisation en cours ...</target>
+<target>Synchronisation en cours ...</target>
<source>Minimize to notification area</source>
<target>Réduction à la zone de notification</target>
<source>When finished:</source>
-<target>A la fin :</target>
+<target>A la fin :</target>
<source>Auto-close</source>
<target>Fermeture automatique</target>
@@ -1241,7 +1247,7 @@ La commande est déclenchée si :
<target>Arrêt</target>
<source>Create a batch file for unattended synchronization. To start, double-click this file or schedule in a task planner: %x</source>
-<target>Créer un fichier batch pour une synchronisation non assitée. Pour démarrer, double-cliquez sur ce fichier ou planifiez-le dans le gestionnaire des tâches : %x</target>
+<target>Créer un fichier batch pour une synchronisation non assitée. Pour démarrer, double-cliquez sur ce fichier ou planifiez-le dans le gestionnaire des tâches : %x</target>
<source>Progress dialog:</source>
<target>Fenêtre de progression:</target>
@@ -1262,13 +1268,13 @@ La commande est déclenchée si :
<target>Arrêter la synchronisation à la première erreur</target>
<source>Save log:</source>
-<target>Sauvegarde du fichier log :</target>
+<target>Sauvegarde du fichier log :</target>
<source>Limit number of log files:</source>
-<target>Limiter le nombre de journaux :</target>
+<target>Limiter le nombre de journaux :</target>
<source>How can I schedule a batch job?</source>
-<target>Comment planifier un fichier de commandes ?</target>
+<target>Comment planifier un fichier de commandes ?</target>
<source>&Keep relative paths</source>
<target>&Conserver les chemins relatifs</target>
@@ -1303,8 +1309,11 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Réafficher en permanence les boîtes de dialogue et les avertissements</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
-<target>Personnaliser le menu contextuel :</target>
+<target>Personnaliser le menu contextuel :</target>
<source>Description</source>
<target>Description</target>
@@ -1325,7 +1334,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Email</target>
<source>If you like FreeFileSync:</source>
-<target>Si vous aimez FreeFileSync :</target>
+<target>Si vous aimez FreeFileSync :</target>
<source>Support with a donation</source>
<target>Soutenir avec un don</target>
@@ -1337,37 +1346,37 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Détails pour les donations</target>
<source>Source code written in C++ using:</source>
-<target>Code source écrit en C++ utilisant :</target>
+<target>Code source écrit en C++ utilisant :</target>
<source>Published under the GNU General Public License</source>
<target>Publié sous licence GNU General Public License</target>
<source>Many thanks for localization:</source>
-<target>Un grand merci pour la traduction à :</target>
+<target>Un grand merci pour la traduction à :</target>
<source>Activate the FreeFileSync Donation Edition by one of the following methods:</source>
-<target>Activez la FreeFileSync Donation Edition par l'une des méthodes suivantes :</target>
+<target>Activez la FreeFileSync Donation Edition par l'une des méthodes suivantes :</target>
<source>1. Activate via internet now:</source>
-<target>1. Activez par internet maintenant :</target>
+<target>1. Activez par internet maintenant :</target>
<source>Activate online</source>
<target>Activez en ligne</target>
<source>2. Retrieve an offline activation key from the following URL:</source>
-<target>2. Récupérer une clé d'activation hors ligne à partir de l'URL suivante :</target>
+<target>2. Récupérer une clé d'activation hors ligne à partir de l'URL suivante :</target>
<source>&Copy to clipboard</source>
<target>& Copie dans le presse-papiers</target>
<source>Enter activation key:</source>
-<target>Entrez la clé d'activation :</target>
+<target>Entrez la clé d'activation :</target>
<source>Activate offline</source>
<target>Activez hors ligne</target>
<source>Highlight configurations that have not been run for more than the following number of days:</source>
-<target>Signaler les configurations non exécutées depuis le nombre de jours suivant :</target>
+<target>Signaler les configurations non exécutées depuis le nombre de jours suivant :</target>
<source>Synchronization Settings</source>
<target>Configuration de la Synchronisation</target>
@@ -1393,6 +1402,15 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<source>Highlight Configurations</source>
<target>Signaler les configurations</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Tout sélectionner</target>
+
<source>&Options</source>
<target>&Options</target>
@@ -1421,7 +1439,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>&Afficher les détails</target>
<source>FreeFileSync %x is available!</source>
-<target>FreeFileSync %x est disponible !</target>
+<target>FreeFileSync %x est disponible !</target>
<source>Local path not available for %x.</source>
<target>Chemin local invalide pour %x.</target>
@@ -1434,8 +1452,8 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<pluralform>Do you really want to execute the command %y for %x items?</pluralform>
</source>
<target>
-<pluralform>Êtes-vous sûr de vouloir exécuter la commande %y pour %x élément ?</pluralform>
-<pluralform>Êtes-vous sûr de vouloir exécuter la commande %y pour %x éléments ?</pluralform>
+<pluralform>Êtes-vous sûr de vouloir exécuter la commande %y pour %x élément ?</pluralform>
+<pluralform>Êtes-vous sûr de vouloir exécuter la commande %y pour %x éléments ?</pluralform>
</target>
<source>&Execute</source>
@@ -1469,16 +1487,16 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
</target>
<source>Set direction:</source>
-<target>Choix de la direction :</target>
+<target>Choix de la direction :</target>
<source>multiple selection</source>
<target>sélection multiple</target>
<source>Include via filter:</source>
-<target>Inclure à l'aide du filtre :</target>
+<target>Inclure à l'aide du filtre :</target>
<source>Exclude via filter:</source>
-<target>Exclure à l'aide du filtre :</target>
+<target>Exclure à l'aide du filtre :</target>
<source>Include temporarily</source>
<target>Inclure temporairement</target>
@@ -1487,7 +1505,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Exclure temporairement</target>
<source>&Copy to...</source>
-<target>&Copier vers ...</target>
+<target>&Copier vers ...</target>
<source>&Delete</source>
<target>&Supprimer</target>
@@ -1499,7 +1517,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Exclure tout</target>
<source>Show icons:</source>
-<target>Afficher les icônes :</target>
+<target>Afficher les icônes :</target>
<source>Small</source>
<target>Petit</target>
@@ -1511,7 +1529,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Grand</target>
<source>Select time span...</source>
-<target>Choisir un intervalle de temps ...</target>
+<target>Choisir un intervalle de temps ...</target>
<source>Donation Edition</source>
<target>Edition Donation</target>
@@ -1526,7 +1544,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>FreeFileSync batch</target>
<source>Do you want to save changes to %x?</source>
-<target>Voulez-vous enregistrer les modifications dans %x ?</target>
+<target>Voulez-vous enregistrer les modifications dans %x ?</target>
<source>Never save &changes</source>
<target>Ne jamais sauvegarder les &modifications</target>
@@ -1538,7 +1556,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Masquer la configuration</target>
<source>Highlight...</source>
-<target>Signaler ...</target>
+<target>Signaler ...</target>
<source>Clear filter</source>
<target>Effacer les filtres</target>
@@ -1613,28 +1631,22 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Liste des fichiers exportée</target>
<source>Searching for program updates...</source>
-<target>Recherche de mises à jour ...</target>
+<target>Recherche de mises à jour ...</target>
<source>Paused</source>
<target>En pause</target>
<source>Stop requested...</source>
-<target>Arrêt demandé ...</target>
+<target>Arrêt demandé ...</target>
<source>Initializing...</source>
-<target>Initialisation ...</target>
+<target>Initialisation ...</target>
<source>Scanning...</source>
-<target>Lecture en cours ...</target>
+<target>Lecture en cours ...</target>
<source>Comparing content...</source>
-<target>Comparaison du contenu ...</target>
-
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Tout sélectionner</target>
+<target>Comparaison du contenu ...</target>
<source>&Continue</source>
<target>&Continuer</target>
@@ -1642,23 +1654,20 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<source>Progress</source>
<target>Progression</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
-<target>Merci %x pour votre don et votre aide !</target>
+<target>Merci %x pour votre don et votre aide !</target>
<source>Connections</source>
<target>Connexions</target>
<source>Recommended range:</source>
-<target>Plage recommandée :</target>
+<target>Plage recommandée :</target>
<source>Password:</source>
-<target>Mot de passe :</target>
+<target>Mot de passe :</target>
<source>Key password:</source>
-<target>Clé du mot de passe :</target>
+<target>Clé du mot de passe :</target>
<source>Please enter a file path.</source>
<target>Veuillez entrer un chemin d'accès.</target>
@@ -1668,8 +1677,8 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<pluralform>Copy the following %x items to another folder?</pluralform>
</source>
<target>
-<pluralform>Copier %x élément dans un autre dossier ?</pluralform>
-<pluralform>Copier les %x éléments suivants dans un autre dossier ?</pluralform>
+<pluralform>Copier %x élément dans un autre dossier ?</pluralform>
+<pluralform>Copier les %x éléments suivants dans un autre dossier ?</pluralform>
</target>
<source>Please enter a target folder.</source>
@@ -1680,8 +1689,8 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<pluralform>Do you really want to move the following %x items to the recycle bin?</pluralform>
</source>
<target>
-<pluralform>Etes-vous sûr de vouloir mettre à la Corbeille %x élément suivant ?</pluralform>
-<pluralform>Etes-vous sûr de vouloir mettre à la Corbeille les %x éléments suivants ?</pluralform>
+<pluralform>Etes-vous sûr de vouloir mettre à la Corbeille %x élément suivant ?</pluralform>
+<pluralform>Etes-vous sûr de vouloir mettre à la Corbeille les %x éléments suivants ?</pluralform>
</target>
<source>Move</source>
@@ -1692,15 +1701,15 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<pluralform>Do you really want to delete the following %x items?</pluralform>
</source>
<target>
-<pluralform>Voulez-vous vraiment supprimer %x élément ?</pluralform>
-<pluralform>Voulez-vous vraiment supprimer ces %x éléments ?</pluralform>
+<pluralform>Voulez-vous vraiment supprimer %x élément ?</pluralform>
+<pluralform>Voulez-vous vraiment supprimer ces %x éléments ?</pluralform>
</target>
<source>Copy DACL, SACL, Owner, Group</source>
<target>Copie DACL, SACL, propriétaire et groupe</target>
<source>Integrate external applications into context menu. The following macros are available:</source>
-<target>Inclure les applications externes dans le menu contextuel. Les macros suivantes sont disponibles :</target>
+<target>Inclure les applications externes dans le menu contextuel. Les macros suivantes sont disponibles :</target>
<source>Full file or folder path</source>
<target>Chemin complet du fichier ou du dossier</target>
@@ -1721,7 +1730,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Afficher toutes les boîtes de dialogue</target>
<source>Downloading update...</source>
-<target>Téléchargement de la mise à jour ...</target>
+<target>Téléchargement de la mise à jour ...</target>
<source>Identify equal files by comparing modification time and size.</source>
<target>Reconnaître les fichiers identiques à l'aide de leur taille et de leur date.</target>
@@ -1793,13 +1802,13 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Ajouter un horodatage à chaque nom de fichier</target>
<source>On completion:</source>
-<target>A la fin :</target>
+<target>A la fin :</target>
<source>On errors:</source>
-<target>En cas d'erreur :</target>
+<target>En cas d'erreur :</target>
<source>On success:</source>
-<target>En cas de succès :</target>
+<target>En cas de succès :</target>
<source>Main config</source>
<target>Configuration principale</target>
@@ -1826,13 +1835,13 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Impossible de retrouver les informations de mise à jour.</target>
<source>Automatic updates:</source>
-<target>Mise à jour automatique :</target>
+<target>Mise à jour automatique :</target>
<source>Check for Program Updates</source>
<target>Recherche des Mises à Jour</target>
<source>Auto-update now or download manually from the FreeFileSync home page?</source>
-<target>Mise à jour automatique maintenant ou téléchargement manuel à partir du site de FreeFileSync ?</target>
+<target>Mise à jour automatique maintenant ou téléchargement manuel à partir du site de FreeFileSync ?</target>
<source>&Auto-update</source>
<target>Mise à jour &automatique</target>
@@ -1841,7 +1850,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>&Téléchargement</target>
<source>Download now?</source>
-<target>Télécharger maintenant ?</target>
+<target>Télécharger maintenant ?</target>
<source>&Download</source>
<target>&Télécharger</target>
@@ -1850,7 +1859,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>FreeFileSync est à jour.</target>
<source>Cannot find current FreeFileSync version number online. A newer version is likely available. Check manually now?</source>
-<target>Le numéro de la version courante de FreeFileSync est introuvable sur internet. Une nouvelle version est probablement disponible. Voulez-vous vérifier maintenant ?</target>
+<target>Le numéro de la version courante de FreeFileSync est introuvable sur internet. Une nouvelle version est probablement disponible. Voulez-vous vérifier maintenant ?</target>
<source>&Check</source>
<target>&Contrôle</target>
@@ -1870,6 +1879,9 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<source>Unable to register to receive system messages.</source>
<target>Impossible d'enregistrer la réception des messages système.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>L'option d'installation %x n'est disponible que dans FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Impossible de trouver la fonction système %x.</target>
@@ -1880,7 +1892,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Impossible de gérer le répertoire %x.</target>
<source>The file is locked by another process:</source>
-<target>Le fichier est verrouillé par un autre process :</target>
+<target>Le fichier est verrouillé par un autre process :</target>
<source>Cannot read security context of %x.</source>
<target>Impossible de lire les paramètres de sécurité de %x.</target>
@@ -1943,7 +1955,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Échec de la vérification de la Corbeille pour le dossier %x.</target>
<source>The following XML elements could not be read:</source>
-<target>Les éléments XML suivants ne peuvent être lus :</target>
+<target>Les éléments XML suivants ne peuvent être lus :</target>
<source>Configuration file %x is incomplete. The missing elements will be set to their default values.</source>
<target>Le fichier de configuration %x est incomplet. Les éléments manquants sont fixés à leur valeur par défaut.</target>
@@ -1955,7 +1967,7 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Sélectionnez les composants que vous voulez installer.</target>
<source>Select installation type:</source>
-<target>Choisir le type d'installation :</target>
+<target>Choisir le type d'installation :</target>
<source>Local</source>
<target>Locale</target>
@@ -1982,10 +1994,10 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<target>Copier seulement les fichiers</target>
<source>Choose a directory for installation:</source>
-<target>Choisir le répertoire d'installation :</target>
+<target>Choisir le répertoire d'installation :</target>
<source>Create shortcuts:</source>
-<target>Création de raccourcis sur :</target>
+<target>Création de raccourcis sur :</target>
<source>Desktop</source>
<target>le Bureau</target>
@@ -2026,9 +2038,6 @@ Cela garantit la cohérence du système de fichiers en cas d'erreur grave.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Veuillez choisir le type d'installation locale ou sélectionner un autre dossier pour cette installation.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>L'option d'installation %x n'est disponible que dans FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Obtenez l'Édition Don avec des fonctionnalités bonus et aidez FreeFileSync à rester sans publicité.</target>
diff --git a/FreeFileSync/Build/Languages/german.lng b/FreeFileSync/Build/Languages/german.lng
index 9739cf40..51d22174 100755
--- a/FreeFileSync/Build/Languages/german.lng
+++ b/FreeFileSync/Build/Languages/german.lng
@@ -7,14 +7,11 @@
<plural_definition>n == 1 ? 0 : 1</plural_definition>
</header>
-<source>No log entries</source>
-<target>Keine Protokolleinträge</target>
-
-<source>Remove old log files after x days:</source>
-<target>Alte Protokolldateien nach x Tagen entfernen:</target>
+<source>Default log path:</source>
+<target>Standardprotokollpfad:</target>
-<source>Show &log</source>
-<target>&Protokoll zeigen</target>
+<source>&Override default log path:</source>
+<target>&Standardprotokollpfad überschreiben:</target>
<source>Both sides have changed since last synchronization.</source>
<target>Beide Seiten wurden seit der letzten Synchronisation verändert.</target>
@@ -109,8 +106,8 @@
<source>global config file:</source>
<target>Globale Konfigurationsdatei:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Beliebige Anzahl von FreeFileSync .ffs_gui und/oder .ffs_batch Konfigurationsdateien.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Beliebige Anzahl von FreeFileSync "ffs_gui" und/oder "ffs_batch" Konfigurationsdateien.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Beliebige Anzahl von alternativen Verzeichnispaaren für maximal eine Konfigurationsdatei.</target>
@@ -642,24 +639,6 @@ Tatsächlich: %y bytes
<source>Failed to open SFTP channel number %x.</source>
<target>Der SFTP Kanal Nummer %x konnte nicht geöffnet werden.</target>
-<source>
-<pluralform>1 byte</pluralform>
-<pluralform>%x bytes</pluralform>
-</source>
-<target>
-<pluralform>1 Byte</pluralform>
-<pluralform>%x Bytes</pluralform>
-</target>
-
-<source>%x MB</source>
-<target>%x MB</target>
-
-<source>%x KB</source>
-<target>%x KB</target>
-
-<source>%x GB</source>
-<target>%x GB</target>
-
<source>Drag && drop</source>
<target>Drag && Drop</target>
@@ -702,8 +681,8 @@ Tatsächlich: %y bytes
<source>3. Press 'Start'.</source>
<target>3. 'Start' drücken.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Zum Schnelleinstieg einfach eine .ffs_batch Datei importieren.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Zum Schnelleinstieg einfach eine "ffs_batch" Datei importieren.</target>
<source>Folders to watch:</source>
<target>Zu überwachende Ordner:</target>
@@ -773,6 +752,24 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>&Retry</source>
<target>&Wiederholen</target>
+<source>
+<pluralform>1 byte</pluralform>
+<pluralform>%x bytes</pluralform>
+</source>
+<target>
+<pluralform>1 Byte</pluralform>
+<pluralform>%x Bytes</pluralform>
+</target>
+
+<source>%x MB</source>
+<target>%x MB</target>
+
+<source>%x KB</source>
+<target>%x KB</target>
+
+<source>%x GB</source>
+<target>%x GB</target>
+
<source>Loading...</source>
<target>Lade...</target>
@@ -917,6 +914,9 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Save as &batch job...</source>
<target>Speichern als Batch&auftrag...</target>
+<source>Show &log</source>
+<target>&Protokoll zeigen</target>
+
<source>Start &comparison</source>
<target>&Vergleich starten</target>
@@ -1061,6 +1061,15 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Handle daylight saving time</source>
<target>Sommerzeit berücksichtigen</target>
+<source>Ignore errors</source>
+<target>Fehler ignorieren</target>
+
+<source>Retry count:</source>
+<target>Wiederholungen:</target>
+
+<source>Delay (in seconds):</source>
+<target>Verzögerung (in Sekunden):</target>
+
<source>Performance improvements:</source>
<target>Leistungsverbesserungen:</target>
@@ -1135,15 +1144,6 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Last x days:</source>
<target>Letzte x Tage:</target>
-<source>Ignore errors</source>
-<target>Fehler ignorieren</target>
-
-<source>Retry count:</source>
-<target>Wiederholungen:</target>
-
-<source>Delay (in seconds):</source>
-<target>Verzögerung (in Sekunden):</target>
-
<source>Run a command after synchronization:</source>
<target>Befehl nach Synchronisation ausführen:</target>
@@ -1273,12 +1273,6 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Stop synchronization at first error</source>
<target>Synchronisation beim ersten Fehler stoppen</target>
-<source>Save log:</source>
-<target>Protokoll speichern:</target>
-
-<source>Limit number of log files:</source>
-<target>Anzahl der Protokolldateien begrenzen:</target>
-
<source>How can I schedule a batch job?</source>
<target>Wie können Batchaufträge in den Taskplaner eingetragen werden?</target>
@@ -1315,6 +1309,9 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Alle dauerhaft versteckten Fenster und Warnmeldungen wieder anzeigen</target>
+<source>Remove old log files after x days:</source>
+<target>Alte Protokolldateien nach x Tagen entfernen:</target>
+
<source>Customize context menu:</source>
<target>Kontextmenü anpassen:</target>
@@ -1408,6 +1405,9 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Info</source>
<target>Info</target>
+<source>No log entries</source>
+<target>Keine Protokolleinträge</target>
+
<source>Select all</source>
<target>Alle auswählen</target>
@@ -1879,6 +1879,9 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Unable to register to receive system messages.</source>
<target>Die Registrierung zum Empfang von Systemmeldungen ist fehlgeschlagen.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Die %x Installationsoption ist nur in der FreeFileSync Spendenversion verfügbar.</target>
+
<source>Cannot find system function %x.</source>
<target>Die Systemfunktion %x wurde nicht gefunden.</target>
@@ -2035,9 +2038,6 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Bitte wählen Sie den lokalen Installationstyp oder einen anderen Ordner für die Installation.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Die %x Installationsoption ist nur in der FreeFileSync Spendenversion verfügbar.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Jetzt die Spendenversion mit Bonusfunktionen holen und mithelfen, FreeFileSync werbefrei zu halten.</target>
diff --git a/FreeFileSync/Build/Languages/greek.lng b/FreeFileSync/Build/Languages/greek.lng
index ffb88275..c09db39b 100755
--- a/FreeFileSync/Build/Languages/greek.lng
+++ b/FreeFileSync/Build/Languages/greek.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>αρχείο γενικών ρυθμίσεων:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Οποιοσδήποτε αριθμός από αρχεία παραμέτρων .ffs_gui ή/και .ffs_batch του FreeFileSync.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Οποιοσδήποτε αριθμός από αρχεία παραμέτρων "ffs_gui" ή/και "ffs_batch" του FreeFileSync.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Οποιοσδήποτε αριθμός από εναλλακτικά ζεύγη υποκαταλόγων για το πολύ ένα αρχείο ρυθμίσεων.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Ενημέρωση των χαρακτηριστικών στα δεξιά</target>
+<source>Warning</source>
+<target>Προειδοποίηση</target>
+
<source>Items processed:</source>
<target>Επεξεργάστηκαν στοιχεία:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Συνολική διάρκεια:</target>
+<source>Stopped</source>
+<target>Διακοπή</target>
+
<source>Cleaning up log files:</source>
<target>Καθάρισμα αρχείων καταγραφής:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Δεν μπορεί να πραγματοποιηθεί σύνδεση με το %x.</target>
+<source>Completed successfully</source>
+<target>Ολοκληρώθηκε επιτυχώς</target>
+
+<source>Completed with warnings</source>
+<target>Ολοκληρώθηκε με προειδοποιήσεις</target>
+
+<source>Completed with errors</source>
+<target>Ολοκληρώθηκε με σφάλματα</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Δεν είναι δυνατή η πρόσβαση στην Υπηρεσία Σκιώδους Αντίγραφου Τόμου.</target>
@@ -678,8 +693,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Πατήστε το 'Έναρξη'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Για να ξεκινήσετε μπορείτε απλά να εισάγετε ένα αρχείο .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Για να ξεκινήσετε μπορείτε απλά να εισάγετε ένα αρχείο "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Φάκελοι για παρακολούθηση:</target>
@@ -761,24 +776,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>Σύστημα: Τερματισμός λειτουργίας</target>
-<source>Stopped</source>
-<target>Διακοπή</target>
-
-<source>Completed with errors</source>
-<target>Ολοκληρώθηκε με σφάλματα</target>
-
-<source>Completed with warnings</source>
-<target>Ολοκληρώθηκε με προειδοποιήσεις</target>
-
-<source>Warning</source>
-<target>Προειδοποίηση</target>
-
<source>Nothing to synchronize</source>
<target>Δεν υπάρχει τίποτα προς συγχρονισμό</target>
-<source>Completed successfully</source>
-<target>Ολοκληρώθηκε επιτυχώς</target>
-
<source>Executing command %x</source>
<target>Εκτέλεση εντολής %x</target>
@@ -830,6 +830,9 @@ The command is triggered if:
<source>Last sync</source>
<target>Τελ. συγχρ.</target>
+<source>Log</source>
+<target>Καταγραφή</target>
+
<source>Folder</source>
<target>Φάκελος</target>
@@ -905,6 +908,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>Αποθήκευση ως δέσ&μη ενεργειών...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Έ&ναρξη σύγκρισης</target>
@@ -1303,6 +1309,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Επανεμφάνιση όλων των μόνιμα κρυμμένων ειδοποιήσεων και προειδοποιητικών μηνυμάτων</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Προσαρμογή μενού περιβάλλοντος:</target>
@@ -1393,6 +1402,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Επισήμανση Παραμέτρων</target>
+<source>Info</source>
+<target>Πληροφορίες</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Επιλογή όλων</target>
+
<source>&Options</source>
<target>&Επιλογές</target>
@@ -1630,21 +1648,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Σύγκριση του περιεχομένου...</target>
-<source>Info</source>
-<target>Πληροφορίες</target>
-
-<source>Select all</source>
-<target>Επιλογή όλων</target>
-
<source>&Continue</source>
<target>&Συνέχεια</target>
<source>Progress</source>
<target>Πρόοδος</target>
-<source>Log</source>
-<target>Καταγραφή</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Σας ευχαριστούμε, %x, για τη δωρεά και την υποστήριξή σας!</target>
@@ -1870,6 +1879,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Δεν μπορεί να καταχωρηθεί η λήψη μηνυμάτων συστήματος.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Η επιλογή εγκατάστασης %x είναι διαθέσιμη μόνο στην Έκδοση Δωρητή του FreeFileSync.</target>
+
<source>Cannot find system function %x.</source>
<target>Δεν μπορεί να βρεθεί η λειτουργία συστήματος %x.</target>
@@ -2026,9 +2038,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Παρακαλούμε επιλέξτε την τοπική εγκατάσταση ή επιλέξτε έναν διαφορετικό φάκελο για εγκατάσταση.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Η επιλογή εγκατάστασης %x είναι διαθέσιμη μόνο στην Έκδοση Δωρητή του FreeFileSync.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Αγοράστε την Έκδοση Δωρητή με περισσότερες δυνατότητες και βοηθήστε να μείνει το FreeFileSync χωρίς διαφημίσεις.</target>
diff --git a/FreeFileSync/Build/Languages/hebrew.lng b/FreeFileSync/Build/Languages/hebrew.lng
index 261eed73..7885afd1 100755
--- a/FreeFileSync/Build/Languages/hebrew.lng
+++ b/FreeFileSync/Build/Languages/hebrew.lng
@@ -7,6 +7,15 @@
<plural_definition>n == 1 ? 0 : 1</plural_definition>
</header>
+<source>No log entries</source>
+<target></target>
+
+<source>Remove old log files after x days:</source>
+<target></target>
+
+<source>Show &log</source>
+<target></target>
+
<source>Both sides have changed since last synchronization.</source>
<target>שני הצדדים שונו מאז הסנכרון האחרון.</target>
@@ -100,8 +109,8 @@
<source>global config file:</source>
<target>קבצי תצורה גלובליים:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>כל כמות של קבצי FreeFileSync .ffs_gui ו\או קבצי קונפיגורציה .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>כל כמות של קבצי FreeFileSync "ffs_gui" ו\או קבצי קונפיגורציה "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>כל כמות של זוגות מחיצות אלטרנטיביות עבור קובץ תצורה אחד לפחות.</target>
@@ -110,7 +119,7 @@
<target>פתח את התצורה הבאה לעריכה בלבד מבלי להפעיל אותה.</target>
<source>Path to an alternate GlobalSettings.xml file.</source>
-<target>נתיב אל קובץ GlobalSettingd.xml אלטרנטיבי.</target>
+<target>נתיב אל קובץ GlobalSettings.xml אלטרנטיבי.</target>
<source>Installation files are corrupted. Please reinstall FreeFileSync.</source>
<target>קבצי ההתקנה פגומים. בבקשה התקן מחדש את FreeFileSync.</target>
@@ -334,6 +343,9 @@
<source>Update attributes on right</source>
<target>עדכן תכונות בצד שמאל</target>
+<source>Warning</source>
+<target>אזהרה</target>
+
<source>Items processed:</source>
<target>אלמנטים עובדו:</target>
@@ -343,6 +355,9 @@
<source>Total time:</source>
<target>זמן כולל:</target>
+<source>Stopped</source>
+<target>נעצר</target>
+
<source>Cleaning up log files:</source>
<target>מנקה קבצי יומן:</target>
@@ -382,6 +397,15 @@
<source>Unable to connect to %x.</source>
<target>לא יכול להתחבר אל %x.</target>
+<source>Completed successfully</source>
+<target>הסתיים בהצלחה</target>
+
+<source>Completed with warnings</source>
+<target>הסתיים עם אזהרות</target>
+
+<source>Completed with errors</source>
+<target>הסתיים עם שגיאות</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>לא ניתן לגשת אל שרות Volume Shadow Copy.</target>
@@ -678,8 +702,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. לחץ 'הפעל'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>בכדי להתחיל יבא קובץ .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>בכדי להתחיל יבא קובץ "ffs_batch".</target>
<source>Folders to watch:</source>
<target>תיקיות לצפייה:</target>
@@ -761,24 +785,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>מערכת: כיבוי</target>
-<source>Stopped</source>
-<target>נעצר</target>
-
-<source>Completed with errors</source>
-<target>הסתיים עם שגיאות</target>
-
-<source>Completed with warnings</source>
-<target>הסתיים עם אזהרות</target>
-
-<source>Warning</source>
-<target>אזהרה</target>
-
<source>Nothing to synchronize</source>
<target>אין מה לסנכרן</target>
-<source>Completed successfully</source>
-<target>הסתיים בהצלחה</target>
-
<source>Executing command %x</source>
<target>מבצע פקודה %x</target>
@@ -830,6 +839,9 @@ The command is triggered if:
<source>Last sync</source>
<target>סינכרון אחרון</target>
+<source>Log</source>
+<target>יומן</target>
+
<source>Folder</source>
<target>תיקייה</target>
@@ -1393,6 +1405,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>הדגש תצורות</target>
+<source>Info</source>
+<target>מידע</target>
+
+<source>Select all</source>
+<target>בחר הכל</target>
+
<source>&Options</source>
<target>&אפשרויות</target>
@@ -1421,7 +1439,7 @@ This guarantees a consistent state even in case of a serious error.
<target>&הראה פרטים</target>
<source>FreeFileSync %x is available!</source>
-<target>FreeFileSync %x זמין !</target>
+<target>FreeFileSync %x זמין!</target>
<source>Local path not available for %x.</source>
<target>נתיב מקומי לא זמין עבור %x.</target>
@@ -1622,7 +1640,7 @@ This guarantees a consistent state even in case of a serious error.
<target>עצור בקשה...</target>
<source>Initializing...</source>
-<target>מאתחל ...</target>
+<target>מאתחל...</target>
<source>Scanning...</source>
<target>סורק...</target>
@@ -1630,21 +1648,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>משווה תכולה...</target>
-<source>Info</source>
-<target>מידע</target>
-
-<source>Select all</source>
-<target>בחר הכל</target>
-
<source>&Continue</source>
<target>&המשך</target>
<source>Progress</source>
<target>התקדמות</target>
-<source>Log</source>
-<target>יומן</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>תודה לך %x, עבור תרומתך ותמיכתך!</target>
@@ -1870,6 +1879,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>לא ניתן להרשם לקבלת הודעות מערכת.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>אפשרת התקנה %x זמינה רק במהדורת תרומות של FreeFileSync.</target>
+
<source>Cannot find system function %x.</source>
<target>לא יכול למצוא פונקצית מערכת %x.</target>
@@ -2026,9 +2038,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>בבקשה בחר התקנה מקומית או בחר תיקייה אחרת להתקנה.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>אפשרת התקנה %x זמינה רק במהדורת תרומות של FreeFileSync.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>קבל את מהדורת התרומות עם תכונות נוספות ועזור לשמר את FreeFileSync נטול-פרסומות.</target>
diff --git a/FreeFileSync/Build/Languages/hindi.lng b/FreeFileSync/Build/Languages/hindi.lng
index 43847881..67a3bfcc 100755
--- a/FreeFileSync/Build/Languages/hindi.lng
+++ b/FreeFileSync/Build/Languages/hindi.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>वैश्विक कॉन्फ़िग फ़ाइल:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>कितने भी FreeFileSync .ffs_gui और/या .ffs_batch कॉन्फ़िगरेशन फ़ाइल्स।</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>कितने भी FreeFileSync "ffs_gui" और/या "ffs_batch" कॉन्फ़िगरेशन फ़ाइल्स।</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>कितने भी वैकलपिक निर्देशिका जोडे अधिक से अधिक एक कॉन्फ़िग फ़ाइल के लिए।</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>दाईं तरफ के गुण अद्यतन करें</target>
+<source>Warning</source>
+<target>चेतावनी</target>
+
<source>Items processed:</source>
<target>संसाधित आइटम्स:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>कुल समय:</target>
+<source>Stopped</source>
+<target>रुका</target>
+
<source>Cleaning up log files:</source>
<target>लॉग फाइलों की सफ़ाई जारी:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>%x से कनेक्ट करने में असमर्थ।</target>
+<source>Completed successfully</source>
+<target>सफलतापूर्वक पूर्ण हुआ</target>
+
+<source>Completed with warnings</source>
+<target>चेतावनियों सहित पूर्ण हुआ</target>
+
+<source>Completed with errors</source>
+<target>त्रुटियों सहित पूर्ण हुआ</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>वॉल्यूम शॅडो प्रतिलिपि सर्व्हिस पहुँच प्राप्त नहीं है।</target>
@@ -678,8 +693,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. 'प्रारंभ' दबाएं।</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>प्रारंभ करने के लिए केवल कोई .ffs_batch फ़ाइल आयात करें।</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>प्रारंभ करने के लिए केवल कोई "ffs_batch" फ़ाइल आयात करें।</target>
<source>Folders to watch:</source>
<target>इन फ़ोलडर्स की निगरानी होगी:</target>
@@ -761,24 +776,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>सिस्टम: बंद करें</target>
-<source>Stopped</source>
-<target>रुका</target>
-
-<source>Completed with errors</source>
-<target>त्रुटियों सहित पूर्ण हुआ</target>
-
-<source>Completed with warnings</source>
-<target>चेतावनियों सहित पूर्ण हुआ</target>
-
-<source>Warning</source>
-<target>चेतावनी</target>
-
<source>Nothing to synchronize</source>
<target>सिंक्रनाइज़ करने के लिए कुछ नहीं</target>
-<source>Completed successfully</source>
-<target>सफलतापूर्वक पूर्ण हुआ</target>
-
<source>Executing command %x</source>
<target>कार्यान्वित आदेश %x</target>
@@ -830,6 +830,9 @@ The command is triggered if:
<source>Last sync</source>
<target>पिछला सिंक</target>
+<source>Log</source>
+<target>लॉग</target>
+
<source>Folder</source>
<target>निर्देशिका</target>
@@ -905,6 +908,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>बॅच जॉब के रूप में सहेजें (&b)...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>तुलना शुरू करें (&c)</target>
@@ -1303,6 +1309,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>स्थायी रूप से छिपाये संवाद बॉक्सेस और चेतावनी संदेश फिर से दिखाएं</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>प्रासंगिक मेनू अनुकूलित करें:</target>
@@ -1393,6 +1402,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>कॉन्फ़िगरेशन्स हाइलाइट करें</target>
+<source>Info</source>
+<target>जानकारी</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>सभी चुने</target>
+
<source>&Options</source>
<target>विकल्प (&O)</target>
@@ -1630,21 +1648,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>सामग्री की तुलना हो रही है...</target>
-<source>Info</source>
-<target>जानकारी</target>
-
-<source>Select all</source>
-<target>सभी चुने</target>
-
<source>&Continue</source>
<target>जारी रखें (&C)</target>
<source>Progress</source>
<target>प्रगति</target>
-<source>Log</source>
-<target>लॉग</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>धन्यवाद, %x, आपके दान और समर्थन के लिए!</target>
@@ -1870,6 +1879,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>सिस्टम संदेशों को प्राप्त करने के लिए पंजीकृत करने में असमर्थ।</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x स्थापना विकल्प केवल FreeFileSync दान संस्‍करण में ही उपलब्ध है।</target>
+
<source>Cannot find system function %x.</source>
<target>सिस्टम फ़ंकशन %x ढूंढ नहीं सकते।</target>
@@ -2026,9 +2038,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>स्थापना के लिए कृपया स्थानीय स्थापना प्रकार चयन करें या कोई और निर्देशिका चुनें।</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x स्थापना विकल्प केवल FreeFileSync दान संस्‍करण में ही उपलब्ध है।</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>दान संस्‍करण बोनस सुविधाओं के साथ प्राप्त करें और FreeFileSync विज्ञापन-रहित रखने में मदद करें।</target>
diff --git a/FreeFileSync/Build/Languages/hungarian.lng b/FreeFileSync/Build/Languages/hungarian.lng
index acc1a85a..5135b1d6 100755
--- a/FreeFileSync/Build/Languages/hungarian.lng
+++ b/FreeFileSync/Build/Languages/hungarian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>globális konfigurációs állomány:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Tetszőleges számú .ffs_gui és/vagy .ffs_batch konfigurációs állomány készíthető a FreeFileSync-hez.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Tetszőleges számú "ffs_gui" és/vagy "ffs_batch" konfigurációs állomány készíthető a FreeFileSync-hez.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Tetszőleges számú alternatív könyvtár-pár legfeljebb egy konfigurációs állományban.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Attribútumok frissítése a jobb oldalon</target>
+<source>Warning</source>
+<target>Figyelmeztetés</target>
+
<source>Items processed:</source>
<target>Feldolgozott elemek száma:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Összes időszükséglet:</target>
+<source>Stopped</source>
+<target>Leállítva</target>
+
<source>Cleaning up log files:</source>
<target>A log állományok törlése:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Nem képes %x-hez kapcsolódni.</target>
+<source>Completed successfully</source>
+<target>Sikeresen végrehajtva</target>
+
+<source>Completed with warnings</source>
+<target>Figyelmeztetések mellett végrehajtva</target>
+
+<source>Completed with errors</source>
+<target>Hibák mellett végrehajtva</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Nem elérhető a Kötet Árnyék-másolat szolgáltatás.</target>
@@ -457,12 +472,6 @@
<source>Creating a Volume Shadow Copy for %x...</source>
<target>%x számára árnyékmásolat-kötetet készítése...</target>
-<source>Searching for excess file versions:</source>
-<target>A felesleges fájl-verziók keresése:</target>
-
-<source>Removing excess file versions:</source>
-<target>A felesleges fájl-verziók törlése:</target>
-
<source>Cannot find folder %x.</source>
<target>%x könyvtárat nem találom.</target>
@@ -514,6 +523,12 @@
<source>Generating database...</source>
<target>Adatbázis generálása...</target>
+<source>Searching for excess file versions:</source>
+<target>A felesleges fájl-verziók keresése:</target>
+
+<source>Removing excess file versions:</source>
+<target>A felesleges fájl-verziók törlése:</target>
+
<source>Unable to create time stamp for versioning:</source>
<target>Nem képes időbélyegzés létrehozására a verzióképzéshez:</target>
@@ -678,8 +693,8 @@ Tényleges: %y bájt
<source>3. Press 'Start'.</source>
<target>3. Nyomd meg a Start gombot.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Az induláshoz importáljon egy .ffs_batch állományt.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Az induláshoz importáljon egy "ffs_batch" állományt.</target>
<source>Folders to watch:</source>
<target>Figyelendő könyvtárak:</target>
@@ -761,24 +776,9 @@ A parancs végrehajtódik, ha:
<source>System: Shut down</source>
<target>Rendszer: Leállítva</target>
-<source>Stopped</source>
-<target>Leállítva</target>
-
-<source>Completed with errors</source>
-<target>Hibák mellett végrehajtva</target>
-
-<source>Completed with warnings</source>
-<target>Figyelmeztetések mellett végrehajtva</target>
-
-<source>Warning</source>
-<target>Figyelmeztetés</target>
-
<source>Nothing to synchronize</source>
<target>Nincs mit szinkronizálni</target>
-<source>Completed successfully</source>
-<target>Sikeresen végrehajtva</target>
-
<source>Executing command %x</source>
<target>%x parancs végrehajtása</target>
@@ -830,6 +830,9 @@ A parancs végrehajtódik, ha:
<source>Last sync</source>
<target>Legutóbbi szinkronizálás</target>
+<source>Log</source>
+<target>Napló</target>
+
<source>Folder</source>
<target>Könyvtár</target>
@@ -905,6 +908,9 @@ A parancs végrehajtódik, ha:
<source>Save as &batch job...</source>
<target>Mentse &kötegelt feladatként...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Kezdje az &összehasonlítást</target>
@@ -1303,6 +1309,9 @@ Ez garantálja a konzisztens állapotot egy komoly hiba esetén is.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Mutassa újra az összes ideiglenesen rejtett párbeszédablakot és figyelmeztetést</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Környezeti menü testreszabása:</target>
@@ -1393,6 +1402,15 @@ Ez garantálja a konzisztens állapotot egy komoly hiba esetén is.
<source>Highlight Configurations</source>
<target>Jelölje ki a beállításokat</target>
+<source>Info</source>
+<target>Információ</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Összeset kiválasztja</target>
+
<source>&Options</source>
<target>&Beállítások</target>
@@ -1630,21 +1648,12 @@ Ez garantálja a konzisztens állapotot egy komoly hiba esetén is.
<source>Comparing content...</source>
<target>Tartalom összehasonlítása...</target>
-<source>Info</source>
-<target>Információ</target>
-
-<source>Select all</source>
-<target>Összeset kiválasztja</target>
-
<source>&Continue</source>
<target>&Folytat</target>
<source>Progress</source>
<target>Haladás</target>
-<source>Log</source>
-<target>Napló</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>%x, köszönöm Önnek adományát és támogatását!</target>
@@ -1870,6 +1879,9 @@ Ez garantálja a konzisztens állapotot egy komoly hiba esetén is.
<source>Unable to register to receive system messages.</source>
<target>Nem tud regisztrálni, hogy megkapja a rendszerüzeneteket.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x telepítési opció csak a FreeFileSync Támogatói Kiadásában érhető el.</target>
+
<source>Cannot find system function %x.</source>
<target>%x rendszerfunkció nem elérhető.</target>
@@ -2026,9 +2038,6 @@ Ez garantálja a konzisztens állapotot egy komoly hiba esetén is.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Válassza a helyi telepítési módot vagy válasszon másik könytárat a telepítéshez.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x telepítési opció csak a FreeFileSync Támogatói Kiadásában érhető el.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Használd a Támogatói Kiadást bónusz szolgáltatásokkal és segits reklám-mentesen tartani a FreeFileSync-et.</target>
diff --git a/FreeFileSync/Build/Languages/italian.lng b/FreeFileSync/Build/Languages/italian.lng
index 446fefc4..7064f93f 100755
--- a/FreeFileSync/Build/Languages/italian.lng
+++ b/FreeFileSync/Build/Languages/italian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>file di configurazione globale:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Qualsiasi numero di FreeFileSync.ffs_gui e/o File di configurazione .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Qualsiasi numero di FreeFileSync"ffs_gui" e/o File di configurazione "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Qualsiasi numero di coppie di directory alternative per al massimo un file di configurazione.</target>
@@ -269,7 +269,7 @@
<target>Bloccare il proprietario:</target>
<source>Detecting abandoned lock...</source>
-<target>Rilevamento blocco abbandonato ...</target>
+<target>Rilevamento blocco abbandonato...</target>
<source>
<pluralform>1 sec</pluralform>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Aggiorna attributi a destra</target>
+<source>Warning</source>
+<target>Attenzione</target>
+
<source>Items processed:</source>
<target>Oggetti processati:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Tempo totale:</target>
+<source>Stopped</source>
+<target>Arrestato</target>
+
<source>Cleaning up log files:</source>
<target>Pulizia dei file di registro:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Impossibile connettersi a %x.</target>
+<source>Completed successfully</source>
+<target>Completato con successo</target>
+
+<source>Completed with warnings</source>
+<target>Completato con avvisi</target>
+
+<source>Completed with errors</source>
+<target>Completato con errori</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Impossibile accedere al Volume Shadow Copy Service.</target>
@@ -678,8 +693,8 @@ Attuale: %y byte
<source>3. Press 'Start'.</source>
<target>3. Premi 'Avvio'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Per iniziare è sufficiente importare un file con estensione .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Per iniziare è sufficiente importare un file con estensione "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Cartelle da guardare:</target>
@@ -761,24 +776,9 @@ Il comando è attivato se:
<source>System: Shut down</source>
<target>Sistema: Spento</target>
-<source>Stopped</source>
-<target>Arrestato</target>
-
-<source>Completed with errors</source>
-<target>Completato con errori</target>
-
-<source>Completed with warnings</source>
-<target>Completato con avvisi</target>
-
-<source>Warning</source>
-<target>Attenzione</target>
-
<source>Nothing to synchronize</source>
<target>Non c'è nulla da sincronizzare</target>
-<source>Completed successfully</source>
-<target>Completato con successo</target>
-
<source>Executing command %x</source>
<target>Esecuzione del comando %x</target>
@@ -830,6 +830,9 @@ Il comando è attivato se:
<source>Last sync</source>
<target>Ultima sincronizzazione</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Cartella</target>
@@ -905,6 +908,9 @@ Il comando è attivato se:
<source>Save as &batch job...</source>
<target>Salva come &processo batch...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Avvio &confronto</target>
@@ -930,7 +936,7 @@ Il comando è attivato se:
<target>&Lingua</target>
<source>&Find...</source>
-<target>&Trova ...</target>
+<target>&Trova...</target>
<source>&Export file list...</source>
<target>&Esporta l'elenco dei file...</target>
@@ -987,7 +993,7 @@ Il comando è attivato se:
<target>Salva</target>
<source>Save as...</source>
-<target>Salva come ...</target>
+<target>Salva come...</target>
<source>View type:</source>
<target>Visualizza tipo:</target>
@@ -1303,6 +1309,9 @@ Questo garantisce uno stato consistente anche in caso di errore grave.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Mostra di nuovo tutti i dialoghi nascosti in modo permanente e i messaggi di allarme</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Personalizzare menu contestuale:</target>
@@ -1393,6 +1402,15 @@ Questo garantisce uno stato consistente anche in caso di errore grave.
<source>Highlight Configurations</source>
<target>Evidenzia le configurazioni</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Seleziona tutto</target>
+
<source>&Options</source>
<target>&Opzioni</target>
@@ -1619,7 +1637,7 @@ Questo garantisce uno stato consistente anche in caso di errore grave.
<target>In pausa</target>
<source>Stop requested...</source>
-<target>Stop richiesto ...</target>
+<target>Stop richiesto...</target>
<source>Initializing...</source>
<target>Inizializzazione...</target>
@@ -1630,21 +1648,12 @@ Questo garantisce uno stato consistente anche in caso di errore grave.
<source>Comparing content...</source>
<target>Comparazione del contenuto...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Seleziona tutto</target>
-
<source>&Continue</source>
<target>&Continuare</target>
<source>Progress</source>
<target>Avanzamento</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Grazie, %x, per la vostra donazione e il supporto!</target>
@@ -1870,6 +1879,9 @@ Questo garantisce uno stato consistente anche in caso di errore grave.
<source>Unable to register to receive system messages.</source>
<target>Impossibile registrarsi per ricevere i messaggi di sistema.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>L'opzione di installazione %x è disponibile solo nell'edizione di donazione FreeFileSync.</target>
+
<source>Cannot find system function %x.</source>
<target>Impossibile trovare la funzione di sistema %x.</target>
@@ -2026,9 +2038,6 @@ Questo garantisce uno stato consistente anche in caso di errore grave.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Scegliere il tipo di installazione locale o selezionare una cartella diversa per l'installazione.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>L'opzione di installazione %x è disponibile solo nell'edizione di donazione FreeFileSync.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Ottieni l'Edizione Donazione con funzioni bonus e aiuto per mantenere FreeFileSync senza pubblicità.</target>
diff --git a/FreeFileSync/Build/Languages/japanese.lng b/FreeFileSync/Build/Languages/japanese.lng
index b63b0a12..c1ca09e4 100755
--- a/FreeFileSync/Build/Languages/japanese.lng
+++ b/FreeFileSync/Build/Languages/japanese.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>グローバル構成ファイル:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>任意の数の FreeFileSync 構成設定ファイル(.ffs_gui および/または .ffs_batch).</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>任意の数の FreeFileSync 構成設定ファイル("ffs_gui" および/または "ffs_batch").</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>任意の数の代替ディレクトリペア(ひとつの構成ファイル).</target>
@@ -110,7 +110,7 @@
<target>選択された構成を実行しないで編集用に開きます.</target>
<source>Path to an alternate GlobalSettings.xml file.</source>
-<target>代替グローバル設定.xml ファイルのパス.</target>
+<target></target>
<source>Installation files are corrupted. Please reinstall FreeFileSync.</source>
<target>インストール ファイルが破損しています、FreeFileSync を再インストールしてください.</target>
@@ -332,6 +332,9 @@
<source>Update attributes on right</source>
<target>右の属性を更新</target>
+<source>Warning</source>
+<target>警告</target>
+
<source>Items processed:</source>
<target>処理された要素:</target>
@@ -341,6 +344,9 @@
<source>Total time:</source>
<target>合計時間:</target>
+<source>Stopped</source>
+<target>停止</target>
+
<source>Cleaning up log files:</source>
<target>ログファイルのクリーン:</target>
@@ -379,6 +385,15 @@
<source>Unable to connect to %x.</source>
<target>%x に接続できません.</target>
+<source>Completed successfully</source>
+<target>正常に完了しました</target>
+
+<source>Completed with warnings</source>
+<target>警告で終了</target>
+
+<source>Completed with errors</source>
+<target>エラーで終了</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>ボリュームシャドウコピーサービスにアクセス出来ません.</target>
@@ -672,8 +687,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. 'スタート'をクリック.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>一括ファイル(.ffs)からインポートして開始.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target></target>
<source>Folders to watch:</source>
<target>監視するフォルダ:</target>
@@ -755,24 +770,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>システム: シャットダウン</target>
-<source>Stopped</source>
-<target>停止</target>
-
-<source>Completed with errors</source>
-<target>エラーで終了</target>
-
-<source>Completed with warnings</source>
-<target>警告で終了</target>
-
-<source>Warning</source>
-<target>警告</target>
-
<source>Nothing to synchronize</source>
<target>同期対象がありません</target>
-<source>Completed successfully</source>
-<target>正常に完了しました</target>
-
<source>Executing command %x</source>
<target>コマンド %x を実行中</target>
@@ -823,6 +823,9 @@ The command is triggered if:
<source>Last sync</source>
<target>前回の同期</target>
+<source>Log</source>
+<target>ログ</target>
+
<source>Folder</source>
<target>フォルダ</target>
@@ -898,6 +901,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>一括ジョブで保存(&B)...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>比較を開始(&C)</target>
@@ -1296,6 +1302,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>非表示にしたすべてのダイアログと警告メッセージを再表示</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>コンテキストメニューのカスタマイズ:</target>
@@ -1386,6 +1395,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>構成の強調表示</target>
+<source>Info</source>
+<target>情報</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>すべて選択</target>
+
<source>&Options</source>
<target>設定(&O)</target>
@@ -1619,21 +1637,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>内容を比較中...</target>
-<source>Info</source>
-<target>情報</target>
-
-<source>Select all</source>
-<target>すべて選択</target>
-
<source>&Continue</source>
<target>続行(&C)</target>
<source>Progress</source>
<target>進行状況</target>
-<source>Log</source>
-<target>ログ</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>ありがとう %x, あなたの寄付と支援に感謝します!!</target>
@@ -1856,6 +1865,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>システム受信メッセージに登録できません.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>インストール オプション %x は、FreeFileSync 寄付版でのみ利用可能です.</target>
+
<source>Cannot find system function %x.</source>
<target>システム関数 %x がみつかりません.</target>
@@ -2010,9 +2022,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>ローカル インストールを選択するか、別のインストール先を選択してください.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>インストール オプション %x は、FreeFileSync 寄付版でのみ利用可能です.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>寄付をすることで広告が一切無く、ボーナス機能が付いた FreeFileSync を使用できます.</target>
diff --git a/FreeFileSync/Build/Languages/korean.lng b/FreeFileSync/Build/Languages/korean.lng
index 8529fa42..811c7c51 100755
--- a/FreeFileSync/Build/Languages/korean.lng
+++ b/FreeFileSync/Build/Languages/korean.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>전체 설정 파일:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>FreeFileSync .ffs_gui 또는 .ffs_batch 설정 파일 개수.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>FreeFileSync "ffs_gui" 또는 "ffs_batch" 설정 파일 개수.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>최대 1개 설정파일에 대한 대체 디렉터리 페어 개수.</target>
@@ -332,6 +332,9 @@
<source>Update attributes on right</source>
<target>우측 속성 업데이트</target>
+<source>Warning</source>
+<target>경고</target>
+
<source>Items processed:</source>
<target>처리된 항목:</target>
@@ -341,6 +344,9 @@
<source>Total time:</source>
<target>전체 시간:</target>
+<source>Stopped</source>
+<target>중단</target>
+
<source>Cleaning up log files:</source>
<target>로그 파일 정리 중:</target>
@@ -379,6 +385,15 @@
<source>Unable to connect to %x.</source>
<target>%x에 연결할 수 없습니다.</target>
+<source>Completed successfully</source>
+<target>성공적으로 완료됨</target>
+
+<source>Completed with warnings</source>
+<target>경고와 함께 완료됨</target>
+
+<source>Completed with errors</source>
+<target>오류와 함께 완료됨</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>볼륨 섀도 복사본 서비스에 접근할 수 없습니다.</target>
@@ -672,8 +687,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. '시작'을 누르세요.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>시작하려면 .ffs_batch file을 가져 오십시오.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>시작하려면 "ffs_batch" file을 가져 오십시오.</target>
<source>Folders to watch:</source>
<target>감시할 폴더:</target>
@@ -755,24 +770,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>시스템: 종료</target>
-<source>Stopped</source>
-<target>중단</target>
-
-<source>Completed with errors</source>
-<target>오류와 함께 완료됨</target>
-
-<source>Completed with warnings</source>
-<target>경고와 함께 완료됨</target>
-
-<source>Warning</source>
-<target>경고</target>
-
<source>Nothing to synchronize</source>
<target>동기화 할 항목이 없습니다</target>
-<source>Completed successfully</source>
-<target>성공적으로 완료됨</target>
-
<source>Executing command %x</source>
<target>%x 명령 실행 중</target>
@@ -823,6 +823,9 @@ The command is triggered if:
<source>Last sync</source>
<target>마지막 동기화</target>
+<source>Log</source>
+<target>로그</target>
+
<source>Folder</source>
<target>폴더</target>
@@ -898,6 +901,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>일괄 작업으로 저장(&b)...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>비교 시작(&C)</target>
@@ -1296,6 +1302,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>영구적으로 숨겨진 모든 대화 상자 및 경고 메세지 다시 보이기</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>컨텍스트 메뉴 커스터마이즈 (사용자 정의):</target>
@@ -1386,6 +1395,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>강조 표시 구성</target>
+<source>Info</source>
+<target>정보</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>모두 선택</target>
+
<source>&Options</source>
<target>옵션(&O)</target>
@@ -1619,21 +1637,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>내용 비교 중...</target>
-<source>Info</source>
-<target>정보</target>
-
-<source>Select all</source>
-<target>모두 선택</target>
-
<source>&Continue</source>
<target>계속(&C)</target>
<source>Progress</source>
<target>진행</target>
-<source>Log</source>
-<target>로그</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>%x님의 기부와 지원에 감사드립니다!</target>
@@ -1856,6 +1865,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>시스템 메시지 수신을 위한 등록을 할 수 없습니다.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x 설치 옵션은 FreeFileSync 기부자 에디션에서만 사용 가능합니다.</target>
+
<source>Cannot find system function %x.</source>
<target>시스템 함수 %x을(를) 찾을 수 없습니다.</target>
@@ -2010,9 +2022,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>로컬 설치 유형을 선택하거나 설치할 다른 폴더를 선택하십시오.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x 설치 옵션은 FreeFileSync 기부자 에디션에서만 사용 가능합니다.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>보너스 기능이 있는 기부자 에디션을 사용하시어 광고없는 FreeFileSync가 유지되도록 도와주세요.</target>
diff --git a/FreeFileSync/Build/Languages/lithuanian.lng b/FreeFileSync/Build/Languages/lithuanian.lng
index 14b24d25..efb1c91f 100755
--- a/FreeFileSync/Build/Languages/lithuanian.lng
+++ b/FreeFileSync/Build/Languages/lithuanian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>bendrinis konfigūracinis failas:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Neribotas kiekis FreeFileSync .ffs_gui ir/arba .ffs_batch konfigūracinių failų.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Neribotas kiekis FreeFileSync "ffs_gui" ir/arba "ffs_batch" konfigūracinių failų.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Bet koks skaičius alternatyvių katalogų grupuojams tik su vienu konfigūraciniu failu.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Atnaujinti atributus dešinėje</target>
+<source>Warning</source>
+<target>Perspėjimas</target>
+
<source>Items processed:</source>
<target>Elementų apdorota:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Visas laikas:</target>
+<source>Stopped</source>
+<target>Sustabdyta</target>
+
<source>Cleaning up log files:</source>
<target>Žurnalinių failų valymas:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Nepavyko prisijungti prie %x.</target>
+<source>Completed successfully</source>
+<target>Sėkmingai užbaigtas</target>
+
+<source>Completed with warnings</source>
+<target>Užbaigtas su perspėjimais</target>
+
+<source>Completed with errors</source>
+<target>Užbaigtas su klaidomis</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Duomenų Šešėlinės Kopijos Paslauga nepasiekiama.</target>
@@ -684,8 +699,8 @@ Esamas: %y baitai
<source>3. Press 'Start'.</source>
<target>3. Spauskite „Pradėti“'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Kad pradėti tiesiog importuokite .ffs_batch failą.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Kad pradėti tiesiog importuokite "ffs_batch" failą.</target>
<source>Folders to watch:</source>
<target>Stebimi aplankai:</target>
@@ -767,24 +782,9 @@ Komanda inicijuojama jei:
<source>System: Shut down</source>
<target>Sistema: Išjungti</target>
-<source>Stopped</source>
-<target>Sustabdyta</target>
-
-<source>Completed with errors</source>
-<target>Užbaigtas su klaidomis</target>
-
-<source>Completed with warnings</source>
-<target>Užbaigtas su perspėjimais</target>
-
-<source>Warning</source>
-<target>Perspėjimas</target>
-
<source>Nothing to synchronize</source>
<target>Nėra ko suvienodinti</target>
-<source>Completed successfully</source>
-<target>Sėkmingai užbaigtas</target>
-
<source>Executing command %x</source>
<target>Vykdyti komandą %x</target>
@@ -837,6 +837,9 @@ Komanda inicijuojama jei:
<source>Last sync</source>
<target>Vėliausias</target>
+<source>Log</source>
+<target>Žurnalas</target>
+
<source>Folder</source>
<target>Aplankas</target>
@@ -912,6 +915,9 @@ Komanda inicijuojama jei:
<source>Save as &batch job...</source>
<target>Išsaugoti kaip &užduočių paketą...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Pradėti &palyginimą</target>
@@ -1310,6 +1316,9 @@ Tai garantuos pastovią buseną, netgi įvykus rimtai klaidai.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Vėl rodyti visus paslėptus dialogo langus ir įspėjamuosius pranešimus</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Pagrindinio meniu pasirinkimai:</target>
@@ -1400,6 +1409,15 @@ Tai garantuos pastovią buseną, netgi įvykus rimtai klaidai.
<source>Highlight Configurations</source>
<target>Pažymėti Nustatymus</target>
+<source>Info</source>
+<target>Informacija</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Pažymėti visus</target>
+
<source>&Options</source>
<target>&Parinktys</target>
@@ -1641,21 +1659,12 @@ Tai garantuos pastovią buseną, netgi įvykus rimtai klaidai.
<source>Comparing content...</source>
<target>Palyginimo turinys...</target>
-<source>Info</source>
-<target>Informacija</target>
-
-<source>Select all</source>
-<target>Pažymėti visus</target>
-
<source>&Continue</source>
<target>&Tęsti</target>
<source>Progress</source>
<target>Pokytis</target>
-<source>Log</source>
-<target>Žurnalas</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Ačiū, %x, už jūsų auką, bei parėmimą!</target>
@@ -1884,6 +1893,9 @@ Tai garantuos pastovią buseną, netgi įvykus rimtai klaidai.
<source>Unable to register to receive system messages.</source>
<target>Nepavyko aktyvuoti sisteminių žinučių gavimo funkciją.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x įdiegiamoji parinktis yra tiktai FreeFileSync Donoro Versijoje.</target>
+
<source>Cannot find system function %x.</source>
<target>Nepavyksta rasti sisteminės funkcijos %x.</target>
@@ -2042,9 +2054,6 @@ Tai garantuos pastovią buseną, netgi įvykus rimtai klaidai.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Prašome pasirinkti vietinio įdiegimo metodą arba pakeiskite aplaką.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x įdiegiamoji parinktis yra tiktai FreeFileSync Donoro Versijoje.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Pasirinkti Parėmimo Versiją su papildomomis funkcijomis ir padėkite išlaikyti FreeFileSync be reklamų.</target>
diff --git a/FreeFileSync/Build/Languages/norwegian.lng b/FreeFileSync/Build/Languages/norwegian.lng
index 1a82aa13..134e2215 100755
--- a/FreeFileSync/Build/Languages/norwegian.lng
+++ b/FreeFileSync/Build/Languages/norwegian.lng
@@ -7,6 +7,15 @@
<plural_definition>n == 1 ? 0 : 1</plural_definition>
</header>
+<source>No log entries</source>
+<target></target>
+
+<source>Remove old log files after x days:</source>
+<target></target>
+
+<source>Show &log</source>
+<target></target>
+
<source>Both sides have changed since last synchronization.</source>
<target>Begge sider er endret siden siste synkronisering.</target>
@@ -100,8 +109,8 @@
<source>global config file:</source>
<target>global innstillingsfil:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Vilkårlig antall FreeFileSync .ffs_gui og/eller .ffs_batch innstillingsfiler.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Vilkårlig antall FreeFileSync "ffs_gui" og/eller "ffs_batch" innstillingsfiler.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Et ubegrenset antall alternative kataloger for maksimalt én konfigurasjonsfil.</target>
@@ -245,7 +254,7 @@
<target>Databasefilene inneholder ennå ikke informasjon om siste synkronisering.</target>
<source>Loading file %x...</source>
-<target>Laster fil %x ...</target>
+<target>Laster fil %x...</target>
<source>Saving file %x...</source>
<target>Lagrer filen %x...</target>
@@ -334,6 +343,9 @@
<source>Update attributes on right</source>
<target>Oppdater attributter til høyre</target>
+<source>Warning</source>
+<target>Advarsel</target>
+
<source>Items processed:</source>
<target>Elementer behandlet:</target>
@@ -343,6 +355,9 @@
<source>Total time:</source>
<target>Samlet tid:</target>
+<source>Stopped</source>
+<target>Stoppet</target>
+
<source>Cleaning up log files:</source>
<target>Sletter loggfiler:</target>
@@ -382,6 +397,15 @@
<source>Unable to connect to %x.</source>
<target>Kan ikke koble til %x.</target>
+<source>Completed successfully</source>
+<target>Fullførte feilfritt</target>
+
+<source>Completed with warnings</source>
+<target>Avsluttet med advarsler</target>
+
+<source>Completed with errors</source>
+<target>Avsluttet med feil</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Volume Shadow Copy-tjenesten er ikke tilgjengelig.</target>
@@ -678,8 +702,8 @@ Faktisk: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Klikk 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Importer en .ffs_batchfil for å komme igang.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Importer en "ffs_batch"fil for å komme igang.</target>
<source>Folders to watch:</source>
<target>Mapper å se på:</target>
@@ -761,24 +785,9 @@ Kommandoen utføres hvis:
<source>System: Shut down</source>
<target>System: Avslutt</target>
-<source>Stopped</source>
-<target>Stoppet</target>
-
-<source>Completed with errors</source>
-<target>Avsluttet med feil</target>
-
-<source>Completed with warnings</source>
-<target>Avsluttet med advarsler</target>
-
-<source>Warning</source>
-<target>Advarsel</target>
-
<source>Nothing to synchronize</source>
<target>Alt er synkronisert</target>
-<source>Completed successfully</source>
-<target>Fullførte feilfritt</target>
-
<source>Executing command %x</source>
<target>Utfør kommandoen %x</target>
@@ -830,6 +839,9 @@ Kommandoen utføres hvis:
<source>Last sync</source>
<target>Sist synkronisert</target>
+<source>Log</source>
+<target>Logg</target>
+
<source>Folder</source>
<target>Mappe</target>
@@ -1268,7 +1280,7 @@ Kommandoen utføres hvis:
<target>Begrens antall loggfiler:</target>
<source>How can I schedule a batch job?</source>
-<target>Hvordan kan jeg lage en batchfil ?</target>
+<target>Hvordan kan jeg lage en batchfil?</target>
<source>&Keep relative paths</source>
<target>&Behold tilknyttede stier</target>
@@ -1393,6 +1405,12 @@ Sikrer prosessen ved alvorlige feil.
<source>Highlight Configurations</source>
<target>Uthev konfigurasjoner</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>Select all</source>
+<target>Velg alt</target>
+
<source>&Options</source>
<target>&Valg</target>
@@ -1630,21 +1648,12 @@ Sikrer prosessen ved alvorlige feil.
<source>Comparing content...</source>
<target>Sammenligner innhold...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Velg alt</target>
-
<source>&Continue</source>
<target>&Fortsett</target>
<source>Progress</source>
<target>Fremskritt</target>
-<source>Log</source>
-<target>Logg</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Takk, %x, for ditt bidrag og støtte!</target>
@@ -1680,8 +1689,8 @@ Sikrer prosessen ved alvorlige feil.
<pluralform>Do you really want to move the following %x items to the recycle bin?</pluralform>
</source>
<target>
-<pluralform>Vil du virkelig flytte følgende element til papirkurven ?</pluralform>
-<pluralform>Vil du virkelig flytte følgende %x elementer til papirkurven ?</pluralform>
+<pluralform>Vil du virkelig flytte følgende element til papirkurven?</pluralform>
+<pluralform>Vil du virkelig flytte følgende %x elementer til papirkurven?</pluralform>
</target>
<source>Move</source>
@@ -1692,8 +1701,8 @@ Sikrer prosessen ved alvorlige feil.
<pluralform>Do you really want to delete the following %x items?</pluralform>
</source>
<target>
-<pluralform>Vil du virkelig slette følgende element ?</pluralform>
-<pluralform>Vil du virkelig slette følgende %x element ?</pluralform>
+<pluralform>Vil du virkelig slette følgende element?</pluralform>
+<pluralform>Vil du virkelig slette følgende %x element?</pluralform>
</target>
<source>Copy DACL, SACL, Owner, Group</source>
@@ -1841,7 +1850,7 @@ Sikrer prosessen ved alvorlige feil.
<target>&Hjemmeside</target>
<source>Download now?</source>
-<target>Last ned nå ?</target>
+<target>Last ned nå?</target>
<source>&Download</source>
<target>&Last ned</target>
@@ -1870,6 +1879,9 @@ Sikrer prosessen ved alvorlige feil.
<source>Unable to register to receive system messages.</source>
<target>Kunne ikke registrere for å motta systembeskjeder.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Installasjonsalternativet %x er bare tilgjengelig i FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Kan ikke finne systemfunksjonen %x.</target>
@@ -1946,7 +1958,7 @@ Sikrer prosessen ved alvorlige feil.
<target>De følgende XML-elementer kunne ikke leses:</target>
<source>Configuration file %x is incomplete. The missing elements will be set to their default values.</source>
-<target>Konfigurasjonsfil %x er ufullstendig. De manglende elementene vil bli satt til standardverdiene .</target>
+<target>Konfigurasjonsfil %x er ufullstendig. De manglende elementene vil bli satt til standardverdiene.</target>
<source>Prepare installation</source>
<target>Forbered installering</target>
@@ -2026,9 +2038,6 @@ Sikrer prosessen ved alvorlige feil.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Velg den lokale installasjonstype eller velge en annen mappe for installasjon.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Installasjonsalternativet %x er bare tilgjengelig i FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Få Donation Edition med bonus-tillegg og hjelp til med å holde FreeFileSync annonsefri.</target>
diff --git a/FreeFileSync/Build/Languages/polish.lng b/FreeFileSync/Build/Languages/polish.lng
index 72e1a41a..e3dd61a9 100755
--- a/FreeFileSync/Build/Languages/polish.lng
+++ b/FreeFileSync/Build/Languages/polish.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>globalny plik konfiguracyjny:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Dowolna ilość plików konfiguracyjnych FreeFileSync .ffs_gui/.ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Dowolna ilość plików konfiguracyjnych FreeFileSync "ffs_gui"/"ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Dowolna liczba alternatywnych par katalogów dla najwyżej jednego pliku konfiguracyjnego.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Aktualizuj atrybuty po prawej stronie</target>
+<source>Warning</source>
+<target>Ostrzeżenie</target>
+
<source>Items processed:</source>
<target>Przetworzone elementy:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Całkowity czas:</target>
+<source>Stopped</source>
+<target>Zatrzymana</target>
+
<source>Cleaning up log files:</source>
<target>Czyszczenie plików logów:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Błąd połączenia do %x.</target>
+<source>Completed successfully</source>
+<target>Zakończono bez błędów</target>
+
+<source>Completed with warnings</source>
+<target>Zakończono z ostrzeżeniami</target>
+
+<source>Completed with errors</source>
+<target>Zakończono z błędami</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Nie można uzyskać dostępu do usługi Volume Shadow Copy.</target>
@@ -684,8 +699,8 @@ Przesłany: %y bajtów
<source>3. Press 'Start'.</source>
<target>3. Wciśnij 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Aby rozpocząć, zaimportuj plik .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Aby rozpocząć, zaimportuj plik "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Katalogi do obserwowania:</target>
@@ -767,24 +782,9 @@ Komenda jest wykonywana gdy:
<source>System: Shut down</source>
<target>System: Wyłączenie</target>
-<source>Stopped</source>
-<target>Zatrzymana</target>
-
-<source>Completed with errors</source>
-<target>Zakończono z błędami</target>
-
-<source>Completed with warnings</source>
-<target>Zakończono z ostrzeżeniami</target>
-
-<source>Warning</source>
-<target>Ostrzeżenie</target>
-
<source>Nothing to synchronize</source>
<target>Brak plików do synchronizacji</target>
-<source>Completed successfully</source>
-<target>Zakończono bez błędów</target>
-
<source>Executing command %x</source>
<target>Wykonywanie polecenia %x</target>
@@ -837,6 +837,9 @@ Komenda jest wykonywana gdy:
<source>Last sync</source>
<target>Ostatnia synchronizacja</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Katalog</target>
@@ -912,6 +915,9 @@ Komenda jest wykonywana gdy:
<source>Save as &batch job...</source>
<target>Zapisz w trybie &wsadowym...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Rozpo&cznij porównywanie</target>
@@ -1310,6 +1316,9 @@ program kopiuje zawartość do pliku tymczasowego (*.ffs_tmp), a następnie nadp
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Przywróć wszystkie, stale ukryte dialogi i powiadomienia</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Dostosuj menu kontekstowe:</target>
@@ -1400,6 +1409,15 @@ program kopiuje zawartość do pliku tymczasowego (*.ffs_tmp), a następnie nadp
<source>Highlight Configurations</source>
<target>Pokaż konfiguracje</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Zaznacz wszystko</target>
+
<source>&Options</source>
<target>&Opcje</target>
@@ -1641,21 +1659,12 @@ program kopiuje zawartość do pliku tymczasowego (*.ffs_tmp), a następnie nadp
<source>Comparing content...</source>
<target>Porównywanie zawartości...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Zaznacz wszystko</target>
-
<source>&Continue</source>
<target>&Kontynuuj</target>
<source>Progress</source>
<target>Postęp</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Dziękujemy %x za Twoje wsparcie!</target>
@@ -1884,6 +1893,9 @@ program kopiuje zawartość do pliku tymczasowego (*.ffs_tmp), a następnie nadp
<source>Unable to register to receive system messages.</source>
<target>Błąd podczas rejestrowania do odbioru komunikatów systemowych.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Opcja instalacyjna %x jest dostępna wyłącznie w wersji FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Nie można odnaleźć funkcji systemowej %x.</target>
@@ -2042,9 +2054,6 @@ program kopiuje zawartość do pliku tymczasowego (*.ffs_tmp), a następnie nadp
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Wybierz lokalny typ instalacji lub określ inny katalog.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Opcja instalacyjna %x jest dostępna wyłącznie w wersji FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Pobierz Donation Edition z funkcjami dodatkowymi i pomóż utrzymać FreeFileSync bez reklam.</target>
diff --git a/FreeFileSync/Build/Languages/portuguese.lng b/FreeFileSync/Build/Languages/portuguese.lng
index 7479c61a..83c0ad21 100755
--- a/FreeFileSync/Build/Languages/portuguese.lng
+++ b/FreeFileSync/Build/Languages/portuguese.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>ficheiro de configuração global:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Qualquer número de ficheiros de configuração .ffs_gui e/ou .ffs_batch do FreeFileSync.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Qualquer número de ficheiros de configuração "ffs_gui" e/ou "ffs_batch" do FreeFileSync.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Qualquer número de pares de directórios alternativos para apenas um ficheiro de configuração.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Actualizar atributos à direita</target>
+<source>Warning</source>
+<target>Atenção</target>
+
<source>Items processed:</source>
<target>Elementos processados:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Tempo total:</target>
+<source>Stopped</source>
+<target>Parado</target>
+
<source>Cleaning up log files:</source>
<target>A limpar ficheiros de registo:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Não é possível conectar-se em %x.</target>
+<source>Completed successfully</source>
+<target>Concluído com sucesso</target>
+
+<source>Completed with warnings</source>
+<target>Concluído com avisos</target>
+
+<source>Completed with errors</source>
+<target>Concluído com erros</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Não é possível aceder ao serviço Volume Shadow Copy.</target>
@@ -678,8 +693,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Pressionar 'Iniciar'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Para começar basta importar um ficheiro .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Para começar basta importar um ficheiro "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Pastas a verificar:</target>
@@ -761,24 +776,9 @@ O comando é executado se:
<source>System: Shut down</source>
<target>Desligar</target>
-<source>Stopped</source>
-<target>Parado</target>
-
-<source>Completed with errors</source>
-<target>Concluído com erros</target>
-
-<source>Completed with warnings</source>
-<target>Concluído com avisos</target>
-
-<source>Warning</source>
-<target>Atenção</target>
-
<source>Nothing to synchronize</source>
<target>Nada a sincronizar</target>
-<source>Completed successfully</source>
-<target>Concluído com sucesso</target>
-
<source>Executing command %x</source>
<target>A executar comando %x</target>
@@ -830,6 +830,9 @@ O comando é executado se:
<source>Last sync</source>
<target>Última sincronia</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Pasta</target>
@@ -905,6 +908,9 @@ O comando é executado se:
<source>Save as &batch job...</source>
<target>Guardar como &batch...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Iniciar &comparação</target>
@@ -1303,6 +1309,9 @@ Isto garante um estado consistente mesmo em caso de falha grave.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Mostrar todos os diálogos escondidos permanentemente e mensagens de aviso novamente</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Personalizar menu de contexto:</target>
@@ -1393,6 +1402,15 @@ Isto garante um estado consistente mesmo em caso de falha grave.
<source>Highlight Configurations</source>
<target>Realçar Configurações</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Seleccionar tudo</target>
+
<source>&Options</source>
<target>&Opções</target>
@@ -1630,21 +1648,12 @@ Isto garante um estado consistente mesmo em caso de falha grave.
<source>Comparing content...</source>
<target>A comparar...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Seleccionar tudo</target>
-
<source>&Continue</source>
<target>&Continuar</target>
<source>Progress</source>
<target>Progresso</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Obrigado, %x, pela sua doação e suporte!</target>
@@ -1870,6 +1879,9 @@ Isto garante um estado consistente mesmo em caso de falha grave.
<source>Unable to register to receive system messages.</source>
<target>Não foi possível registar para receber mensagens do sistema.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>A opção de instalação %x está disponível somente no FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Não é possível encontrar a função do sistema %x.</target>
@@ -2026,9 +2038,6 @@ Isto garante um estado consistente mesmo em caso de falha grave.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Por favor, escolha o tipo do local de instalação ou seleccione uma pasta diferente para instalar.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>A opção de instalação %x está disponível somente no FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Obtenha a Donation Edition com recursos bônus e ajude a manter o FreeFileSync sem anúncios.</target>
diff --git a/FreeFileSync/Build/Languages/portuguese_br.lng b/FreeFileSync/Build/Languages/portuguese_br.lng
index 3d02293d..9b336566 100755
--- a/FreeFileSync/Build/Languages/portuguese_br.lng
+++ b/FreeFileSync/Build/Languages/portuguese_br.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>arquivo de configuração global:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Qualquer número de arquivos FreeFileSync .ffs e/ou de tarefa em lotes .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Qualquer número de arquivos FreeFileSync "ffs_gui" e/ou de tarefa em lotes "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Qualquer número de pares alternativos de diretórios para no máximo um arquivo de configuração.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Atualizar atributos à direita</target>
+<source>Warning</source>
+<target>Aviso</target>
+
<source>Items processed:</source>
<target>Elementos processados:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Tempo total:</target>
+<source>Stopped</source>
+<target>Interrompido</target>
+
<source>Cleaning up log files:</source>
<target>Limpando arquivos de log:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Não foi possível conectar a %x.</target>
+<source>Completed successfully</source>
+<target>Concluído com sucesso</target>
+
+<source>Completed with warnings</source>
+<target>Concluído com avisos</target>
+
+<source>Completed with errors</source>
+<target>Concluído com erros</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Não é possível acessar o Serviço de Cópias de Sombra de Volume.</target>
@@ -678,8 +693,8 @@ Atual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Pressionar 'Iniciar'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Para iniciar importe um arquivo .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Para iniciar importe um arquivo "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Pastas para monitorar:</target>
@@ -761,24 +776,9 @@ O comando é disparado se:
<source>System: Shut down</source>
<target>Sistema: Desligar</target>
-<source>Stopped</source>
-<target>Interrompido</target>
-
-<source>Completed with errors</source>
-<target>Concluído com erros</target>
-
-<source>Completed with warnings</source>
-<target>Concluído com avisos</target>
-
-<source>Warning</source>
-<target>Aviso</target>
-
<source>Nothing to synchronize</source>
<target>Nada para sincronizar</target>
-<source>Completed successfully</source>
-<target>Concluído com sucesso</target>
-
<source>Executing command %x</source>
<target>Executando comando %x</target>
@@ -830,6 +830,9 @@ O comando é disparado se:
<source>Last sync</source>
<target>Últ. Sinc.</target>
+<source>Log</source>
+<target>Log</target>
+
<source>Folder</source>
<target>Pasta</target>
@@ -905,6 +908,9 @@ O comando é disparado se:
<source>Save as &batch job...</source>
<target>Salvar como &tarefa em lotes...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Iniciar &Comparação</target>
@@ -1303,6 +1309,9 @@ Isto garante um estado consistente mesmo em caso de erro grave.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Mostrar todas as caixas de diálogo e as mensagens de aviso permanentemente ocultadas</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Personalizar menu de contexto:</target>
@@ -1393,6 +1402,15 @@ Isto garante um estado consistente mesmo em caso de erro grave.
<source>Highlight Configurations</source>
<target>Realçar Configurações</target>
+<source>Info</source>
+<target>Informações</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Selecionar todos</target>
+
<source>&Options</source>
<target>&Opções</target>
@@ -1630,21 +1648,12 @@ Isto garante um estado consistente mesmo em caso de erro grave.
<source>Comparing content...</source>
<target>Comparando conteúdo...</target>
-<source>Info</source>
-<target>Informações</target>
-
-<source>Select all</source>
-<target>Selecionar todos</target>
-
<source>&Continue</source>
<target>&Continuar</target>
<source>Progress</source>
<target>Progresso</target>
-<source>Log</source>
-<target>Log</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Obrigado, %x, pela sua doação e suporte!</target>
@@ -1870,6 +1879,9 @@ Isto garante um estado consistente mesmo em caso de erro grave.
<source>Unable to register to receive system messages.</source>
<target>Não é possível registrar para receber mensagens do sistema.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>A opção de instalação %x está disponível apenas na Edição do Doador do FreeFileSync.</target>
+
<source>Cannot find system function %x.</source>
<target>Não é possível localizar a função de sistema %x.</target>
@@ -2026,9 +2038,6 @@ Isto garante um estado consistente mesmo em caso de erro grave.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Escolha o tipo de instalação local ou selecione uma pasta diferente para instalação.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>A opção de instalação %x está disponível apenas na Edição do Doador do FreeFileSync.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Obtenha a Edição do Doador com recursos adicionais e ajude a manter o FreeFileSync livre de anúncios.</target>
diff --git a/FreeFileSync/Build/Languages/romanian.lng b/FreeFileSync/Build/Languages/romanian.lng
index f9de2796..7a970005 100755
--- a/FreeFileSync/Build/Languages/romanian.lng
+++ b/FreeFileSync/Build/Languages/romanian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>filă de configurare globală:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Orice număr de file de configurare pentru FreeFileSync, de tipul .ffs_gui sau/și .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Orice număr de file de configurare pentru FreeFileSync, de tipul "ffs_gui" sau/și "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Orice număr de perechi alternative de dosare pentru cel mult o filă de configurare.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Actualizează atributele în partea dreaptă</target>
+<source>Warning</source>
+<target>Atenție</target>
+
<source>Items processed:</source>
<target>Elemente Procesate:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Timp Total:</target>
+<source>Stopped</source>
+<target>Oprită</target>
+
<source>Cleaning up log files:</source>
<target>Curăț filele de jurnalizare:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Nu mă pot conecta la %x.</target>
+<source>Completed successfully</source>
+<target>Realizată cu succes</target>
+
+<source>Completed with warnings</source>
+<target>Realizată cu atenționări</target>
+
+<source>Completed with errors</source>
+<target>Realizată cu erori</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Nu pot accesa Serviciul de Conservare a Volumelor [Volume Shadow Copy].</target>
@@ -684,8 +699,8 @@ Actuală: %y baiți
<source>3. Press 'Start'.</source>
<target>3. Apasă pe 'Pornește'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Pentru a începe, importă o filă de tipul .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Pentru a începe, importă o filă de tipul "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Dosare de Monitorizat:</target>
@@ -767,24 +782,9 @@ Comanda este declanșată dacă:
<source>System: Shut down</source>
<target>Sistem: Închide PC-ul [Shut down]</target>
-<source>Stopped</source>
-<target>Oprită</target>
-
-<source>Completed with errors</source>
-<target>Realizată cu erori</target>
-
-<source>Completed with warnings</source>
-<target>Realizată cu atenționări</target>
-
-<source>Warning</source>
-<target>Atenție</target>
-
<source>Nothing to synchronize</source>
<target>Nu e nimic de sincronizat</target>
-<source>Completed successfully</source>
-<target>Realizată cu succes</target>
-
<source>Executing command %x</source>
<target>Execut comanda %x</target>
@@ -837,6 +837,9 @@ Comanda este declanșată dacă:
<source>Last sync</source>
<target>Ultima Sincr.</target>
+<source>Log</source>
+<target>Jurnal</target>
+
<source>Folder</source>
<target>Dosar</target>
@@ -912,6 +915,9 @@ Comanda este declanșată dacă:
<source>Save as &batch job...</source>
<target>Salvea&ză ca Sarcină Set...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Pornește &Compararea</target>
@@ -1310,6 +1316,9 @@ Aceasta garantează consecvența stării filelor chiar și în cazul apariției
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Sînt arătate din nou dialogurile și mesajele de eroare care au fost ascunse permanent</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Personalizează meniul contextual:</target>
@@ -1400,6 +1409,15 @@ Aceasta garantează consecvența stării filelor chiar și în cazul apariției
<source>Highlight Configurations</source>
<target>Evidențiază Configurațiile</target>
+<source>Info</source>
+<target>Informații</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Selectează Tot</target>
+
<source>&Options</source>
<target>&Opțiuni</target>
@@ -1641,21 +1659,12 @@ Aceasta garantează consecvența stării filelor chiar și în cazul apariției
<source>Comparing content...</source>
<target>Compar conținutul...</target>
-<source>Info</source>
-<target>Informații</target>
-
-<source>Select all</source>
-<target>Selectează Tot</target>
-
<source>&Continue</source>
<target>&Continuă</target>
<source>Progress</source>
<target>Progres</target>
-<source>Log</source>
-<target>Jurnal</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Mulțumesc %x, pentru donație și sprijin!</target>
@@ -1855,7 +1864,7 @@ Aceasta garantează consecvența stării filelor chiar și în cazul apariției
<target>&Situl Softului</target>
<source>Download now?</source>
-<target>Vrei s-o descarci acum ?</target>
+<target>Vrei s-o descarci acum?</target>
<source>&Download</source>
<target>&Descarcă</target>
@@ -1884,6 +1893,9 @@ Aceasta garantează consecvența stării filelor chiar și în cazul apariției
<source>Unable to register to receive system messages.</source>
<target>Nu pot înregistra softul pentru a primi mesaje de la sistemul de operare.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Opțiunea de instalare %x e disponibilă doar pentru FreeFileSync Ediția pentru Donatori.</target>
+
<source>Cannot find system function %x.</source>
<target>Nu pot găsi funcția de sistem %x.</target>
@@ -2042,9 +2054,6 @@ Aceasta garantează consecvența stării filelor chiar și în cazul apariției
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Alege instalarea locală sau selectează un dosar diferit pentru instalare.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Opțiunea de instalare %x e disponibilă doar pentru FreeFileSync Ediția pentru Donatori.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Obține Ediția pentru Donatori cu funcții suplimentare și ajută la menținerea FreeFileSync fără publicitate.</target>
diff --git a/FreeFileSync/Build/Languages/russian.lng b/FreeFileSync/Build/Languages/russian.lng
index 643c49a5..17566e71 100755
--- a/FreeFileSync/Build/Languages/russian.lng
+++ b/FreeFileSync/Build/Languages/russian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>глобальный конфигурационный файл:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Любое количество FreeFileSync .ffs_gui и/или .ffs_batch конфигурационных файлов.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Любое количество FreeFileSync "ffs_gui" и/или "ffs_batch" конфигурационных файлов.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Любое количество альтернативных пар папок для не более одного конфигурационного файла.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Обновление атрибутов справа</target>
+<source>Warning</source>
+<target>Внимание</target>
+
<source>Items processed:</source>
<target>Элементов обработано:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Общее время:</target>
+<source>Stopped</source>
+<target>Остановлено</target>
+
<source>Cleaning up log files:</source>
<target>Очистка лог-файлов (журналов):</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Невозможно соединиться с %x.</target>
+<source>Completed successfully</source>
+<target>Выполнено успешно</target>
+
+<source>Completed with warnings</source>
+<target>Выполнено с предупреждениями</target>
+
+<source>Completed with errors</source>
+<target>Выполнено с ошибками</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Невозможно получить доступ к службе Теневого Копирования Тома.</target>
@@ -684,8 +699,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Нажмите 'Старт'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Для запуска просто импортируйте файл .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Для запуска просто импортируйте файл "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Папки для наблюдения:</target>
@@ -767,24 +782,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>Система: Завершение работы</target>
-<source>Stopped</source>
-<target>Остановлено</target>
-
-<source>Completed with errors</source>
-<target>Выполнено с ошибками</target>
-
-<source>Completed with warnings</source>
-<target>Выполнено с предупреждениями</target>
-
-<source>Warning</source>
-<target>Внимание</target>
-
<source>Nothing to synchronize</source>
<target>Ничего нет для синхронизации</target>
-<source>Completed successfully</source>
-<target>Выполнено успешно</target>
-
<source>Executing command %x</source>
<target>Выполнение команды %x</target>
@@ -837,6 +837,9 @@ The command is triggered if:
<source>Last sync</source>
<target>Последняя синхронизация</target>
+<source>Log</source>
+<target>Лог (журнал)</target>
+
<source>Folder</source>
<target>Папка</target>
@@ -912,6 +915,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>Сохранить как пакетное &задание...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Начать с&равнение</target>
@@ -1310,6 +1316,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Показать все скрытые окна и сообщения с предупреждениями снова</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Кастомизация контекстного меню:</target>
@@ -1400,6 +1409,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Выделение конфигураций</target>
+<source>Info</source>
+<target>Информация</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Выделить все</target>
+
<source>&Options</source>
<target>&Настройки</target>
@@ -1641,21 +1659,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Сравнение содержания...</target>
-<source>Info</source>
-<target>Информация</target>
-
-<source>Select all</source>
-<target>Выделить все</target>
-
<source>&Continue</source>
<target>&Продолжить</target>
<source>Progress</source>
<target>Прогресс</target>
-<source>Log</source>
-<target>Лог (журнал)</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Благодарим вас, %x, за пожертвование и поддержку!</target>
@@ -1884,6 +1893,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Невозможно зарегистрироваться для получения системных сообщений.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x опция установки доступна только в платной версии FreeFileSync.</target>
+
<source>Cannot find system function %x.</source>
<target>Невозможно найти системную функцию %x.</target>
@@ -2042,9 +2054,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Пожалуйста, выберите локальный тип установки или выберите другую папку для установки.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x опция установки доступна только в платной версии FreeFileSync.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Приобретите платную версию FreeFileSync с бонусными функциями и помогите сохранить FreeFileSync свободным от рекламы.</target>
diff --git a/FreeFileSync/Build/Languages/slovak.lng b/FreeFileSync/Build/Languages/slovak.lng
index 82d56212..4d296d17 100755
--- a/FreeFileSync/Build/Languages/slovak.lng
+++ b/FreeFileSync/Build/Languages/slovak.lng
@@ -50,7 +50,7 @@
<target>Zmazanie symbolického odkazu %x</target>
<source>Checking recycle bin availability for folder %x...</source>
-<target>Kontrola Koša pre priečinok %x ...</target>
+<target>Kontrola Koša pre priečinok %x...</target>
<source>The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:</source>
<target>Premiestnenie do Koša nie je možné pri nasledujúcich priečinkoch. Zmazané alebo prepísané súbory nebude možné obnoviť:</target>
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>globálny konfiguračný súbor:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Ľubovolný počet konfiguračných súborov FreeFileSync typu .ffs_gui a/alebo .ffs_batch.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Ľubovolný počet konfiguračných súborov FreeFileSync typu "ffs_gui" a/alebo "ffs_batch".</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Ľubovolný počet alternatívnych dvojíc adresárov na aspoň jednu konfiguráciu.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Aktualizovať atribúty napravo</target>
+<source>Warning</source>
+<target>Varovanie</target>
+
<source>Items processed:</source>
<target>Spracovaných položiek:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Celkový čas:</target>
+<source>Stopped</source>
+<target>Zastavené</target>
+
<source>Cleaning up log files:</source>
<target>Odstránenie log súborov:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Nie je možné vytvoriť pripojenie k %x.</target>
+<source>Completed successfully</source>
+<target>Dokončenie bolo úspešné</target>
+
+<source>Completed with warnings</source>
+<target>Ukončené s varovaniami</target>
+
+<source>Completed with errors</source>
+<target>Ukončené s chybami</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Nie je prístup k službe Tieňové kópie.</target>
@@ -684,8 +699,8 @@ Aktuálne: %y b
<source>3. Press 'Start'.</source>
<target>3. Stlačte 'Štart'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Môžete načítať tiež konfiguračný súbor .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Môžete načítať tiež konfiguračný súbor "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Sledované priečinka:</target>
@@ -767,24 +782,9 @@ Príkaz bude spustení ak:
<source>System: Shut down</source>
<target>Systém: Vypnúť</target>
-<source>Stopped</source>
-<target>Zastavené</target>
-
-<source>Completed with errors</source>
-<target>Ukončené s chybami</target>
-
-<source>Completed with warnings</source>
-<target>Ukončené s varovaniami</target>
-
-<source>Warning</source>
-<target>Varovanie</target>
-
<source>Nothing to synchronize</source>
<target>Nie je čo synchronizovať</target>
-<source>Completed successfully</source>
-<target>Dokončenie bolo úspešné</target>
-
<source>Executing command %x</source>
<target>Spúšťací príkaz %x</target>
@@ -837,6 +837,9 @@ Príkaz bude spustení ak:
<source>Last sync</source>
<target>Posledná synchronizácia</target>
+<source>Log</source>
+<target>Záznam spracovania</target>
+
<source>Folder</source>
<target>Priečinok</target>
@@ -912,6 +915,9 @@ Príkaz bude spustení ak:
<source>Save as &batch job...</source>
<target>Uložiť ako &dávku...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Spustiť &porovnanie</target>
@@ -1307,6 +1313,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Zobraziť znovu všetky trvale skryté dialógy a varovné hlásenia</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Prispôsobiť kontextovú ponuku:</target>
@@ -1397,6 +1406,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Zvýrazniť konfigurácie</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Vybrať všetko</target>
+
<source>&Options</source>
<target>Nastavenie &programu</target>
@@ -1621,7 +1639,7 @@ This guarantees a consistent state even in case of a serious error.
<target>Zoznam súborov bol exportovaný</target>
<source>Searching for program updates...</source>
-<target>Hľadanie aktualizácií programu ...</target>
+<target>Hľadanie aktualizácií programu...</target>
<source>Paused</source>
<target>Pauza</target>
@@ -1638,21 +1656,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Porovnávanie obsahu...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Vybrať všetko</target>
-
<source>&Continue</source>
<target>&Pokračovať</target>
<source>Progress</source>
<target>Priebeh</target>
-<source>Log</source>
-<target>Záznam spracovania</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Ďakujem, %x, za dar a podporu!</target>
@@ -1881,6 +1890,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Nepodarilo sa registrovať k odberu systémových správ.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Inštalačná možnosť %x je dostupná iba pri FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Nie je možné nájsť systémovú funkciu %x.</target>
@@ -2039,9 +2051,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Prosím zvoľte lokálny typ inštalácie alebo vyberte iný priečinok pre inštaláciu.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Inštalačná možnosť %x je dostupná iba pri FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Získajte Donation Edition s bonusovými funkciami a pomôžte, aby ostal FreeFileSync bez reklami.</target>
diff --git a/FreeFileSync/Build/Languages/slovenian.lng b/FreeFileSync/Build/Languages/slovenian.lng
index 161410d4..8dc2eea4 100755
--- a/FreeFileSync/Build/Languages/slovenian.lng
+++ b/FreeFileSync/Build/Languages/slovenian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>datoteka z globalnimi konfiguracijami:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Poljubno število FreeFileSync .ffs_gui in/ali .ffs_batch nastavitvenih datotek.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Poljubno število FreeFileSync "ffs_gui" in/ali "ffs_batch" nastavitvenih datotek.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Poljubno število alternativnih parov imenikov za največ eno nastavitveno datoteko.</target>
@@ -338,6 +338,9 @@
<source>Update attributes on right</source>
<target>Posodobi atribute na desni strani</target>
+<source>Warning</source>
+<target>Opozorilo</target>
+
<source>Items processed:</source>
<target>Obdelanih postavk:</target>
@@ -347,6 +350,9 @@
<source>Total time:</source>
<target>Celoten čas:</target>
+<source>Stopped</source>
+<target>Ustavljeno</target>
+
<source>Cleaning up log files:</source>
<target>Čiščenje datotek dnevnika:</target>
@@ -388,6 +394,15 @@
<source>Unable to connect to %x.</source>
<target>Ne morem povezati na %x.</target>
+<source>Completed successfully</source>
+<target>Uspešno končano</target>
+
+<source>Completed with warnings</source>
+<target>Dokončano z opozorili</target>
+
+<source>Completed with errors</source>
+<target>Dokončano z napakami</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Ne morem dostopati do Volume Shadov Copy storitve.</target>
@@ -690,8 +705,8 @@ Dejansko: %y bajtov
<source>3. Press 'Start'.</source>
<target>3. Pritisnite 'Začni'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Če želite začeti, uvozite datoteko .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Če želite začeti, uvozite datoteko "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Mape za pregled:</target>
@@ -773,24 +788,9 @@ Ukaz se sproži če:
<source>System: Shut down</source>
<target>Sistem: Izključi računalnik</target>
-<source>Stopped</source>
-<target>Ustavljeno</target>
-
-<source>Completed with errors</source>
-<target>Dokončano z napakami</target>
-
-<source>Completed with warnings</source>
-<target>Dokončano z opozorili</target>
-
-<source>Warning</source>
-<target>Opozorilo</target>
-
<source>Nothing to synchronize</source>
<target>Nič za sinhroniziranje</target>
-<source>Completed successfully</source>
-<target>Uspešno končano</target>
-
<source>Executing command %x</source>
<target>Izvedba ukaza %x</target>
@@ -844,6 +844,9 @@ Ukaz se sproži če:
<source>Last sync</source>
<target>Zadnja sinhronizacija</target>
+<source>Log</source>
+<target>Dnevnik</target>
+
<source>Folder</source>
<target>Mapa</target>
@@ -919,6 +922,9 @@ Ukaz se sproži če:
<source>Save as &batch job...</source>
<target>Shrani kot paketno op&ravilo...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Začni &primerjavo</target>
@@ -1317,6 +1323,9 @@ To zagotavlja dosledno stanje tudi v primeru resne napake.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Prikaži vsa trajno skrita pogovorna okna in opozorilna sporočila</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Prilagodi kontekstni meni:</target>
@@ -1407,6 +1416,15 @@ To zagotavlja dosledno stanje tudi v primeru resne napake.
<source>Highlight Configurations</source>
<target>Označite konfiguracije</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Izberi vse</target>
+
<source>&Options</source>
<target>&Možnosti</target>
@@ -1652,21 +1670,12 @@ To zagotavlja dosledno stanje tudi v primeru resne napake.
<source>Comparing content...</source>
<target>Primerjam vsebino...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Izberi vse</target>
-
<source>&Continue</source>
<target>&Nadaljuj</target>
<source>Progress</source>
<target>Napredek</target>
-<source>Log</source>
-<target>Dnevnik</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Najlepša hvala, %x, za vašo donacijo in podporo!</target>
@@ -1898,6 +1907,9 @@ To zagotavlja dosledno stanje tudi v primeru resne napake.
<source>Unable to register to receive system messages.</source>
<target>Sistemskih sporočil ni mogoče registrirati.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Možnost namestitve %x je na voljo samo v FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Sistemske funkcije ni mogoče najti %x.</target>
@@ -2058,9 +2070,6 @@ To zagotavlja dosledno stanje tudi v primeru resne napake.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Prosimo izberite vrsto lokalne namestitve ali pa izberite drugo mapo za namestitev.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Možnost namestitve %x je na voljo samo v FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Pridobite donacijsko izdajo s bonusnimi funkcijami in pomagajte ohraniti FreeFileSync brez oglasov.</target>
diff --git a/FreeFileSync/Build/Languages/spanish.lng b/FreeFileSync/Build/Languages/spanish.lng
index 4389baa6..d539e749 100755
--- a/FreeFileSync/Build/Languages/spanish.lng
+++ b/FreeFileSync/Build/Languages/spanish.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>archivo de config. global:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Cualquier número de archivos de configuración de FreeFileSync (.ffs_gui ó .ffs_batch).</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Cualquier número de archivos de configuración de FreeFileSync ("ffs_gui" ó "ffs_batch").</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Cualquier número de pares de directorios alternativos para un archivo de configuración como máximo.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Actualizar atributos en la derecha</target>
+<source>Warning</source>
+<target>Atención</target>
+
<source>Items processed:</source>
<target>Elementos procesados:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Tiempo total:</target>
+<source>Stopped</source>
+<target>Detenido</target>
+
<source>Cleaning up log files:</source>
<target>Limpiando archivos de registro:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>No se puede conectar a %x.</target>
+<source>Completed successfully</source>
+<target>Completado con éxito</target>
+
+<source>Completed with warnings</source>
+<target>Completado con avisos</target>
+
+<source>Completed with errors</source>
+<target>Completado con errores</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>No se puede acceder al servicio de Instantánea de volumen.</target>
@@ -678,8 +693,8 @@ Reales: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Presione 'Inicio'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Para comenzar, importe un archivo .ffs_batch.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Para comenzar, importe un archivo "ffs_batch".</target>
<source>Folders to watch:</source>
<target>Carpetas para examinar:</target>
@@ -761,24 +776,9 @@ El comando es disparado si:
<source>System: Shut down</source>
<target>Sistema: apagar</target>
-<source>Stopped</source>
-<target>Detenido</target>
-
-<source>Completed with errors</source>
-<target>Completado con errores</target>
-
-<source>Completed with warnings</source>
-<target>Completado con avisos</target>
-
-<source>Warning</source>
-<target>Atención</target>
-
<source>Nothing to synchronize</source>
<target>Nada que sincronizar</target>
-<source>Completed successfully</source>
-<target>Completado con éxito</target>
-
<source>Executing command %x</source>
<target>Ejecución del comando %x</target>
@@ -830,6 +830,9 @@ El comando es disparado si:
<source>Last sync</source>
<target>Última sincronización</target>
+<source>Log</source>
+<target>Registro</target>
+
<source>Folder</source>
<target>Carpeta</target>
@@ -905,6 +908,9 @@ El comando es disparado si:
<source>Save as &batch job...</source>
<target>Guardar como tarea por &lotes...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Iniciar la &comparación</target>
@@ -1241,10 +1247,10 @@ El comando es disparado si:
<target>Detener</target>
<source>Create a batch file for unattended synchronization. To start, double-click this file or schedule in a task planner: %x</source>
-<target>Crear tarea por lotes para sincronización desatendida. Para iniciar, haga doble clic en este archivo o prográmelo en el planificador de tareas : %x</target>
+<target>Crear tarea por lotes para sincronización desatendida. Para iniciar, haga doble clic en este archivo o prográmelo en el planificador de tareas: %x</target>
<source>Progress dialog:</source>
-<target>Diálogo de progreso:</target>
+<target>Diálogo de progreson:</target>
<source>Run minimized</source>
<target>Ejecutar minimizado</target>
@@ -1303,8 +1309,11 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Volver a mostrar todos los diálogos y mensajes de advertencia que fueron permanentemente ocultados</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
-<target>Personalizar menú contextual :</target>
+<target>Personalizar menú contextual:</target>
<source>Description</source>
<target>Descripción</target>
@@ -1313,7 +1322,7 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<target>&Configuración predeterminada</target>
<source>Feedback and suggestions are welcome</source>
-<target>Tus comentarios y sugerencias son bienvenidos :</target>
+<target>Tus comentarios y sugerencias son bienvenidos:</target>
<source>Home page</source>
<target>Página de inicio</target>
@@ -1337,13 +1346,13 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<target>Detalles para donación</target>
<source>Source code written in C++ using:</source>
-<target>Código fuente C++ con soporte de :</target>
+<target>Código fuente C++ con soporte de:</target>
<source>Published under the GNU General Public License</source>
-<target>Publicado bajo régimen de derechos GNU General Public License :</target>
+<target>Publicado bajo régimen de derechos GNU General Public License:</target>
<source>Many thanks for localization:</source>
-<target>Agradecimientos a los traductores :</target>
+<target>Agradecimientos a los traductores:</target>
<source>Activate the FreeFileSync Donation Edition by one of the following methods:</source>
<target>Active FreeFileSync Donation Edition por uno de los métodos siguientes:</target>
@@ -1355,7 +1364,7 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<target>Activar en línea</target>
<source>2. Retrieve an offline activation key from the following URL:</source>
-<target>2. Recuperar una clave de activación sin conexión desde la dirección URL siguiente :</target>
+<target>2. Recuperar una clave de activación sin conexión desde la dirección URL siguiente:</target>
<source>&Copy to clipboard</source>
<target>&Copiar al portapapeles</target>
@@ -1393,6 +1402,15 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<source>Highlight Configurations</source>
<target>Resaltar configuraciones</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Seleccionar todo</target>
+
<source>&Options</source>
<target>&Opciones</target>
@@ -1630,21 +1648,12 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<source>Comparing content...</source>
<target>Comparando contenido...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Seleccionar todo</target>
-
<source>&Continue</source>
<target>&Continuar</target>
<source>Progress</source>
<target>Progreso</target>
-<source>Log</source>
-<target>Registro</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>¡Muchas gracias, %x, por su contribución y ayuda!</target>
@@ -1870,6 +1879,9 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<source>Unable to register to receive system messages.</source>
<target>No es posible registrar la recepción de mensajes sistema.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>La opción %x de instalación sólo está disponible para la versión FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>No se puede encontrar la función del sistema %x.</target>
@@ -1943,7 +1955,7 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<target>Fallo al comprobar la papelera de reciclaje para la carpeta %x.</target>
<source>The following XML elements could not be read:</source>
-<target>No se pueden leer los siguientes elementos XML :</target>
+<target>No se pueden leer los siguientes elementos XML:</target>
<source>Configuration file %x is incomplete. The missing elements will be set to their default values.</source>
<target>El archivo de configuración %x está incompleto. Los elementos ausentes se definirán con valores predeterminados.</target>
@@ -2026,9 +2038,6 @@ Esto garantiza un estado coherente incluso en caso de error grave.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Elija el tipo de instalación local o seleccione otra carpeta de instalación.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>La opción %x de instalación sólo está disponible para la versión FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Obtenga la FreeFileSync Donation Edition con sus características extra y ayude a mantener FreeFileSync libre de anuncios.</target>
diff --git a/FreeFileSync/Build/Languages/swedish.lng b/FreeFileSync/Build/Languages/swedish.lng
index 10151ff7..ee21b7ee 100755
--- a/FreeFileSync/Build/Languages/swedish.lng
+++ b/FreeFileSync/Build/Languages/swedish.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>övergripande konfigurationsfil:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Valfritt antal FreeFileSync .ffs_gui och/eller .ffs_batch konfigurationsfiler.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Valfritt antal FreeFileSync "ffs_gui" och/eller "ffs_batch" konfigurationsfiler.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Valfritt antal alternativa katalogpar för som mest, en konfigurationsfil.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Uppdatera attribut på höger sida</target>
+<source>Warning</source>
+<target>Varning</target>
+
<source>Items processed:</source>
<target>Processade poster:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Total tid:</target>
+<source>Stopped</source>
+<target>Stoppad</target>
+
<source>Cleaning up log files:</source>
<target>Städar upp loggfiler:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>Kan inte ansluta till %x.</target>
+<source>Completed successfully</source>
+<target>Korrekt slutförd</target>
+
+<source>Completed with warnings</source>
+<target>Slutförd med varningar</target>
+
+<source>Completed with errors</source>
+<target>Slutförd med fel</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Kan inte komma åt tjänsten 'Volume Shadow Copy'.</target>
@@ -678,8 +693,8 @@ Aktuell: %y byte
<source>3. Press 'Start'.</source>
<target>3. Tryck 'Start'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Importera en .ffs_batch-fil för att komma igång.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Importera en "ffs_batch"-fil för att komma igång.</target>
<source>Folders to watch:</source>
<target>Mappar att övervaka:</target>
@@ -761,24 +776,9 @@ Kommandot triggas om:
<source>System: Shut down</source>
<target>System: Stäng av</target>
-<source>Stopped</source>
-<target>Stoppad</target>
-
-<source>Completed with errors</source>
-<target>Slutförd med fel</target>
-
-<source>Completed with warnings</source>
-<target>Slutförd med varningar</target>
-
-<source>Warning</source>
-<target>Varning</target>
-
<source>Nothing to synchronize</source>
<target>Det finns inget att synkronisera</target>
-<source>Completed successfully</source>
-<target>Korrekt slutförd</target>
-
<source>Executing command %x</source>
<target>Kör kommandot %x</target>
@@ -830,6 +830,9 @@ Kommandot triggas om:
<source>Last sync</source>
<target>Senaste synkronisering</target>
+<source>Log</source>
+<target>Logg</target>
+
<source>Folder</source>
<target>Mapp</target>
@@ -905,6 +908,9 @@ Kommandot triggas om:
<source>Save as &batch job...</source>
<target>Spara som &batch-fil...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>&Jämför</target>
@@ -1303,6 +1309,9 @@ Detta garanterar ett konsekvent tillstånd även vid allvarliga fel.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Visa alla permanent dolda dialoger och varningsmeddelanden igen</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Anpassad kontextmeny:</target>
@@ -1393,6 +1402,15 @@ Detta garanterar ett konsekvent tillstånd även vid allvarliga fel.
<source>Highlight Configurations</source>
<target>Färgmarkera konfigurationer</target>
+<source>Info</source>
+<target>Info</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Markera alla</target>
+
<source>&Options</source>
<target>&Alternativ</target>
@@ -1630,21 +1648,12 @@ Detta garanterar ett konsekvent tillstånd även vid allvarliga fel.
<source>Comparing content...</source>
<target>Jämför innehåll...</target>
-<source>Info</source>
-<target>Info</target>
-
-<source>Select all</source>
-<target>Markera alla</target>
-
<source>&Continue</source>
<target>&Fortsätt</target>
<source>Progress</source>
<target>Förlopp</target>
-<source>Log</source>
-<target>Logg</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Tack %x, för din donation och ditt stöd!</target>
@@ -1870,6 +1879,9 @@ Detta garanterar ett konsekvent tillstånd även vid allvarliga fel.
<source>Unable to register to receive system messages.</source>
<target>Det gick inte att registrera mottagning av systemmeddelanden.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Installationsalternativet %x är endast tillgängligt i FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Kan inte hitta systemfunktion %x.</target>
@@ -2026,9 +2038,6 @@ Detta garanterar ett konsekvent tillstånd även vid allvarliga fel.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Välj lokal installationstyp eller välj en annan mapp för installationen.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Installationsalternativet %x är endast tillgängligt i FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Hämta donationsversionen med bonusfunktioner och hjälp till att hålla FreeFileSync reklamfri.</target>
diff --git a/FreeFileSync/Build/Languages/turkish.lng b/FreeFileSync/Build/Languages/turkish.lng
index a61cd83b..e4c3a9fd 100755
--- a/FreeFileSync/Build/Languages/turkish.lng
+++ b/FreeFileSync/Build/Languages/turkish.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>genel yapılandırma dosyası:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>FreeFileSync .ffs_gui ya da .ffs_batch yapılandırma dosyalarının sayısı.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>FreeFileSync "ffs_gui" ya da "ffs_batch" yapılandırma dosyalarının sayısı.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>En fazla bir yapılandırma dosyası için herhangi bir sayıda alternatif klasör çifti.</target>
@@ -334,6 +334,9 @@
<source>Update attributes on right</source>
<target>Sağdaki öznitelikler güncellensin</target>
+<source>Warning</source>
+<target>Uyarı</target>
+
<source>Items processed:</source>
<target>İşlenen öge:</target>
@@ -343,6 +346,9 @@
<source>Total time:</source>
<target>Toplam süre:</target>
+<source>Stopped</source>
+<target>Durduruldu</target>
+
<source>Cleaning up log files:</source>
<target>Günlük dosyaları temizleniyor:</target>
@@ -382,6 +388,15 @@
<source>Unable to connect to %x.</source>
<target>%x üzerine bağlanılamadı.</target>
+<source>Completed successfully</source>
+<target>Tamamlandı</target>
+
+<source>Completed with warnings</source>
+<target>Uyarılar ile tamamlandı</target>
+
+<source>Completed with errors</source>
+<target>Sorunlar ile tamamlandı</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Birim Gölge Hizmetine erişilemiyor.</target>
@@ -479,7 +494,7 @@
<target>Şu klasörler birbirinden çok farklı. Lütfen eşitleme için doğru klasörleri seçtiğinizden emin olun.</target>
<source>Not enough free disk space available in:</source>
-<target>Şurada yeterli disk alanı yok :</target>
+<target>Şurada yeterli disk alanı yok:</target>
<source>Required:</source>
<target>Zorunlu:</target>
@@ -678,8 +693,8 @@ Gerçekleşen: %y bayt
<source>3. Press 'Start'.</source>
<target>3. 'Başlat' düğmesine tıklayın.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>.ffs_batch dosyasını yükleyerek başlayabilirsiniz.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>"ffs_batch" dosyasını yükleyerek başlayabilirsiniz.</target>
<source>Folders to watch:</source>
<target>İzlenecek Klasörler:</target>
@@ -761,24 +776,9 @@ Komut şu durumlarda yürütülür:
<source>System: Shut down</source>
<target>Sistem: Kapat</target>
-<source>Stopped</source>
-<target>Durduruldu</target>
-
-<source>Completed with errors</source>
-<target>Sorunlar ile tamamlandı</target>
-
-<source>Completed with warnings</source>
-<target>Uyarılar ile tamamlandı</target>
-
-<source>Warning</source>
-<target>Uyarı</target>
-
<source>Nothing to synchronize</source>
<target>Eşitlenecek bir şey yok</target>
-<source>Completed successfully</source>
-<target>Tamamlandı</target>
-
<source>Executing command %x</source>
<target>%x komutu yürütülüyor</target>
@@ -830,6 +830,9 @@ Komut şu durumlarda yürütülür:
<source>Last sync</source>
<target>Son eşitleme</target>
+<source>Log</source>
+<target>Günlük</target>
+
<source>Folder</source>
<target>Klasör</target>
@@ -905,6 +908,9 @@ Komut şu durumlarda yürütülür:
<source>Save as &batch job...</source>
<target>&Toplu İş Olarak Kaydet...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>&Karşılaştırmayı Başlat</target>
@@ -1303,6 +1309,9 @@ Bu yöntem, ciddi bir sorun çıkması durumunda bile işlemin tutarlı olarak y
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Kalıcı olarak gizlenmiş tüm ileti ve uyarılar yeniden görüntülenir</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Sağ Tık Menüsü Uyarlamaları:</target>
@@ -1393,6 +1402,15 @@ Bu yöntem, ciddi bir sorun çıkması durumunda bile işlemin tutarlı olarak y
<source>Highlight Configurations</source>
<target>Yapılandırmalar Vurgulansın</target>
+<source>Info</source>
+<target>Bilgi</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Tümünü Seç</target>
+
<source>&Options</source>
<target>&Ayarlar</target>
@@ -1630,21 +1648,12 @@ Bu yöntem, ciddi bir sorun çıkması durumunda bile işlemin tutarlı olarak y
<source>Comparing content...</source>
<target>İçerik karşılaştırılıyor...</target>
-<source>Info</source>
-<target>Bilgi</target>
-
-<source>Select all</source>
-<target>Tümünü Seç</target>
-
<source>&Continue</source>
<target>&Devam</target>
<source>Progress</source>
<target>İlerleme</target>
-<source>Log</source>
-<target>Günlük</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Sevgili %x, bağışın ve desteğin için teşekkürler!</target>
@@ -1870,6 +1879,9 @@ Bu yöntem, ciddi bir sorun çıkması durumunda bile işlemin tutarlı olarak y
<source>Unable to register to receive system messages.</source>
<target>Sistem iletilerini alabilmek için gerekli kayıt eklenemedi.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>%x kurulumu yalnız FreeFileSync Donation Sürümü ile yapılabilir.</target>
+
<source>Cannot find system function %x.</source>
<target>%x sistem işlevi bulunamadı.</target>
@@ -2026,9 +2038,6 @@ Bu yöntem, ciddi bir sorun çıkması durumunda bile işlemin tutarlı olarak y
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Kurulum için farklı bir klasör ya da yerel kurulum türünü seçin.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>%x kurulumu yalnız FreeFileSync Donation Sürümü ile yapılabilir.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Hediye özellikleri edinmek ve FreeFileSync yazılımını reklamsız kullanmak için Bağış Sürümünü alın.</target>
diff --git a/FreeFileSync/Build/Languages/ukrainian.lng b/FreeFileSync/Build/Languages/ukrainian.lng
index 46342c15..a095fe89 100755
--- a/FreeFileSync/Build/Languages/ukrainian.lng
+++ b/FreeFileSync/Build/Languages/ukrainian.lng
@@ -100,8 +100,8 @@
<source>global config file:</source>
<target>глобальний конфігураційний файл:</target>
-<source>Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.</source>
-<target>Будь-яка кількість FreeFileSync .ffs_gui та/або .ffs_batch файлів конфігурації.</target>
+<source>Any number of FreeFileSync "ffs_gui" and/or "ffs_batch" configuration files.</source>
+<target>Будь-яка кількість FreeFileSync "ffs_gui" та/або "ffs_batch" файлів конфігурації.</target>
<source>Any number of alternative directory pairs for at most one config file.</source>
<target>Будь-яка кількість альтернативних пар папок для не більше одного конфігураційного файлу.</target>
@@ -336,6 +336,9 @@
<source>Update attributes on right</source>
<target>Оновити атрибути праворуч</target>
+<source>Warning</source>
+<target>Увага</target>
+
<source>Items processed:</source>
<target>Елементів оброблено:</target>
@@ -345,6 +348,9 @@
<source>Total time:</source>
<target>Загальний час:</target>
+<source>Stopped</source>
+<target>Зупинено</target>
+
<source>Cleaning up log files:</source>
<target>Очищення файлів журналу:</target>
@@ -385,6 +391,15 @@
<source>Unable to connect to %x.</source>
<target>Не вдається з'єднатися з %x.</target>
+<source>Completed successfully</source>
+<target>Завершено успішно</target>
+
+<source>Completed with warnings</source>
+<target>Завершено з попередженнями</target>
+
+<source>Completed with errors</source>
+<target>Завершено з помилками</target>
+
<source>Cannot access the Volume Shadow Copy Service.</source>
<target>Не вдається отримати доступ до послуги Тіньового Копіювання Тому.</target>
@@ -684,8 +699,8 @@ Actual: %y bytes
<source>3. Press 'Start'.</source>
<target>3. Натисніть 'Запуск'.</target>
-<source>To get started just import a .ffs_batch file.</source>
-<target>Щоб запустити імпортуйте .ffs_batch файл.</target>
+<source>To get started just import a "ffs_batch" file.</source>
+<target>Щоб запустити імпортуйте "ffs_batch" файл.</target>
<source>Folders to watch:</source>
<target>Папки для спостереження:</target>
@@ -767,24 +782,9 @@ The command is triggered if:
<source>System: Shut down</source>
<target>Система: Завершення роботи</target>
-<source>Stopped</source>
-<target>Зупинено</target>
-
-<source>Completed with errors</source>
-<target>Завершено з помилками</target>
-
-<source>Completed with warnings</source>
-<target>Завершено з попередженнями</target>
-
-<source>Warning</source>
-<target>Увага</target>
-
<source>Nothing to synchronize</source>
<target>Нічого синхронізувати</target>
-<source>Completed successfully</source>
-<target>Завершено успішно</target>
-
<source>Executing command %x</source>
<target>Виконати команду %x</target>
@@ -837,6 +837,9 @@ The command is triggered if:
<source>Last sync</source>
<target>Остання синхронізація</target>
+<source>Log</source>
+<target>Лог</target>
+
<source>Folder</source>
<target>Папка</target>
@@ -912,6 +915,9 @@ The command is triggered if:
<source>Save as &batch job...</source>
<target>Зберегти як &пакетне завдання...</target>
+<source>Show &log</source>
+<target></target>
+
<source>Start &comparison</source>
<target>Запуск по&рівняння</target>
@@ -1310,6 +1316,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Show all permanently hidden dialogs and warning messages again</source>
<target>Показати всі сховані діалоги і повідомлення з попередженнями знову</target>
+<source>Remove old log files after x days:</source>
+<target></target>
+
<source>Customize context menu:</source>
<target>Налаштування контекстного меню:</target>
@@ -1400,6 +1409,15 @@ This guarantees a consistent state even in case of a serious error.
<source>Highlight Configurations</source>
<target>Налаштування виділення</target>
+<source>Info</source>
+<target>Інформація</target>
+
+<source>No log entries</source>
+<target></target>
+
+<source>Select all</source>
+<target>Виділити все</target>
+
<source>&Options</source>
<target>&Опції</target>
@@ -1624,7 +1642,7 @@ This guarantees a consistent state even in case of a serious error.
<target>Список файлів експортовано</target>
<source>Searching for program updates...</source>
-<target>Пошук оновлень програми ...</target>
+<target>Пошук оновлень програми...</target>
<source>Paused</source>
<target>Призупинено</target>
@@ -1641,21 +1659,12 @@ This guarantees a consistent state even in case of a serious error.
<source>Comparing content...</source>
<target>Порівнювання вмісту...</target>
-<source>Info</source>
-<target>Інформація</target>
-
-<source>Select all</source>
-<target>Виділити все</target>
-
<source>&Continue</source>
<target>&Продовжити</target>
<source>Progress</source>
<target>Прогрес</target>
-<source>Log</source>
-<target>Лог</target>
-
<source>Thank you, %x, for your donation and support!</source>
<target>Дякуємо Вам, %x, за ваше пожертвування та підтримку!</target>
@@ -1884,6 +1893,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Unable to register to receive system messages.</source>
<target>Не вдається зареєструватися для отримання системних повідомлень.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Варіант установки %x доступний тільки у FreeFileSync Donation Edition.</target>
+
<source>Cannot find system function %x.</source>
<target>Не вдається знайти системну функцію %x.</target>
@@ -2042,9 +2054,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Please choose the local installation type or select a different folder for installation.</source>
<target>Будь ласка, виберіть локальний тип інсталяції чи іншу папку для встановлення.</target>
-<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
-<target>Варіант установки %x доступний тільки у FreeFileSync Donation Edition.</target>
-
<source>Get the Donation Edition with bonus features and help keep FreeFileSync ad-free.</source>
<target>Отримайте Donation Edition з бонусними функціями та допоможіть зберегти FreeFileSync без реклами.</target>
diff --git a/FreeFileSync/Build/Resources.zip b/FreeFileSync/Build/Resources.zip
index 48cee7b5..4fe5268b 100755
--- a/FreeFileSync/Build/Resources.zip
+++ b/FreeFileSync/Build/Resources.zip
Binary files differ
diff --git a/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp b/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
index 97314b4d..0f895246 100755
--- a/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
+++ b/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
@@ -7,7 +7,6 @@
#include "folder_selector2.h"
#include <zen/thread.h>
#include <zen/file_access.h>
-#include <zen/optional.h>
#include <wx/dirdlg.h>
#include <wx/scrolwin.h>
#include <wx+/popup_dlg.h>
@@ -31,8 +30,10 @@ void setFolderPath(const Zstring& dirpath, wxTextCtrl* txtCtrl, wxWindow& toolti
const Zstring folderPathFmt = fff::getResolvedFilePath(dirpath); //may block when resolving [<volume name>]
- tooltipWnd.SetToolTip(nullptr); //workaround wxComboBox bug http://trac.wxwidgets.org/ticket/10512 / http://trac.wxwidgets.org/ticket/12659
- tooltipWnd.SetToolTip(utfTo<wxString>(folderPathFmt)); //who knows when the real bugfix reaches mere mortals via an official release...
+ if (folderPathFmt.empty())
+ tooltipWnd.UnsetToolTip(); //wxGTK doesn't allow wxToolTip with empty text!
+ else
+ tooltipWnd.SetToolTip(utfTo<wxString>(folderPathFmt));
if (staticText) //change static box label only if there is a real difference to what is shown in wxTextCtrl anyway
staticText->SetLabel(equalFilePath(appendSeparator(trimCpy(dirpath)), appendSeparator(folderPathFmt)) ? wxString(_("Drag && drop")) : utfTo<wxString>(folderPathFmt));
@@ -103,7 +104,7 @@ void FolderSelector2::onFilesDropped(FileDropEvent& event)
try
{
if (getItemType(itemPath) == ItemType::FILE) //throw FileError
- if (Opt<Zstring> parentPath = getParentFolderPath(itemPath))
+ if (std::optional<Zstring> parentPath = getParentFolderPath(itemPath))
itemPath = *parentPath;
}
catch (FileError&) {} //e.g. good for inactive mapped network shares, not so nice for C:\pagefile.sys
diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
index d0f1a137..aec55f7c 100755
--- a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
+++ b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
@@ -87,7 +87,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
bSizer161->Add( bSizer16, 0, 0, 5 );
- m_staticText811 = new wxStaticText( this, wxID_ANY, _("To get started just import a .ffs_batch file."), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText811 = new wxStaticText( this, wxID_ANY, _("To get started just import a \"ffs_batch\" file."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText811->Wrap( -1 );
m_staticText811->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
diff --git a/FreeFileSync/Source/RealTimeSync/monitor.cpp b/FreeFileSync/Source/RealTimeSync/monitor.cpp
index a586ce4d..84e3e363 100755
--- a/FreeFileSync/Source/RealTimeSync/monitor.cpp
+++ b/FreeFileSync/Source/RealTimeSync/monitor.cpp
@@ -21,79 +21,82 @@ namespace
const std::chrono::seconds FOLDER_EXISTENCE_CHECK_INTERVAL(1);
-std::set<Zstring, LessFilePath> getFormattedDirs(const std::vector<Zstring>& folderPathPhrases) //throw FileError
-{
- std::set<Zstring, LessFilePath> folderPaths; //make unique
-
- for (const Zstring& phrase : folderPathPhrases)
- {
- //hopefully clear enough now: https://freefilesync.org/forum/viewtopic.php?t=4302
- auto checkProtocol = [&](const Zstring& protoName)
- {
- if (startsWith(trimCpy(phrase), protoName + Zstr(":"), CmpAsciiNoCase()))
- throw FileError(replaceCpy(_("The %x protocol does not support directory monitoring:"), L"%x", utfTo<std::wstring>(protoName)) + L"\n\n" + fmtPath(phrase));
- };
- checkProtocol(Zstr("FTP")); //
- checkProtocol(Zstr("SFTP")); //throw FileError
- checkProtocol(Zstr("MTP")); //
-
- //make unique: no need to resolve duplicate phrases more than once! (consider "[volume name]" syntax) -> shouldn't this be already buffered by OS?
- folderPaths.insert(fff::getResolvedFilePath(phrase));
- }
-
- return folderPaths;
-}
-
-
//wait until all directories become available (again) + logs in network share
std::set<Zstring, LessFilePath> waitForMissingDirs(const std::vector<Zstring>& folderPathPhrases, //throw FileError
const std::function<void(const Zstring& folderPath)>& requestUiRefresh, std::chrono::milliseconds cbInterval)
{
+ //early failure! check for unsupported folder paths:
+ for (const Zstring& protoName : { Zstr("FTP"), Zstr("SFTP"), Zstr("MTP") })
+ for (const Zstring& phrase : folderPathPhrases)
+ //hopefully clear enough now: https://freefilesync.org/forum/viewtopic.php?t=4302
+ if (startsWith(trimCpy(phrase), protoName + Zstr(":"), CmpAsciiNoCase()))
+ throw FileError(replaceCpy(_("The %x protocol does not support directory monitoring:"), L"%x", utfTo<std::wstring>(protoName)) + L"\n\n" + fmtPath(phrase));
+
for (;;)
{
- //support specifying volume by name => call getResolvedFilePath() repeatedly
- std::set<Zstring, LessFilePath> folderPaths = getFormattedDirs(folderPathPhrases); //throw FileError
+ struct FolderInfo
+ {
+ Zstring folderPathPhrase;
+ std::future<bool> folderAvailable;
+ };
+ std::map<Zstring, FolderInfo, LessFilePath> folderInfos; //folderPath => FolderInfo
- std::vector<std::pair<Zstring, std::future<bool>>> futureInfo;
- //start all folder checks asynchronously (non-existent network path may block)
- for (const Zstring& folderPath : folderPaths)
- futureInfo.emplace_back(folderPath, runAsync([folderPath]
+ for (const Zstring& phrase : folderPathPhrases)
{
- //2. check dir availability
- return dirAvailable(folderPath);
- }));
+ const Zstring& folderPath = fff::getResolvedFilePath(phrase);
- bool allAvailable = true;
+ //start all folder checks asynchronously (non-existent network path may block)
+ if (folderInfos.find(folderPath) == folderInfos.end())
+ folderInfos[folderPath] = { phrase, runAsync([folderPath]{ return dirAvailable(folderPath); }) };
+ }
- for (auto& item : futureInfo)
+ std::set<Zstring, LessFilePath> availablePaths;
+ std::set<Zstring, LessFilePath> missingPathPhrases;
+ for (auto& item : folderInfos)
{
const Zstring& folderPath = item.first;
- std::future<bool>& ftDirAvailable = item.second;
+ std::future<bool>& folderAvailable = item.second.folderAvailable;
- for (;;)
- {
- while (ftDirAvailable.wait_for(cbInterval) != std::future_status::ready)
- requestUiRefresh(folderPath); //throw X
+ while (folderAvailable.wait_for(cbInterval) != std::future_status::ready)
+ requestUiRefresh(folderPath); //throw X
- if (ftDirAvailable.get())
- break;
+ if (folderAvailable.get())
+ availablePaths.insert(folderPath);
+ else
+ missingPathPhrases.insert(item.second.folderPathPhrase);
+ }
+ if (missingPathPhrases.empty())
+ return availablePaths; //only return when all folders were found on *first* try!
+
+ auto delayUntil = std::chrono::steady_clock::now() + FOLDER_EXISTENCE_CHECK_INTERVAL;
- //wait until folder is available: do not needlessly poll all others again!
- allAvailable = false;
+
+ for (const Zstring& folderPathPhrase : missingPathPhrases)
+ for (;;)
+ {
+ //support specifying volume by name => call getResolvedFilePath() repeatedly
+ const Zstring folderPath = fff::getResolvedFilePath(folderPathPhrase);
//wait some time...
- const auto delayUntil = std::chrono::steady_clock::now() + FOLDER_EXISTENCE_CHECK_INTERVAL;
for (auto now = std::chrono::steady_clock::now(); now < delayUntil; now = std::chrono::steady_clock::now())
{
requestUiRefresh(folderPath); //throw X
std::this_thread::sleep_for(cbInterval);
}
- ftDirAvailable = runAsync([folderPath] { return dirAvailable(folderPath); });
+ std::future<bool> folderAvailable = runAsync([folderPath]
+ {
+ return dirAvailable(folderPath);
+ });
+
+ while (folderAvailable.wait_for(cbInterval) != std::future_status::ready)
+ requestUiRefresh(folderPath); //throw X
+
+ if (folderAvailable.get())
+ break;
+ //else: wait until folder is available: do not needlessly poll existing folders again!
+ delayUntil = std::chrono::steady_clock::now() + FOLDER_EXISTENCE_CHECK_INTERVAL;
}
- }
- if (allAvailable) //only return when all folders were found on *first* try!
- return folderPaths;
}
}
diff --git a/FreeFileSync/Source/base/algorithm.cpp b/FreeFileSync/Source/base/algorithm.cpp
index a91d1130..044349b3 100755
--- a/FreeFileSync/Source/base/algorithm.cpp
+++ b/FreeFileSync/Source/base/algorithm.cpp
@@ -676,7 +676,7 @@ void fff::redetermineSyncDirection(const DirectionConfig& dirCfg, //throw FileEr
BaseFolderPair& baseFolder,
const std::function<void(const std::wstring& msg)>& notifyStatus)
{
- Opt<FileError> dbLoadError; //defer until after default directions have been set!
+ std::optional<FileError> dbLoadError; //defer until after default directions have been set!
//try to load sync-database files
std::shared_ptr<InSyncFolder> lastSyncState;
@@ -730,7 +730,7 @@ void fff::redetermineSyncDirection(const MainConfiguration& mainCfg, //throw Fil
if (folderCmp.size() != directCfgs.size())
throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
- Opt<FileError> dbLoadError; //defer until after default directions have been set!
+ std::optional<FileError> dbLoadError; //defer until after default directions have been set!
for (auto it = folderCmp.begin(); it != folderCmp.end(); ++it)
try
@@ -1123,8 +1123,8 @@ void fff::applyTimeSpanFilter(FolderComparison& folderCmp, time_t timeFrom, time
}
-Opt<PathDependency> fff::getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
- const AbstractPath& basePathR, const HardFilter& filterR)
+std::optional<PathDependency> fff::getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
+ const AbstractPath& basePathR, const HardFilter& filterR)
{
if (!AFS::isNullPath(basePathL) && !AFS::isNullPath(basePathR))
{
@@ -1159,7 +1159,7 @@ Opt<PathDependency> fff::getPathDependency(const AbstractPath& basePathL, const
}
}
}
- return NoValue();
+ return {};
}
//############################################################################################################
@@ -1211,12 +1211,12 @@ void copyToAlternateFolderFrom(const std::vector<const FileSystemObject*>& rowsT
{
//start deleting existing target as required by copyFileTransactional():
//best amortized performance if "target existing" is the most common case
- Opt<FileError> deletionError;
+ std::exception_ptr deletionError;
auto tryDeleteTargetItem = [&]
{
if (overwriteIfExists)
try { AFS::removeFilePlain(targetPath); /*throw FileError*/ }
- catch (const FileError& e) { deletionError = e; } //probably "not existing" error, defer evaluation
+ catch (FileError&) { deletionError = std::current_exception(); } //probably "not existing" error, defer evaluation
//else: copyFileTransactional() undefined behavior (fail/overwrite/auto-rename)
};
@@ -1231,7 +1231,7 @@ void copyToAlternateFolderFrom(const std::vector<const FileSystemObject*>& rowsT
if (ps.relPath.empty()) //already existing
{
if (deletionError)
- throw* deletionError;
+ std::rethrow_exception(deletionError);
}
else if (ps.relPath.size() > 1) //parent folder missing
{
diff --git a/FreeFileSync/Source/base/algorithm.h b/FreeFileSync/Source/base/algorithm.h
index 178e056e..7e073945 100755
--- a/FreeFileSync/Source/base/algorithm.h
+++ b/FreeFileSync/Source/base/algorithm.h
@@ -48,8 +48,8 @@ struct PathDependency
AbstractPath basePathChild;
Zstring relPath; //filled if child path is subfolder of parent path; empty if child path == parent path
};
-zen::Opt<PathDependency> getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
- const AbstractPath& basePathR, const HardFilter& filterR);
+std::optional<PathDependency> getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
+ const AbstractPath& basePathR, const HardFilter& filterR);
std::pair<std::wstring, int> getSelectedItemsAsString( //returns string with item names and total count of selected(!) items, NOT total files/dirs!
const std::vector<const FileSystemObject*>& selectionLeft, //all pointers need to be bound!
diff --git a/FreeFileSync/Source/base/application.cpp b/FreeFileSync/Source/base/application.cpp
index 9ccb0b05..a160ff06 100755
--- a/FreeFileSync/Source/base/application.cpp
+++ b/FreeFileSync/Source/base/application.cpp
@@ -23,6 +23,7 @@
#include "generate_logfile.h"
#include "../ui/batch_status_handler.h"
#include "../ui/main_dlg.h"
+//#include "../fs/concrete.h"
#include <gtk/gtk.h>
@@ -252,7 +253,7 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
try
{
if (getItemType(itemPath) == ItemType::FILE) //throw FileError
- if (Opt<Zstring> parentPath = getParentFolderPath(itemPath))
+ if (std::optional<Zstring> parentPath = getParentFolderPath(itemPath))
return *parentPath;
}
catch (FileError&) {}
@@ -330,7 +331,7 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
{
return lpc != LocalPairConfig{ lpc.folderPathPhraseLeft,
lpc.folderPathPhraseRight,
- NoValue(), NoValue(), FilterConfig() };
+ std::nullopt, std::nullopt, FilterConfig() };
};
auto replaceDirectories = [&](MainConfiguration& mainCfg)
@@ -353,7 +354,7 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
}
else
mainCfg.additionalPairs.push_back({ dirPathPhrasePairs[i].first, dirPathPhrasePairs[i].second,
- NoValue(), NoValue(), FilterConfig() });
+ std::nullopt, std::nullopt, FilterConfig() });
}
return true;
};
@@ -487,7 +488,7 @@ void showSyntaxHelp()
L"\n" +
_("config files:") + L"\n" +
- _("Any number of FreeFileSync .ffs_gui and/or .ffs_batch configuration files.") + L"\n\n" +
+ _("Any number of FreeFileSync \"ffs_gui\" and/or \"ffs_batch\" configuration files.") + L"\n\n" +
L"-DirPair " + _("directory") + L" " + _("directory") + L"\n" +
_("Any number of alternative directory pairs for at most one config file.") + L"\n\n" +
@@ -547,7 +548,7 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
const std::map<AbstractPath, size_t>& deviceParallelOps = batchCfg.mainCfg.deviceParallelOps;
- std::set<Zstring, LessFilePath> logFilePathsToKeep;
+ std::set<AbstractPath> logFilePathsToKeep;
for (const ConfigFileItem& item : globalCfg.gui.mainDlg.cfgFileHistory)
logFilePathsToKeep.insert(item.logFilePath);
@@ -559,8 +560,6 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
extractJobName(cfgFilePath),
globalCfg.soundFileSyncFinished,
syncStartTime,
- batchCfg.batchExCfg.altLogfileCountMax,
- batchCfg.batchExCfg.altLogFolderPathPhrase,
batchCfg.mainCfg.ignoreErrors,
batchCfg.batchExCfg.batchErrorHandling,
batchCfg.mainCfg.automaticRetryCount,
@@ -570,18 +569,6 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
batchCfg.batchExCfg.postSyncAction);
try
{
- warn_static("consider for removal after FFS 10.3 release")
-#if 1
- if (batchCfg.batchExCfg.altLogfileCountMax != 0)
- {
- if (!trimCpy(batchCfg.batchExCfg.altLogFolderPathPhrase).empty())
- statusHandler.reportWarning(replaceCpy(L"Beginning with FreeFileSync 10.3 the batch-specific log folder path %x will not be used.\n"
- L"Instead all synchronization logs will be written into " + fmtPath(getDefaultLogFolderPath()) +
- L"\n(See Menu -> Tools: Options; re-save this configuation to remove this warning)",
- L"%x", fmtPath(batchCfg.batchExCfg.altLogFolderPathPhrase)), globalCfg.warnDlgs.warnBatchLoggingDeprecated);
- }
-#endif
-
//inform about (important) non-default global settings
logNonDefaultSettings(globalCfg, statusHandler); //throw AbortProcess
@@ -615,7 +602,7 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
}
catch (AbortProcess&) {} //exit used by statusHandler
- BatchStatusHandler::Result r = statusHandler.reportFinalStatus(globalCfg.logfilesMaxAgeDays, logFilePathsToKeep); //noexcept
+ BatchStatusHandler::Result r = statusHandler.reportFinalStatus(batchCfg.mainCfg.altLogFolderPathPhrase, globalCfg.logfilesMaxAgeDays, logFilePathsToKeep); //noexcept
//----------------------------------------------------------------------
raiseReturnCode(returnCode, mapToReturnCode(r.finalStatus));
@@ -626,8 +613,8 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
{
if (r.finalStatus != SyncResult::ABORTED)
cfi.lastSyncTime = std::chrono::system_clock::to_time_t(syncStartTime);
- assert(!r.logFilePath.empty());
- if (!r.logFilePath.empty())
+ assert(!AFS::isNullPath(r.logFilePath));
+ if (!AFS::isNullPath(r.logFilePath))
{
cfi.logFilePath = r.logFilePath;
cfi.logResult = r.finalStatus;
diff --git a/FreeFileSync/Source/base/comparison.cpp b/FreeFileSync/Source/base/comparison.cpp
index 00303c17..84b392cf 100755
--- a/FreeFileSync/Source/base/comparison.cpp
+++ b/FreeFileSync/Source/base/comparison.cpp
@@ -69,7 +69,7 @@ struct ResolvedBaseFolders
ResolvedBaseFolders initializeBaseFolders(const std::vector<FolderPairCfg>& fpCfgList, const std::map<AbstractPath, size_t>& deviceParallelOps,
- int folderAccessTimeout,
+ std::chrono::seconds folderAccessTimeout,
bool allowUserInteraction,
bool& warnFolderNotExisting,
ProcessCallback& callback /*throw X*/)
@@ -940,7 +940,7 @@ void fff::logNonDefaultSettings(const XmlGlobalSettings& activeSettings, Process
changedSettingsMsg += L"\n " + _("File time tolerance") + L" - " + numberTo<std::wstring>(activeSettings.fileTimeTolerance);
if (activeSettings.folderAccessTimeout != defaultSettings.folderAccessTimeout)
- changedSettingsMsg += L"\n " + _("Folder access timeout") + L" - " + numberTo<std::wstring>(activeSettings.folderAccessTimeout);
+ changedSettingsMsg += L"\n " + _("Folder access timeout") + L" - " + numberTo<std::wstring>(activeSettings.folderAccessTimeout.count());
if (activeSettings.runWithBackgroundPriority != defaultSettings.runWithBackgroundPriority)
changedSettingsMsg += L"\n " + _("Run with background priority") + L" - " + (activeSettings.runWithBackgroundPriority ? _("Enabled") : _("Disabled"));
@@ -960,7 +960,7 @@ FolderComparison fff::compare(WarningDialogs& warnings,
int fileTimeTolerance,
bool allowUserInteraction,
bool runWithBackgroundPriority,
- int folderAccessTimeout,
+ std::chrono::seconds folderAccessTimeout,
bool createDirLocks,
std::unique_ptr<LockHolder>& dirLocks,
const std::vector<FolderPairCfg>& fpCfgList,
@@ -1035,8 +1035,8 @@ FolderComparison fff::compare(WarningDialogs& warnings,
std::wstring msg;
for (const auto& w : workLoad)
- if (Opt<PathDependency> pd = getPathDependency(w.first.folderPathLeft, *w.second.filter.nameFilter,
- w.first.folderPathRight, *w.second.filter.nameFilter))
+ if (std::optional<PathDependency> pd = getPathDependency(w.first.folderPathLeft, *w.second.filter.nameFilter,
+ w.first.folderPathRight, *w.second.filter.nameFilter))
{
msg += L"\n\n" +
AFS::getDisplayPath(w.first.folderPathLeft) + L"\n" +
@@ -1057,7 +1057,7 @@ FolderComparison fff::compare(WarningDialogs& warnings,
{
std::set<Zstring, LessFilePath> dirPathsExisting;
for (const AbstractPath& folderPath : resInfo.existingBaseFolders)
- if (Opt<Zstring> nativePath = AFS::getNativeItemPath(folderPath)) //restrict directory locking to native paths until further
+ if (std::optional<Zstring> nativePath = AFS::getNativeItemPath(folderPath)) //restrict directory locking to native paths until further
dirPathsExisting.insert(*nativePath);
dirLocks = std::make_unique<LockHolder>(dirPathsExisting, warnings.warnDirectoryLockFailed, callback);
diff --git a/FreeFileSync/Source/base/comparison.h b/FreeFileSync/Source/base/comparison.h
index 356dbe89..4c93a3ba 100755
--- a/FreeFileSync/Source/base/comparison.h
+++ b/FreeFileSync/Source/base/comparison.h
@@ -55,7 +55,7 @@ FolderComparison compare(WarningDialogs& warnings,
int fileTimeTolerance,
bool allowUserInteraction,
bool runWithBackgroundPriority,
- int folderAccessTimeout,
+ std::chrono::seconds folderAccessTimeout,
bool createDirLocks,
std::unique_ptr<LockHolder>& dirLocks, //out
const std::vector<FolderPairCfg>& fpCfgList,
diff --git a/FreeFileSync/Source/base/dir_exist_async.h b/FreeFileSync/Source/base/dir_exist_async.h
index 345b29c2..acd79a69 100755
--- a/FreeFileSync/Source/base/dir_exist_async.h
+++ b/FreeFileSync/Source/base/dir_exist_async.h
@@ -30,7 +30,7 @@ struct FolderStatus
};
FolderStatus getFolderStatusNonBlocking(const std::set<AbstractPath>& folderPaths, const std::map<AbstractPath, size_t>& deviceParallelOps,
- int folderAccessTimeout, bool allowUserInteraction,
+ std::chrono::seconds folderAccessTimeout, bool allowUserInteraction,
ProcessCallback& procCallback /*throw X*/)
{
using namespace zen;
@@ -83,7 +83,7 @@ FolderStatus getFolderStatusNonBlocking(const std::set<AbstractPath>& folderPath
procCallback.reportStatus(replaceCpy(_("Searching for folder %x..."), L"%x", displayPathFmt)); //throw X
- while (std::chrono::steady_clock::now() < startTime + std::chrono::seconds(folderAccessTimeout) &&
+ while (std::chrono::steady_clock::now() < startTime + folderAccessTimeout &&
fi.second.wait_for(UI_UPDATE_INTERVAL / 2) != std::future_status::ready)
procCallback.requestUiRefresh(); //throw X
diff --git a/FreeFileSync/Source/base/dir_lock.cpp b/FreeFileSync/Source/base/dir_lock.cpp
index ab38ed53..161fb35e 100755
--- a/FreeFileSync/Source/base/dir_lock.cpp
+++ b/FreeFileSync/Source/base/dir_lock.cpp
@@ -12,9 +12,6 @@
#include <zen/guid.h>
#include <zen/file_access.h>
#include <zen/file_io.h>
-#include <zen/optional.h>
-//#include <wx/log.h>
-//#include <wx/app.h>
#include <fcntl.h> //open()
#include <sys/stat.h> //
@@ -46,7 +43,7 @@ public:
void operator()() const //throw ThreadInterruption
{
- const Opt<Zstring> parentDirPath = getParentFolderPath(lockFilePath_);
+ const std::optional<Zstring> parentDirPath = getParentFolderPath(lockFilePath_);
setCurrentThreadName(("DirLock: " + (parentDirPath ? utfTo<std::string>(*parentDirPath) : "")).c_str());
for (;;)
@@ -91,10 +88,10 @@ Zstring abandonedLockDeletionName(const Zstring& lockFilePath) //make sure to NO
using SessionId = pid_t;
//return ppid on Windows, sid on Linux/Mac, "no value" if process corresponding to "processId" is not existing
-Opt<SessionId> getSessionId(ProcessId processId) //throw FileError
+std::optional<SessionId> getSessionId(ProcessId processId) //throw FileError
{
if (::kill(processId, 0) != 0) //sig == 0: no signal sent, just existence check
- return NoValue();
+ return {};
const pid_t procSid = ::getsid(processId); //NOT to be confused with "login session", e.g. not stable on OS X!!!
if (procSid < 0) //pids are never negative, empiric proof: https://linux.die.net/man/2/wait
@@ -151,7 +148,7 @@ LockInformation getLockInfoFromCurrentProcess() //throw FileError
lockInfo.userId = numberTo<std::string>(userIdNo) + "(" + pwsEntry->pw_name + ")"; //follow Linux naming convention "1000(zenju)"
- Opt<SessionId> sessionIdTmp = getSessionId(lockInfo.processId); //throw FileError
+ std::optional<SessionId> sessionIdTmp = getSessionId(lockInfo.processId); //throw FileError
if (!sessionIdTmp)
throw FileError(_("Cannot get process information."), L"no session id found"); //should not happen?
lockInfo.sessionId = *sessionIdTmp;
@@ -237,7 +234,7 @@ ProcessStatus getProcessStatus(const LockInformation& lockInfo) //throw FileErro
lockInfo.processId == localInfo.processId) //obscure, but possible: deletion failed or a lock file is "stolen" and put back while the program is running
return ProcessStatus::ITS_US;
- if (Opt<SessionId> sessionId = getSessionId(lockInfo.processId)) //throw FileError
+ if (std::optional<SessionId> sessionId = getSessionId(lockInfo.processId)) //throw FileError
return *sessionId == lockInfo.sessionId ? ProcessStatus::RUNNING : ProcessStatus::NOT_RUNNING;
return ProcessStatus::NOT_RUNNING;
}
diff --git a/FreeFileSync/Source/base/file_hierarchy.cpp b/FreeFileSync/Source/base/file_hierarchy.cpp
index a10646be..88f7f152 100755
--- a/FreeFileSync/Source/base/file_hierarchy.cpp
+++ b/FreeFileSync/Source/base/file_hierarchy.cpp
@@ -20,8 +20,8 @@ std::wstring fff::getShortDisplayNameForFolderPair(const AbstractPath& itemPathL
AbstractPath tmpPathR = itemPathR;
for (;;)
{
- Opt<AbstractPath> parentPathL = AFS::getParentFolderPath(tmpPathL);
- Opt<AbstractPath> parentPathR = AFS::getParentFolderPath(tmpPathR);
+ std::optional<AbstractPath> parentPathL = AFS::getParentFolderPath(tmpPathL);
+ std::optional<AbstractPath> parentPathR = AFS::getParentFolderPath(tmpPathR);
if (!parentPathL || !parentPathR)
break;
@@ -289,23 +289,24 @@ SyncOperation FilePair::applyMoveOptimization(SyncOperation op) const
note: as long as we consider "create + delete" cases only, detection of renamed files, should be fine even for "binary" comparison variant!
*/
if (moveFileRef_)
- if (auto refFile = dynamic_cast<const FilePair*>(FileSystemObject::retrieve(moveFileRef_))) //we expect a "FilePair", but only need a "FileSystemObject"
- {
- SyncOperation opRef = refFile->FileSystemObject::getSyncOperation(); //do *not* make a virtual call!
-
- if (op == SO_CREATE_NEW_LEFT &&
- opRef == SO_DELETE_LEFT)
- op = SO_MOVE_LEFT_TO;
- else if (op == SO_DELETE_LEFT &&
- opRef == SO_CREATE_NEW_LEFT)
- op = SO_MOVE_LEFT_FROM;
- else if (op == SO_CREATE_NEW_RIGHT &&
- opRef == SO_DELETE_RIGHT)
- op = SO_MOVE_RIGHT_TO;
- else if (op == SO_DELETE_RIGHT &&
- opRef == SO_CREATE_NEW_RIGHT)
- op = SO_MOVE_RIGHT_FROM;
- }
+ if (auto refFile = dynamic_cast<const FilePair*>(FileSystemObject::retrieve(moveFileRef_))) //we expect a "FilePair", but only need a "FileSystemObject" here
+ if (refFile->moveFileRef_ == getId()) //both ends should agree...
+ {
+ const SyncOperation opRef = refFile->FileSystemObject::getSyncOperation(); //do *not* make a virtual call!
+
+ if (op == SO_CREATE_NEW_LEFT &&
+ opRef == SO_DELETE_LEFT)
+ op = SO_MOVE_LEFT_TO;
+ else if (op == SO_DELETE_LEFT &&
+ opRef == SO_CREATE_NEW_LEFT)
+ op = SO_MOVE_LEFT_FROM;
+ else if (op == SO_CREATE_NEW_RIGHT &&
+ opRef == SO_DELETE_RIGHT)
+ op = SO_MOVE_RIGHT_TO;
+ else if (op == SO_DELETE_RIGHT &&
+ opRef == SO_CREATE_NEW_RIGHT)
+ op = SO_MOVE_RIGHT_FROM;
+ }
return op;
}
@@ -476,6 +477,7 @@ std::wstring fff::getSyncOpDescription(const FileSystemObject& fsObj)
if (auto sourceFile = dynamic_cast<const FilePair*>(&fsObj))
if (auto targetFile = dynamic_cast<const FilePair*>(FileSystemObject::retrieve(sourceFile->getMoveRef())))
{
+ assert(targetFile->getMoveRef() == sourceFile->getId());
const bool onLeft = op == SO_MOVE_LEFT_FROM || op == SO_MOVE_LEFT_TO;
const bool isSource = op == SO_MOVE_LEFT_FROM || op == SO_MOVE_RIGHT_FROM;
diff --git a/FreeFileSync/Source/base/file_hierarchy.h b/FreeFileSync/Source/base/file_hierarchy.h
index 1bae389f..0ea4a3bb 100755
--- a/FreeFileSync/Source/base/file_hierarchy.h
+++ b/FreeFileSync/Source/base/file_hierarchy.h
@@ -445,7 +445,7 @@ public:
virtual SyncOperation getSyncOperation() const;
std::wstring getSyncOpConflict() const; //return conflict when determining sync direction or (still unresolved) conflict during categorization
- template <SelectedSide side> void removeObject(); //removes file or directory (recursively!) without physically removing the element: used by manual deletion
+ template <SelectedSide side> void removeObject(); //removes file or directory (recursively!) without physically removing the element: used by manual deletion
const ContainerObject& parent() const { return parent_; }
/**/ ContainerObject& parent() { return parent_; }
@@ -543,9 +543,9 @@ private:
void flip () override;
void removeObjectL() override;
void removeObjectR() override;
- void notifySyncCfgChanged() override { syncOpBuffered_ = zen::NoValue(); FileSystemObject::notifySyncCfgChanged(); ContainerObject::notifySyncCfgChanged(); }
+ void notifySyncCfgChanged() override { syncOpBuffered_ = {}; FileSystemObject::notifySyncCfgChanged(); ContainerObject::notifySyncCfgChanged(); }
- mutable zen::Opt<SyncOperation> syncOpBuffered_; //determining sync-op for directory may be expensive as it depends on child-objects => buffer
+ mutable std::optional<SyncOperation> syncOpBuffered_; //determining sync-op for directory may be expensive as it depends on child-objects => buffer
FolderAttributes attrL_;
FolderAttributes attrR_;
diff --git a/FreeFileSync/Source/base/generate_logfile.cpp b/FreeFileSync/Source/base/generate_logfile.cpp
index 221441b1..cbad8a4c 100755
--- a/FreeFileSync/Source/base/generate_logfile.cpp
+++ b/FreeFileSync/Source/base/generate_logfile.cpp
@@ -254,7 +254,7 @@ void limitLogfileCount(const AbstractPath& logFolderPath, //throw FileError
tc.hour = 0;
return localToTimeT(tc); //returns -1 on error => swallow => no versions trimmed by versionMaxAgeDays
}();
- const time_t cutOffTime = lastMidnightTime - logfilesMaxAgeDays * 24 * 3600;
+ const time_t cutOffTime = lastMidnightTime - static_cast<time_t>(logfilesMaxAgeDays) * 24 * 3600;
std::exception_ptr firstError;
@@ -289,7 +289,7 @@ MessageType fff::getFinalMsgType(SyncResult finalStatus)
case SyncResult::FINISHED_WITH_WARNINGS:
return MSG_TYPE_WARNING;
case SyncResult::FINISHED_WITH_ERROR:
- case SyncResult::ABORTED:
+ case SyncResult::ABORTED: //= user cancel; *not* a MSG_TYPE_FATAL_ERROR!
return MSG_TYPE_ERROR;
}
assert(false);
@@ -297,21 +297,19 @@ MessageType fff::getFinalMsgType(SyncResult finalStatus)
}
-Zstring fff::saveLogFile(const ProcessSummary& summary, //throw FileError
- const ErrorLog& log,
- const std::chrono::system_clock::time_point& syncStartTime,
- int logfilesMaxAgeDays,
- const std::set<Zstring, LessFilePath>& logFilePathsToKeep,
- const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/)
+AbstractPath fff::saveLogFile(const ProcessSummary& summary, //throw FileError
+ const ErrorLog& log,
+ const std::chrono::system_clock::time_point& syncStartTime,
+ const Zstring& altLogFolderPathPhrase, //optional
+ int logfilesMaxAgeDays,
+ const std::set<AbstractPath>& logFilePathsToKeep,
+ const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/)
{
- //let's keep our log handling abstract; we might need it some time
- const AbstractPath logFolderPath = createAbstractPath(getDefaultLogFolderPath());
+ AbstractPath logFolderPath = createAbstractPath(altLogFolderPathPhrase);
+ if (AFS::isNullPath(logFolderPath))
+ logFolderPath = createAbstractPath(getDefaultLogFolderPath());
- std::set<AbstractPath> abstractLogFilePathsToKeep;
- for (const Zstring& filePath : logFilePathsToKeep)
- abstractLogFilePathsToKeep.insert(createAbstractPath(filePath));
-
- Opt<AbstractPath> logFilePath;
+ std::optional<AbstractPath> logFilePath;
std::exception_ptr firstError;
try
{
@@ -321,12 +319,12 @@ Zstring fff::saveLogFile(const ProcessSummary& summary, //throw FileError
try
{
- limitLogfileCount(logFolderPath, logfilesMaxAgeDays, abstractLogFilePathsToKeep, notifyStatus); //throw FileError, X
+ limitLogfileCount(logFolderPath, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatus); //throw FileError, X
}
catch (const FileError&) { if (!firstError) firstError = std::current_exception(); };
if (firstError) //late failure!
std::rethrow_exception(firstError);
- return *AFS::getNativeItemPath(*logFilePath); //logFilePath *is* native because getDefaultLogFolderPath() is!
+ return *logFilePath;
}
diff --git a/FreeFileSync/Source/base/generate_logfile.h b/FreeFileSync/Source/base/generate_logfile.h
index 8b321c8b..dbb3cbd0 100755
--- a/FreeFileSync/Source/base/generate_logfile.h
+++ b/FreeFileSync/Source/base/generate_logfile.h
@@ -11,6 +11,7 @@
#include <zen/error_log.h>
#include "return_codes.h"
#include "status_handler.h"
+#include "../fs/abstract.h"
namespace fff
@@ -18,12 +19,13 @@ namespace fff
Zstring getDefaultLogFolderPath();
-Zstring saveLogFile(const ProcessSummary& summary, //throw FileError
- const zen::ErrorLog& log,
- const std::chrono::system_clock::time_point& syncStartTime,
- int logfilesMaxAgeDays,
- const std::set<Zstring, LessFilePath>& logFilePathsToKeep,
- const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/);
+AbstractPath saveLogFile(const ProcessSummary& summary, //throw FileError
+ const zen::ErrorLog& log,
+ const std::chrono::system_clock::time_point& syncStartTime,
+ const Zstring& altLogFolderPathPhrase, //optional
+ int logfilesMaxAgeDays,
+ const std::set<AbstractPath>& logFilePathsToKeep,
+ const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/);
zen::MessageType getFinalMsgType(SyncResult finalStatus);
}
diff --git a/FreeFileSync/Source/base/icon_buffer.cpp b/FreeFileSync/Source/base/icon_buffer.cpp
index 6c030bb5..a784f9e0 100755
--- a/FreeFileSync/Source/base/icon_buffer.cpp
+++ b/FreeFileSync/Source/base/icon_buffer.cpp
@@ -134,14 +134,14 @@ public:
}
//must be called by main thread only! => wxBitmap is NOT thread-safe like an int (non-atomic ref-count!!!)
- Opt<wxBitmap> retrieve(const AbstractPath& filePath)
+ std::optional<wxBitmap> retrieve(const AbstractPath& filePath)
{
assert(runningMainThread());
std::lock_guard<std::mutex> dummy(lockIconList_);
auto it = iconList.find(filePath);
if (it == iconList.end())
- return NoValue();
+ return {};
markAsHot(it);
@@ -249,7 +249,7 @@ private:
struct IconData
{
IconData() {}
- IconData(IconData&& tmp) : iconRaw(std::move(tmp.iconRaw)), iconFmt(std::move(tmp.iconFmt)), prev(tmp.prev), next(tmp.next) {}
+ IconData(IconData&& tmp) noexcept : iconRaw(std::move(tmp.iconRaw)), iconFmt(std::move(tmp.iconFmt)), prev(tmp.prev), next(tmp.next) {}
ImageHolder iconRaw; //native icon representation: may be used by any thread
@@ -336,15 +336,15 @@ bool IconBuffer::readyForRetrieval(const AbstractPath& filePath)
}
-Opt<wxBitmap> IconBuffer::retrieveFileIcon(const AbstractPath& filePath)
+std::optional<wxBitmap> IconBuffer::retrieveFileIcon(const AbstractPath& filePath)
{
- if (Opt<wxBitmap> ico = pimpl_->buffer.retrieve(filePath))
+ if (std::optional<wxBitmap> ico = pimpl_->buffer.retrieve(filePath))
return ico;
//since this icon seems important right now, we don't want to wait until next setWorkload() to start retrieving
pimpl_->workload.add(filePath);
pimpl_->buffer.limitSize();
- return NoValue();
+ return {};
}
diff --git a/FreeFileSync/Source/base/icon_buffer.h b/FreeFileSync/Source/base/icon_buffer.h
index f0ad78e4..2f5e4e60 100755
--- a/FreeFileSync/Source/base/icon_buffer.h
+++ b/FreeFileSync/Source/base/icon_buffer.h
@@ -10,7 +10,6 @@
#include <vector>
#include <memory>
#include <zen/zstring.h>
-#include <zen/optional.h>
#include <wx/bitmap.h>
#include "../fs/abstract.h"
@@ -35,7 +34,7 @@ public:
void setWorkload (const std::vector<AbstractPath>& load); //(re-)set new workload of icons to be retrieved;
bool readyForRetrieval(const AbstractPath& filePath);
- zen::Opt<wxBitmap> retrieveFileIcon (const AbstractPath& filePath); //... and mark as hot
+ std::optional<wxBitmap> retrieveFileIcon (const AbstractPath& filePath); //... and mark as hot
wxBitmap getIconByExtension(const Zstring& filePath); //...and add to buffer
//retrieveFileIcon() + getIconByExtension() are safe to call from within WM_PAINT handler! no COM calls (...on calling thread)
diff --git a/FreeFileSync/Source/base/localization.cpp b/FreeFileSync/Source/base/localization.cpp
index bc27e6ea..28f19e33 100755
--- a/FreeFileSync/Source/base/localization.cpp
+++ b/FreeFileSync/Source/base/localization.cpp
@@ -39,18 +39,19 @@ public:
std::wstring translate(const std::wstring& text) const override
{
//look for translation in buffer table
- auto it = transMapping.find(text);
- if (it != transMapping.end() && !it->second.empty())
+ auto it = transMapping_.find(text);
+ if (it != transMapping_.end() && !it->second.empty())
return it->second;
return text; //fallback
}
std::wstring translate(const std::wstring& singular, const std::wstring& plural, int64_t n) const override
{
- auto it = transMappingPl.find({ singular, plural });
- if (it != transMappingPl.end())
+ auto it = transMappingPl_.find({ singular, plural });
+ if (it != transMappingPl_.end())
{
- const size_t formNo = pluralParser->getForm(n);
+ const size_t formNo = pluralParser_->getForm(n);
+ assert(formNo < it->second.size());
if (formNo < it->second.size())
return replaceCpy(it->second[formNo], L"%x", formatNumber(n));
}
@@ -61,9 +62,9 @@ private:
using Translation = std::unordered_map<std::wstring, std::wstring>; //hash_map is 15% faster than std::map on GCC
using TranslationPlural = std::map<std::pair<std::wstring, std::wstring>, std::vector<std::wstring>>;
- Translation transMapping; //map original text |-> translation
- TranslationPlural transMappingPl;
- std::unique_ptr<plural::PluralForm> pluralParser; //bound!
+ Translation transMapping_; //map original text |-> translation
+ TranslationPlural transMappingPl_;
+ std::unique_ptr<plural::PluralForm> pluralParser_; //bound!
const wxLanguage langId_;
};
@@ -82,30 +83,31 @@ FFSTranslation::FFSTranslation(const Zstring& lngFilePath, wxLanguage langId) :
}
lng::TransHeader header;
- lng::TranslationMap transInput;
- lng::TranslationPluralMap transPluralInput;
- lng::parseLng(inputStream, header, transInput, transPluralInput); //throw ParsingError
+ lng::TranslationMap transUtf;
+ lng::TranslationPluralMap transPluralUtf;
+ lng::parseLng(inputStream, header, transUtf, transPluralUtf); //throw ParsingError
- for (const auto& item : transInput)
+ pluralParser_ = std::make_unique<plural::PluralForm>(header.pluralDefinition); //throw plural::ParsingError
+
+ for (const auto& item : transUtf)
{
- const std::wstring original = utfTo<std::wstring>(item.first);
- const std::wstring translation = utfTo<std::wstring>(item.second);
- transMapping.emplace(original, translation);
+ std::wstring original = utfTo<std::wstring>(item.first);
+ std::wstring translation = utfTo<std::wstring>(item.second);
+
+ transMapping_.emplace(std::move(original), std::move(translation));
}
- for (const auto& item : transPluralInput)
+ for (const auto& item : transPluralUtf)
{
- const std::wstring engSingular = utfTo<std::wstring>(item.first.first);
- const std::wstring engPlural = utfTo<std::wstring>(item.first.second);
+ std::wstring engSingular = utfTo<std::wstring>(item.first.first);
+ std::wstring engPlural = utfTo<std::wstring>(item.first.second);
- std::vector<std::wstring> plFormsWide;
+ std::vector<std::wstring> pluralForms;
for (const std::string& pf : item.second)
- plFormsWide.push_back(utfTo<std::wstring>(pf));
+ pluralForms.push_back(utfTo<std::wstring>(pf));
- transMappingPl.insert({ { engSingular, engPlural }, plFormsWide });
+ transMappingPl_.insert({ { std::move(engSingular), std::move(engPlural) }, std::move(pluralForms) });
}
-
- pluralParser = std::make_unique<plural::PluralForm>(header.pluralDefinition); //throw plural::ParsingError
}
diff --git a/FreeFileSync/Source/base/parallel_scan.cpp b/FreeFileSync/Source/base/parallel_scan.cpp
index 805c4223..cc432462 100755
--- a/FreeFileSync/Source/base/parallel_scan.cpp
+++ b/FreeFileSync/Source/base/parallel_scan.cpp
@@ -172,8 +172,8 @@ public:
AFS::TraverserCallback::HandleError rv = *errorResponse_;
- errorRequest_ = NoValue();
- errorResponse_ = NoValue();
+ errorRequest_ = {};
+ errorResponse_ = {};
dummy.unlock(); //optimization for condition_variable::notify_all()
conditionReadyForNewRequest_.notify_all(); //instead of notify_one(); workaround bug: https://svn.boost.org/trac/boost/ticket/7796
@@ -294,8 +294,8 @@ private:
std::condition_variable conditionReadyForNewRequest_;
std::condition_variable conditionNewRequest;
std::condition_variable conditionHaveResponse_;
- Opt<std::pair<std::wstring, size_t>> errorRequest_; //error message + retry number
- Opt<AFS::TraverserCallback::HandleError> errorResponse_;
+ std::optional<std::pair<std::wstring, size_t>> errorRequest_; //error message + retry number
+ std::optional<AFS::TraverserCallback::HandleError> errorResponse_;
size_t threadsToFinish_; //can't use activeThreadIdxs_.size() which is locked by different mutex!
//also note: activeThreadIdxs_.size() may be 0 during worker thread construction!
@@ -390,8 +390,6 @@ void DirCallback::onFile(const AFS::FileInfo& fi) //throw ThreadInterruption
const Zstring fileRelPath = parentRelPathPf_ + fi.itemName;
- warn_static("why call reportCurrentFile() per file at all? should be sufficient to do per folder only!")
-
//update status information no matter whether item is excluded or not!
if (cfg_.acb.mayReportCurrentFile(cfg_.threadIdx, cfg_.lastReportTime))
cfg_.acb.reportCurrentFile(AFS::getDisplayPath(AFS::appendRelPath(cfg_.baseFolderPath, fileRelPath)));
diff --git a/FreeFileSync/Source/base/parallel_scan.h b/FreeFileSync/Source/base/parallel_scan.h
index fd9bc242..bbe1071f 100755
--- a/FreeFileSync/Source/base/parallel_scan.h
+++ b/FreeFileSync/Source/base/parallel_scan.h
@@ -43,7 +43,7 @@ struct DirectoryValue
{
FolderContainer folderCont;
- //relative paths (or empty string for root) for directories that could not be read (completely), e.g. access denied, or temporal network drop
+ //relative paths (or empty string for root) for directories that could not be read (completely), e.g. access denied, or temporary network drop
std::map<Zstring, std::wstring, LessFilePath> failedFolderReads; //with corresponding error message
//relative paths (never empty) for failure to read single file/dir/symlink with corresponding error message
diff --git a/FreeFileSync/Source/base/parse_lng.h b/FreeFileSync/Source/base/parse_lng.h
index 0ddc86c0..b48af8b2 100755
--- a/FreeFileSync/Source/base/parse_lng.h
+++ b/FreeFileSync/Source/base/parse_lng.h
@@ -13,7 +13,6 @@
#include <memory>
#include <map>
#include <set>
-//#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
@@ -477,69 +476,68 @@ private:
checkPlaceholder("%y");
checkPlaceholder("%z");
- auto ampersandTokenCount = [](const std::string& str) -> size_t
- {
- const std::string tmp = replaceCpy(str, "&&", ""); //make sure to not catch && which windows resolves as just one & for display!
- return std::count(tmp.begin(), tmp.end(), '&');
- };
+ //if source is a one-liner, so should be the translation
+ if (!contains(original, '\n') && contains(translation, '\n'))
+ throw ParsingError({ L"Source text is a one-liner, but translation consists of multiple lines", scn_.posRow(), scn_.posCol() });
//if source contains ampersand to mark menu accellerator key, so must translation
- const size_t ampCountOrig = ampersandTokenCount(original);
- if (ampCountOrig != ampersandTokenCount(translation) ||
- ampCountOrig > 1)
+ const size_t ampCount = ampersandTokenCount(original);
+ if (ampCount > 1 || ampCount != ampersandTokenCount(translation))
throw ParsingError({ L"Source and translation both need exactly one & character to mark a menu item access key or none at all", scn_.posRow(), scn_.posCol() });
//ampersand at the end makes buggy wxWidgets crash miserably
- if (ampCountOrig > 0)
- if ((endsWith(original, "&") && !endsWith(original, "&&")) ||
- (endsWith(translation, "&") && !endsWith(translation, "&&")))
- throw ParsingError({ L"The & character to mark a menu item access key must not occur at the end of a string", scn_.posRow(), scn_.posCol() });
+ if (endsWithSingleAmp(original) || endsWithSingleAmp(translation))
+ throw ParsingError({ L"The & character to mark a menu item access key must not occur at the end of a string", scn_.posRow(), scn_.posCol() });
//if source ends with colon, so must translation (note: character seems to be universally used, even for asian and arabic languages)
- if (endsWith(original, ":") &&
- !endsWith(translation, ":") &&
- !endsWith(translation, "\xef\xbc\x9a")) //chinese colon
+ if (endsWith(original, ":") && !endsWithColon(translation))
throw ParsingError({ L"Source text ends with a colon character \":\", but translation does not", scn_.posRow(), scn_.posCol() });
- auto endsWithSingleDot = [](const std::string& s) { return endsWith(s, ".") && !endsWith(s, ".."); };
-
//if source ends with a period, so must translation (note: character seems to be universally used, even for asian and arabic languages)
- if (endsWithSingleDot(original) &&
- !endsWithSingleDot(translation) &&
- !endsWith(translation, "\xe0\xa5\xa4") && //hindi period
- !endsWith(translation, "\xe3\x80\x82")) //chinese period
+ if (endsWithSingleDot(original) && !endsWithSingleDot(translation))
throw ParsingError({ L"Source text ends with a punctuation mark character \".\", but translation does not", scn_.posRow(), scn_.posCol() });
//if source ends with an ellipsis, so must translation (note: character seems to be universally used, even for asian and arabic languages)
- if (endsWith(original, "...") &&
- !endsWith(translation, "...") &&
- !endsWith(translation, "\xe2\x80\xa6")) //narrow ellipsis (spanish?)
+ if (endsWithEllipsis(original) && !endsWithEllipsis(translation))
throw ParsingError({ L"Source text ends with an ellipsis \"...\", but translation does not", scn_.posRow(), scn_.posCol() });
- //if source is a one-liner, so should be the translation
- if (!contains(original, '\n') && contains(translation, '\n'))
- throw ParsingError({ L"Source text is a one-liner, but translation consists of multiple lines", scn_.posRow(), scn_.posCol() });
-
- //check for correct FFS brand names
- if (contains(original, "FreeFileSync") && !contains(translation, "FreeFileSync"))
- throw ParsingError({ L"Misspelled \"FreeFileSync\" in translation", scn_.posRow(), scn_.posCol() });
- if (contains(original, "RealTimeSync") && !contains(translation, "RealTimeSync"))
- throw ParsingError({ L"Misspelled \"RealTimeSync\" in translation", scn_.posRow(), scn_.posCol() });
+ //check for not-to-be-translated texts
+ for (const char* fixedStr : { "FreeFileSync", "RealTimeSync", "ffs_gui", "ffs_batch", "ffs_tmp", "GlobalSettings.xml" })
+ if (contains(original, fixedStr) && !contains(translation, fixedStr))
+ throw ParsingError({ replaceCpy<std::wstring>(L"Misspelled \"%x\" in translation", L"%x", utfTo<std::wstring>(fixedStr)), scn_.posRow(), scn_.posCol() });
+
+ //some languages (French!) put a space before punctuation mark => must be a no-brake space!
+ for (const char punctChar : std::string(".!?:;$#"))
+ if (contains(original, std::string(" ") + punctChar) ||
+ contains(translation, std::string(" ") + punctChar))
+ throw ParsingError({ replaceCpy<std::wstring>(L"Text contains a space before the \"%x\" character. Are line-breaks really allowed here?"
+ " Maybe this should be a \"non-breaking space\" (Windows: Alt 0160 UTF8: 0xC2 0xA0)?",
+ L"%x", utfTo<std::wstring>(punctChar)), scn_.posRow(), scn_.posCol() });
}
}
void validateTranslation(const SingularPluralPair& original, const PluralForms& translation, const plural::PluralFormInfo& pluralInfo) //throw ParsingError
{
using namespace zen;
+
+ if (original.first.empty() || original.second.empty())
+ throw ParsingError({ L"Translation source text is empty", scn_.posRow(), scn_.posCol() });
+
+ const std::vector<std::string> allTexts = [&]
+ {
+ std::vector<std::string> at{ original.first, original.second };
+ at.insert(at.end(), translation.begin(), translation.end());
+ return at;
+ }();
+
+ for (const std::string& str : allTexts)
+ if (!isValidUtf(str))
+ throw ParsingError({ L"Text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol() });
+
//check the primary placeholder is existing at least for the second english text
if (!contains(original.second, "%x"))
throw ParsingError({ L"Plural form source text does not contain %x placeholder", scn_.posRow(), scn_.posCol() });
- if (!isValidUtf(original.first) || !isValidUtf(original.second))
- throw ParsingError({ L"Translation source text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol() });
- if (std::any_of(translation.begin(), translation.end(), [](const std::string& pform) { return !isValidUtf(pform); }))
- throw ParsingError({ L"Translation text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol() });
-
if (!translation.empty())
{
//check for invalid number of plural forms
@@ -578,29 +576,108 @@ private:
auto checkSecondaryPlaceholder = [&](const std::string& placeholder)
{
- //make sure secondary placeholder is used in both source texts (or none)
- if (zen::contains(original.first, placeholder) ||
- zen::contains(original.second, placeholder))
- {
- if (!zen::contains(original.first, placeholder) ||
- !zen::contains(original.second, placeholder))
- throw ParsingError({ zen::replaceCpy<std::wstring>(L"Placeholder %x missing in plural form source", L"%x", zen::utfTo<std::wstring>(placeholder)), scn_.posRow(), scn_.posCol() });
-
- //secondary placeholder is required for all plural forms
- if (std::any_of(translation.begin(), translation.end(), [&](const std::string& pform) { return !zen::contains(pform, placeholder); }))
- throw ParsingError({ zen::replaceCpy<std::wstring>(L"Placeholder %x missing in plural form translation", L"%x", zen::utfTo<std::wstring>(placeholder)), scn_.posRow(), scn_.posCol() });
- }
+ //make sure secondary placeholder is used for both source texts (or none) and all plural forms
+ if (contains(original.first, placeholder) ||
+ contains(original.second, placeholder))
+ for (const std::string& str : allTexts)
+ if (!contains(str, placeholder))
+ throw ParsingError({ zen::replaceCpy<std::wstring>(L"Placeholder %x missing in text", L"%x", zen::utfTo<std::wstring>(placeholder)), scn_.posRow(), scn_.posCol() });
};
checkSecondaryPlaceholder("%y");
checkSecondaryPlaceholder("%z");
//if source is a one-liner, so should be the translation
if (!contains(original.first, '\n') && !contains(original.second, '\n') &&
- std::any_of(translation.begin(), translation.end(), [](const std::string& pform) { return contains(pform, '\n'); }))
- throw ParsingError({ L"Source text is a one-liner, but at least one plural form translation consists of multiple lines", scn_.posRow(), scn_.posCol() });
+ /**/std::any_of(translation.begin(), translation.end(), [](const std::string& pform) { return contains(pform, '\n'); }))
+ /**/throw ParsingError({ L"Source text is a one-liner, but at least one plural form translation consists of multiple lines", scn_.posRow(), scn_.posCol() });
+
+ //if source contains ampersand to mark menu accellerator key, so must translation
+ const size_t ampCount = ampersandTokenCount(original.first);
+ for (const std::string& str : allTexts)
+ if (ampCount > 1 || ampersandTokenCount(str) != ampCount)
+ throw ParsingError({ L"Source and translation both need exactly one & character to mark a menu item access key or none at all", scn_.posRow(), scn_.posCol() });
+
+ //ampersand at the end makes buggy wxWidgets crash miserably
+ for (const std::string& str : allTexts)
+ if (endsWithSingleAmp(str))
+ throw ParsingError({ L"The & character to mark a menu item access key must not occur at the end of a string", scn_.posRow(), scn_.posCol() });
+
+ //if source ends with colon, so must translation (note: character seems to be universally used, even for asian and arabic languages)
+ if (endsWith(original.first, ":") || endsWith(original.second, ":"))
+ for (const std::string& str : allTexts)
+ if (!endsWithColon(str))
+ throw ParsingError({ L"Source text ends with a colon character \":\", but translation does not", scn_.posRow(), scn_.posCol() });
+
+ //if source ends with a period, so must translation (note: character seems to be universally used, even for asian and arabic languages)
+ if (endsWithSingleDot(original.first) || endsWithSingleDot(original.second))
+ for (const std::string& str : allTexts)
+ if (!endsWithSingleDot(str))
+ throw ParsingError({ L"Source text ends with a punctuation mark character \".\", but translation does not", scn_.posRow(), scn_.posCol() });
+
+ //if source ends with an ellipsis, so must translation (note: character seems to be universally used, even for asian and arabic languages)
+ if (endsWithEllipsis(original.first) || endsWithEllipsis(original.second))
+ for (const std::string& str : allTexts)
+ if (!endsWithEllipsis(str))
+ throw ParsingError({ L"Source text ends with an ellipsis \"...\", but translation does not", scn_.posRow(), scn_.posCol() });
+
+ //check for not-to-be-translated texts
+ for (const char* fixedStr : { "FreeFileSync", "RealTimeSync", "ffs_gui", "ffs_batch", "ffs_tmp", "GlobalSettings.xml" })
+ if (contains(original.first, fixedStr) || contains(original.second, fixedStr))
+ for (const std::string& str : allTexts)
+ if (!contains(str, fixedStr))
+ throw ParsingError({ replaceCpy<std::wstring>(L"Misspelled \"%x\" in translation", L"%x", utfTo<std::wstring>(fixedStr)), scn_.posRow(), scn_.posCol() });
+
+ //some languages (French!) put a space before punctuation mark => must be a no-brake space!
+ for (const char punctChar : std::string(".!?:;$#"))
+ for (const std::string& str : allTexts)
+ if (contains(str, std::string(" ") + punctChar))
+ throw ParsingError({ replaceCpy<std::wstring>(L"Text contains a space before the \"%x\" character. Are line-breaks really allowed here?"
+ " Maybe this should be a \"non-breaking space\" (Windows: Alt 0160 UTF8: 0xC2 0xA0)?",
+ L"%x", utfTo<std::wstring>(punctChar)), scn_.posRow(), scn_.posCol() });
}
}
+ //helper
+ static size_t ampersandTokenCount(const std::string& str)
+ {
+ using namespace zen;
+ const std::string tmp = replaceCpy(str, "&&", ""); //make sure to not catch && which windows resolves as just one & for display!
+ return std::count(tmp.begin(), tmp.end(), '&');
+ }
+
+ static bool endsWithSingleAmp(const std::string& s)
+ {
+ using namespace zen;
+ return endsWith(s, "&") && !endsWith(s, "&&");
+ }
+
+ static bool endsWithEllipsis(const std::string& s)
+ {
+ using namespace zen;
+ return endsWith(s, "...") ||
+ endsWith(s, "\xe2\x80\xa6"); //narrow ellipsis (spanish?)
+ }
+
+ static bool endsWithColon(const std::string& s)
+ {
+ using namespace zen;
+ return endsWith(s, ":") ||
+ endsWith(s, "\xef\xbc\x9a"); //chinese colon
+ }
+
+ static bool endsWithSingleDot(const std::string& s)
+ {
+ using namespace zen;
+ return (endsWith(s, ".") ||
+ endsWith(s, "\xe0\xa5\xa4") || //hindi period
+ endsWith(s, "\xe3\x80\x82")) //chinese period
+ &&
+ (!endsWith(s, "..") &&
+ !endsWith(s, "\xe0\xa5\xa4\xe0\xa5\xa4") && //hindi period
+ !endsWith(s, "\xe3\x80\x82\xe3\x80\x82")); //chinese period
+ }
+
+
void nextToken() { tk_ = scn_.nextToken(); }
const Token& token() const { return tk_; }
diff --git a/FreeFileSync/Source/base/perf_check.cpp b/FreeFileSync/Source/base/perf_check.cpp
index ae4a8cc8..7ea523e8 100755
--- a/FreeFileSync/Source/base/perf_check.cpp
+++ b/FreeFileSync/Source/base/perf_check.cpp
@@ -20,9 +20,9 @@ PerfCheck::PerfCheck(std::chrono::milliseconds windowSizeRemTime,
windowMax_(std::max(windowSizeRemTime, windowSizeSpeed)) {}
-void PerfCheck::addSample(std::chrono::nanoseconds timeElapsed, int itemsCurrent, double dataCurrent)
+void PerfCheck::addSample(std::chrono::nanoseconds timeElapsed, int itemsCurrent, double bytesCurrent)
{
- samples_.insert(samples_.end(), { timeElapsed, { itemsCurrent, dataCurrent }}); //use fact that time is monotonously ascending
+ samples_.insert(samples_.end(), { timeElapsed, { itemsCurrent, bytesCurrent }}); //use fact that time is monotonously ascending
//remove all records earlier than "now - windowMax"
auto it = samples_.upper_bound(timeElapsed - windowMax_);
@@ -49,49 +49,38 @@ std::tuple<double /*timeDelta*/, int /*itemsDelta*/, double /*bytesDelta*/> Perf
}
-Opt<double> PerfCheck::getRemainingTimeSec(double dataRemaining) const
+std::optional<double> PerfCheck::getRemainingTimeSec(double bytesRemaining) const
{
- double timeDelta = 0;
- int itemsDelta = 0;
- double bytesDelta = 0;
- std::tie(timeDelta, itemsDelta, bytesDelta) = getBlockDeltas(windowSizeRemTime_);
- //const auto [timeDelta, itemsDelta, bytesDelta] = getBlockDeltas(windowSizeRemTime_); C++17
+ const auto [timeDelta, itemsDelta, bytesDelta] = getBlockDeltas(windowSizeRemTime_);
//objects model logical operations *NOT* disk accesses, so we better play safe and use "bytes" only!
- //http://sourceforge.net/p/freefilesync/feature-requests/197/
if (!numeric::isNull(bytesDelta)) //sign(dataRemaining) != sign(bytesDelta) usually an error, so show it!
- return dataRemaining * timeDelta / bytesDelta;
+ return bytesRemaining * timeDelta / bytesDelta;
- return NoValue();
+ return {};
}
-Opt<std::wstring> PerfCheck::getBytesPerSecond() const
+std::optional<std::wstring> PerfCheck::getBytesPerSecond() const
{
- double timeDelta = 0;
- int itemsDelta = 0;
- double bytesDelta = 0;
- std::tie(timeDelta, itemsDelta, bytesDelta) = getBlockDeltas(windowSizeSpeed_);
+ const auto [timeDelta, itemsDelta, bytesDelta] = getBlockDeltas(windowSizeSpeed_);
if (!numeric::isNull(timeDelta))
return formatFilesizeShort(numeric::round(bytesDelta / timeDelta)) + _("/sec");
- return NoValue();
+ return {};
}
-Opt<std::wstring> PerfCheck::getItemsPerSecond() const
+std::optional<std::wstring> PerfCheck::getItemsPerSecond() const
{
- double timeDelta = 0;
- int itemsDelta = 0;
- double bytesDelta = 0;
- std::tie(timeDelta, itemsDelta, bytesDelta) = getBlockDeltas(windowSizeSpeed_);
+ const auto [timeDelta, itemsDelta, bytesDelta] = getBlockDeltas(windowSizeSpeed_);
if (!numeric::isNull(timeDelta))
return replaceCpy(_("%x items/sec"), L"%x", formatTwoDigitPrecision(itemsDelta / timeDelta));
- return NoValue();
+ return {};
}
diff --git a/FreeFileSync/Source/base/perf_check.h b/FreeFileSync/Source/base/perf_check.h
index b4845a90..a00aae84 100755
--- a/FreeFileSync/Source/base/perf_check.h
+++ b/FreeFileSync/Source/base/perf_check.h
@@ -10,7 +10,7 @@
#include <map>
#include <chrono>
#include <string>
-#include <zen/optional.h>
+#include <zen/legacy_compiler.h> //#includes <optional>
namespace fff
@@ -21,11 +21,11 @@ public:
PerfCheck(std::chrono::milliseconds windowSizeRemTime,
std::chrono::milliseconds windowSizeSpeed);
- void addSample(std::chrono::nanoseconds timeElapsed, int itemsCurrent, double dataCurrent);
+ void addSample(std::chrono::nanoseconds timeElapsed, int itemsCurrent, double bytesCurrent);
- zen::Opt<double> getRemainingTimeSec(double dataRemaining) const;
- zen::Opt<std::wstring> getBytesPerSecond() const; //for window
- zen::Opt<std::wstring> getItemsPerSecond() const; //
+ std::optional<double> getRemainingTimeSec(double bytesRemaining) const;
+ std::optional<std::wstring> getBytesPerSecond() const; //for window
+ std::optional<std::wstring> getItemsPerSecond() const; //
private:
struct Record
diff --git a/FreeFileSync/Source/base/process_xml.cpp b/FreeFileSync/Source/base/process_xml.cpp
index e9a6fd47..da7fa2e7 100755
--- a/FreeFileSync/Source/base/process_xml.cpp
+++ b/FreeFileSync/Source/base/process_xml.cpp
@@ -9,22 +9,22 @@
#include <zen/file_access.h>
#include <zen/file_io.h>
#include <zen/xml_io.h>
-#include <zen/optional.h>
#include <zen/time.h>
#include <wx/intl.h>
#include "ffs_paths.h"
-//#include "../fs/concrete.h"
+#include "../fs/concrete.h"
using namespace zen;
using namespace fff; //functionally needed for correct overload resolution!!!
+//using AFS = AbstractFileSystem;
namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
-const int XML_FORMAT_VER_GLOBAL = 10; //2018-07-27
-const int XML_FORMAT_VER_FFS_CFG = 13; //2018-07-14
+const int XML_FORMAT_VER_GLOBAL = 11; //2018-09-09
+const int XML_FORMAT_VER_FFS_CFG = 14; //2018-08-13
//-------------------------------------------------------------------------------------------------------------------------------
}
@@ -914,9 +914,9 @@ bool readStruc(const XmlElement& input, ConfigFileItem& value)
const bool rv3 = in.attribute("LastSync", value.lastSyncTime);
- Zstring logPathRaw;
- const bool rv4 = in.attribute("LogPath", logPathRaw);
- if (rv4) value.logFilePath = resolveFreeFileSyncDriveMacro(logPathRaw);
+ Zstring logPathPhrase;
+ const bool rv4 = in.attribute("LogPath", logPathPhrase);
+ if (rv4) value.logFilePath = createAbstractPath(resolveFreeFileSyncDriveMacro(logPathPhrase));
return rv1 && rv2 && rv3 && rv4;
}
@@ -928,7 +928,11 @@ void writeStruc(const ConfigFileItem& value, XmlElement& output)
out.attribute("Result", value.logResult);
out.attribute("CfgPath", substituteFreeFileSyncDriveLetter(value.cfgFilePath));
out.attribute("LastSync", value.lastSyncTime);
- out.attribute("LogPath", substituteFreeFileSyncDriveLetter(value.logFilePath));
+
+ if (std::optional<Zstring> nativePath = AFS::getNativeItemPath(value.logFilePath))
+ out.attribute("LogPath", substituteFreeFileSyncDriveLetter(*nativePath));
+ else
+ out.attribute("LogPath", AFS::getInitPathPhrase(value.logFilePath));
}
//TODO: remove after migration! 2018-07-27
@@ -1227,7 +1231,6 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg, int formatVer)
if (formatVer < 8)
inMain["OnCompletion"](mainCfg.postSyncCommand);
else
- {
//TODO: remove if parameter migration after some time! 2018-02-24
if (formatVer < 10)
inMain["IgnoreErrors"](mainCfg.ignoreErrors);
@@ -1238,6 +1241,17 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg, int formatVer)
inMain["Errors"].attribute("Delay", mainCfg.automaticRetryDelay);
}
+ //TODO: remove if parameter migration after some time! 2018-08-13
+ if (formatVer < 14)
+ ; //path will be extracted from BatchExclusiveConfig
+ else
+ inMain["LogFolder"](mainCfg.altLogFolderPathPhrase);
+
+ //TODO: remove if parameter migration after some time! 2017-10-24
+ if (formatVer < 8)
+ inMain["OnCompletion"](mainCfg.postSyncCommand);
+ else
+ {
inMain["PostSyncCommand"](mainCfg.postSyncCommand);
inMain["PostSyncCommand"].attribute("Condition", mainCfg.postSyncCondition);
}
@@ -1318,18 +1332,6 @@ void readConfig(const XmlIn& in, BatchExclusiveConfig& cfg, int formatVer)
}
else
inBatchCfg["PostSyncAction"](cfg.postSyncAction);
-
- //TODO: remove if clause after migration! 2018-07-12
- if (formatVer < 13)
- {
- inBatchCfg["LogfileFolder"](cfg.altLogFolderPathPhrase);
- inBatchCfg["LogfileFolder"].attribute("Limit", cfg.altLogfileCountMax);
- }
- else
- {
- inBatchCfg["LogfileFolder"](cfg.altLogFolderPathPhrase);
- inBatchCfg["LogfileFolder"].attribute("MaxCount", cfg.altLogfileCountMax);
- }
}
@@ -1338,6 +1340,13 @@ void readConfig(const XmlIn& in, XmlBatchConfig& cfg, int formatVer)
readConfig(in, cfg.mainCfg, formatVer);
readConfig(in, cfg.batchExCfg, formatVer);
+ //TODO: remove if clause after migration! 2018-08-13
+ if (formatVer < 14)
+ {
+ XmlIn inBatchCfg = in[formatVer < 10 ? "BatchConfig" : "Batch"];
+ inBatchCfg["LogfileFolder"](cfg.mainCfg.altLogFolderPathPhrase);
+ }
+
//TODO: remove if clause after migration! 2017-10-24
if (formatVer < 8)
{
@@ -1396,6 +1405,11 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inGeneral["NotificationSound" ].attribute("SyncFinished", cfg.soundFileSyncFinished);
inGeneral["ProgressDialog" ].attribute("AutoClose", cfg.autoCloseProgressDialog);
+ //TODO: remove if parameter migration after some time! 2018-08-13
+ if (formatVer < 14)
+ if (cfg.logfilesMaxAgeDays == 14) //default value was too small
+ cfg.logfilesMaxAgeDays = XmlGlobalSettings().logfilesMaxAgeDays;
+
//TODO: remove old parameter after migration! 2018-02-04
if (formatVer < 8)
{
@@ -1431,7 +1445,6 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inOpt["WarnDependentBaseFolders" ].attribute("Show", cfg.warnDlgs.warnDependentBaseFolders);
inOpt["WarnDirectoryLockFailed" ].attribute("Show", cfg.warnDlgs.warnDirectoryLockFailed);
inOpt["WarnVersioningFolderPartOfSync"].attribute("Show", cfg.warnDlgs.warnVersioningFolderPartOfSync);
- inOpt["WarnBatchLoggingDeprecated" ].attribute("Show", cfg.warnDlgs.warnBatchLoggingDeprecated);
}
//gui specific global settings (optional)
@@ -1445,22 +1458,27 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inWnd.attribute("PosY", cfg.gui.mainDlg.dlgPos.y);
inWnd.attribute("Maximized", cfg.gui.mainDlg.isMaximized);
- XmlIn inCopyTo = inWnd["ManualCopyTo"];
- inCopyTo.attribute("KeepRelativePaths", cfg.gui.mainDlg.copyToCfg.keepRelPaths);
- inCopyTo.attribute("OverwriteIfExists", cfg.gui.mainDlg.copyToCfg.overwriteIfExists);
-
- XmlIn inCopyToHistory = inCopyTo["FolderHistory"];
- inCopyToHistory(cfg.gui.mainDlg.copyToCfg.folderHistory);
- inCopyToHistory.attribute("LastUsedPath", cfg.gui.mainDlg.copyToCfg.lastUsedPath);
- inCopyToHistory.attribute("MaxSize", cfg.gui.mainDlg.copyToCfg.historySizeMax);
+ //###########################################################
//TODO: remove old parameter after migration! 2018-02-04
if (formatVer < 8)
inWnd["CaseSensitiveSearch"].attribute("Enabled", cfg.gui.mainDlg.textSearchRespectCase);
else
- inWnd["Search"].attribute("CaseSensitive", cfg.gui.mainDlg.textSearchRespectCase);
+ //TODO: remove if parameter migration after some time! 2018-09-09
+ if (formatVer < 11)
+ inWnd["Search"].attribute("CaseSensitive", cfg.gui.mainDlg.textSearchRespectCase);
+ else
+ inWnd["SearchPanel"].attribute("CaseSensitive", cfg.gui.mainDlg.textSearchRespectCase);
+
+ //TODO: remove if parameter migration after some time! 2018-09-09
+ if (formatVer < 11)
+ inWnd["FolderPairsVisible" ].attribute("Max", cfg.gui.mainDlg.maxFolderPairsVisible);
- inWnd["FolderPairsVisible" ].attribute("Max", cfg.gui.mainDlg.maxFolderPairsVisible);
+ //TODO: remove if parameter migration after some time! 2018-09-09
+ if (formatVer < 11)
+ ;
+ else
+ inWnd["FolderHistory" ].attribute("MaxSize", cfg.gui.mainDlg.folderHistItemsMax);
//###########################################################
@@ -1485,7 +1503,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inGui["ConfigHistory"](cfgHist);
for (const Zstring& cfgPath : cfgHist)
- cfg.gui.mainDlg.cfgFileHistory.emplace_back(cfgPath, 0, Zstring(), SyncResult::FINISHED_WITH_SUCCESS);
+ cfg.gui.mainDlg.cfgFileHistory.emplace_back(cfgPath, 0, getNullPath(), SyncResult::FINISHED_WITH_SUCCESS);
}
//TODO: remove after migration! 2018-07-27
else if (formatVer < 10)
@@ -1496,7 +1514,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inConfig["Configurations"](cfgFileHistory);
for (const ConfigFileItemV9& item : cfgFileHistory)
- cfg.gui.mainDlg.cfgFileHistory.emplace_back(item.filePath, item.lastSyncTime, Zstring(), SyncResult::FINISHED_WITH_SUCCESS);
+ cfg.gui.mainDlg.cfgFileHistory.emplace_back(item.filePath, item.lastSyncTime, getNullPath(), SyncResult::FINISHED_WITH_SUCCESS);
}
else
{
@@ -1540,7 +1558,16 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inFileGrid.attribute("ShowIcons", cfg.gui.mainDlg.showIcons);
inFileGrid.attribute("IconSize", cfg.gui.mainDlg.iconSize);
inFileGrid.attribute("SashOffset", cfg.gui.mainDlg.sashOffset);
- inFileGrid.attribute("HistoryMaxSize", cfg.gui.mainDlg.folderHistItemsMax);
+
+ //TODO: remove if parameter migration after some time! 2018-09-09
+ if (formatVer < 11)
+ ;
+ else
+ inFileGrid.attribute("MaxFolderPairsShown", cfg.gui.mainDlg.maxFolderPairsVisible);
+
+ //TODO: remove if parameter migration after some time! 2018-09-09
+ if (formatVer < 11)
+ inFileGrid.attribute("HistoryMaxSize", cfg.gui.mainDlg.folderHistItemsMax);
inFileGrid["ColumnsLeft"].attribute("PathFormat", cfg.gui.mainDlg.itemPathFormatLeftGrid);
inFileGrid["ColumnsLeft"](cfg.gui.mainDlg.columnAttribLeft);
@@ -1560,6 +1587,19 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inGui["FolderHistoryLeft"].attribute("MaxSize", cfg.gui.mainDlg.folderHistItemsMax);
}
+ //TODO: remove if parameter migration after some time! 2018-09-09
+ if (formatVer < 11)
+ if (cfg.gui.mainDlg.folderHistItemsMax == 15) //default value was too small
+ cfg.gui.mainDlg.folderHistItemsMax = XmlGlobalSettings().gui.mainDlg.folderHistItemsMax;
+
+ //###########################################################
+ XmlIn inCopyTo = inWnd["ManualCopyTo"];
+ inCopyTo.attribute("KeepRelativePaths", cfg.gui.mainDlg.copyToCfg.keepRelPaths);
+ inCopyTo.attribute("OverwriteIfExists", cfg.gui.mainDlg.copyToCfg.overwriteIfExists);
+
+ XmlIn inCopyToHistory = inCopyTo["FolderHistory"];
+ inCopyToHistory(cfg.gui.mainDlg.copyToCfg.folderHistory);
+ inCopyToHistory.attribute("LastUsedPath", cfg.gui.mainDlg.copyToCfg.lastUsedPath);
//###########################################################
inWnd["DefaultViewFilter"](cfg.gui.mainDlg.viewFilterDefault);
@@ -1955,6 +1995,8 @@ void writeConfig(const MainConfiguration& mainCfg, XmlOut& out)
outMain["Errors"].attribute("Retry", mainCfg.automaticRetryCount);
outMain["Errors"].attribute("Delay", mainCfg.automaticRetryDelay);
+ outMain["LogFolder"](mainCfg.altLogFolderPathPhrase);
+
outMain["PostSyncCommand"](mainCfg.postSyncCommand);
outMain["PostSyncCommand"].attribute("Condition", mainCfg.postSyncCondition);
}
@@ -1979,8 +2021,6 @@ void writeConfig(const BatchExclusiveConfig& cfg, XmlOut& out)
outBatchCfg["ProgressDialog"].attribute("AutoClose", cfg.autoCloseSummary);
outBatchCfg["ErrorDialog" ](cfg.batchErrorHandling);
outBatchCfg["PostSyncAction"](cfg.postSyncAction);
- outBatchCfg["LogfileFolder"](cfg.altLogFolderPathPhrase);
- outBatchCfg["LogfileFolder"].attribute("MaxCount", cfg.altLogfileCountMax);
}
@@ -2025,7 +2065,6 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
outOpt["WarnDependentBaseFolders" ].attribute("Show", cfg.warnDlgs.warnDependentBaseFolders);
outOpt["WarnDirectoryLockFailed" ].attribute("Show", cfg.warnDlgs.warnDirectoryLockFailed);
outOpt["WarnVersioningFolderPartOfSync"].attribute("Show", cfg.warnDlgs.warnVersioningFolderPartOfSync);
- outOpt["WarnBatchLoggingDeprecated" ].attribute("Show", cfg.warnDlgs.warnBatchLoggingDeprecated);
//gui specific global settings (optional)
XmlOut outGui = out["Gui"];
@@ -2038,18 +2077,9 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
outWnd.attribute("PosY", cfg.gui.mainDlg.dlgPos.y);
outWnd.attribute("Maximized", cfg.gui.mainDlg.isMaximized);
- XmlOut outCopyTo = outWnd["ManualCopyTo"];
- outCopyTo.attribute("KeepRelativePaths", cfg.gui.mainDlg.copyToCfg.keepRelPaths);
- outCopyTo.attribute("OverwriteIfExists", cfg.gui.mainDlg.copyToCfg.overwriteIfExists);
-
- XmlOut outCopyToHistory = outCopyTo["FolderHistory"];
- outCopyToHistory(cfg.gui.mainDlg.copyToCfg.folderHistory);
- outCopyToHistory.attribute("LastUsedPath", cfg.gui.mainDlg.copyToCfg.lastUsedPath);
- outCopyToHistory.attribute("MaxSize", cfg.gui.mainDlg.copyToCfg.historySizeMax);
-
- outWnd["Search" ].attribute("CaseSensitive", cfg.gui.mainDlg.textSearchRespectCase);
- outWnd["FolderPairsVisible"].attribute("Max", cfg.gui.mainDlg.maxFolderPairsVisible);
-
+ //###########################################################
+ outWnd["SearchPanel" ].attribute("CaseSensitive", cfg.gui.mainDlg.textSearchRespectCase);
+ outWnd["FolderHistory"].attribute("MaxSize", cfg.gui.mainDlg.folderHistItemsMax);
//###########################################################
XmlOut outConfig = outWnd["ConfigPanel"];
@@ -2084,7 +2114,7 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
outFileGrid.attribute("ShowIcons", cfg.gui.mainDlg.showIcons);
outFileGrid.attribute("IconSize", cfg.gui.mainDlg.iconSize);
outFileGrid.attribute("SashOffset", cfg.gui.mainDlg.sashOffset);
- outFileGrid.attribute("HistoryMaxSize", cfg.gui.mainDlg.folderHistItemsMax);
+ outFileGrid.attribute("MaxFolderPairsShown", cfg.gui.mainDlg.maxFolderPairsVisible);
outFileGrid["ColumnsLeft"].attribute("PathFormat", cfg.gui.mainDlg.itemPathFormatLeftGrid);
outFileGrid["ColumnsLeft"](cfg.gui.mainDlg.columnAttribLeft);
@@ -2097,6 +2127,14 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
outFileGrid["FolderHistoryRight"](cfg.gui.mainDlg.folderHistoryRight);
//###########################################################
+ XmlOut outCopyTo = outWnd["ManualCopyTo"];
+ outCopyTo.attribute("KeepRelativePaths", cfg.gui.mainDlg.copyToCfg.keepRelPaths);
+ outCopyTo.attribute("OverwriteIfExists", cfg.gui.mainDlg.copyToCfg.overwriteIfExists);
+
+ XmlOut outCopyToHistory = outCopyTo["FolderHistory"];
+ outCopyToHistory(cfg.gui.mainDlg.copyToCfg.folderHistory);
+ outCopyToHistory.attribute("LastUsedPath", cfg.gui.mainDlg.copyToCfg.lastUsedPath);
+ //###########################################################
outWnd["DefaultViewFilter"](cfg.gui.mainDlg.viewFilterDefault);
outWnd["Perspective" ](cfg.gui.mainDlg.guiPerspectiveLast);
diff --git a/FreeFileSync/Source/base/process_xml.h b/FreeFileSync/Source/base/process_xml.h
index cd11a3b8..17cb884a 100755
--- a/FreeFileSync/Source/base/process_xml.h
+++ b/FreeFileSync/Source/base/process_xml.h
@@ -72,11 +72,6 @@ struct BatchExclusiveConfig
bool runMinimized = false;
bool autoCloseSummary = false;
PostSyncAction postSyncAction = PostSyncAction::NONE;
- warn_static("consider for removal after FFS 10.3 release")
-#if 1
- Zstring altLogFolderPathPhrase; //store log file copy (in addition to %appdata%\FreeFileSync\Logs): MANDATORY if altLogfileCountMax != 0
- int altLogfileCountMax = 0; //max log file count; 0 := don't save logfiles; < 0 := no limit
-#endif
};
@@ -115,10 +110,6 @@ struct WarningDialogs
bool warnInputFieldEmpty = true;
bool warnDirectoryLockFailed = true;
bool warnVersioningFolderPartOfSync = true;
- warn_static("consider for removal after FFS 10.3 release")
-#if 1
- bool warnBatchLoggingDeprecated = true;
-#endif
};
inline bool operator==(const WarningDialogs& lhs, const WarningDialogs& rhs)
{
@@ -132,8 +123,7 @@ inline bool operator==(const WarningDialogs& lhs, const WarningDialogs& rhs)
lhs.warnRecyclerMissing == rhs.warnRecyclerMissing &&
lhs.warnInputFieldEmpty == rhs.warnInputFieldEmpty &&
lhs.warnDirectoryLockFailed == rhs.warnDirectoryLockFailed &&
- lhs.warnVersioningFolderPartOfSync == rhs.warnVersioningFolderPartOfSync &&
- lhs.warnBatchLoggingDeprecated == rhs.warnBatchLoggingDeprecated;
+ lhs.warnVersioningFolderPartOfSync == rhs.warnVersioningFolderPartOfSync;
}
inline bool operator!=(const WarningDialogs& lhs, const WarningDialogs& rhs) { return !(lhs == rhs); }
@@ -185,11 +175,11 @@ struct XmlGlobalSettings
bool copyFilePermissions = false;
int fileTimeTolerance = 2; //max. allowed file time deviation; < 0 means unlimited tolerance; default 2s: FAT vs NTFS
- int folderAccessTimeout = 20; //unit: [s]; consider CD-ROM insert or hard disk spin up time from sleep
+ std::chrono::seconds folderAccessTimeout{20}; //consider CD-ROM insert or hard disk spin up time from sleep
bool runWithBackgroundPriority = false;
bool createLockFile = true;
bool verifyFileCopy = false;
- int logfilesMaxAgeDays = 14; //<= 0 := no limit; for log files under %appdata%\FreeFileSync\Logs
+ int logfilesMaxAgeDays = 30; //<= 0 := no limit; for log files under %AppData%\FreeFileSync\Logs
Zstring soundFileCompareFinished;
Zstring soundFileSyncFinished = Zstr("gong.wav");
@@ -208,15 +198,6 @@ struct XmlGlobalSettings
wxSize dlgSize;
bool isMaximized = false;
- struct
- {
- bool keepRelPaths = false;
- bool overwriteIfExists = false;
- Zstring lastUsedPath;
- std::vector<Zstring> folderHistory;
- size_t historySizeMax = 15;
- } copyToCfg;
-
bool textSearchRespectCase = false; //good default for Linux, too!
int maxFolderPairsVisible = 6;
@@ -234,9 +215,18 @@ struct XmlGlobalSettings
bool treeGridLastSortAscending = getDefaultSortDirection(treeGridLastSortColumnDefault); //
std::vector<ColAttributesTree> treeGridColumnAttribs = getTreeGridDefaultColAttribs();
+ size_t folderHistItemsMax = 20;
+
+ struct
+ {
+ bool keepRelPaths = false;
+ bool overwriteIfExists = false;
+ Zstring lastUsedPath;
+ std::vector<Zstring> folderHistory;
+ } copyToCfg;
+
std::vector<Zstring> folderHistoryLeft;
std::vector<Zstring> folderHistoryRight;
- size_t folderHistItemsMax = 15;
bool showIcons = true;
FileIconSize iconSize = ICON_SIZE_SMALL;
int sashOffset = 0;
diff --git a/FreeFileSync/Source/base/resolve_path.cpp b/FreeFileSync/Source/base/resolve_path.cpp
index b40b91ce..f8eae4d9 100755
--- a/FreeFileSync/Source/base/resolve_path.cpp
+++ b/FreeFileSync/Source/base/resolve_path.cpp
@@ -4,7 +4,6 @@
#include <zen/time.h>
#include <zen/thread.h>
#include <zen/utf.h>
-#include <zen/optional.h>
#include <zen/scope_guard.h>
#include <zen/globals.h>
#include <zen/file_access.h>
@@ -17,13 +16,13 @@ using namespace zen;
namespace
{
-Opt<Zstring> getEnvironmentVar(const Zstring& name)
+std::optional<Zstring> getEnvironmentVar(const Zstring& name)
{
assert(runningMainThread()); //getenv() is not thread-safe!
const char* buffer = ::getenv(name.c_str()); //no extended error reporting
if (!buffer)
- return NoValue();
+ return {};
Zstring value(buffer);
//some postprocessing:
@@ -56,7 +55,7 @@ Zstring resolveRelativePath(const Zstring& relativePath)
*/
if (startsWith(relativePath, "~/") || relativePath == "~")
{
- Opt<Zstring> homeDir = getEnvironmentVar("HOME");
+ std::optional<Zstring> homeDir = getEnvironmentVar("HOME");
if (!homeDir)
return relativePath; //error! no further processing!
@@ -79,7 +78,7 @@ Zstring resolveRelativePath(const Zstring& relativePath)
//returns value if resolved
-Opt<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-characters
+std::optional<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-characters
{
//there exist environment variables named %TIME%, %DATE% so check for our internal macros first!
if (strEqual(macro, Zstr("time"), CmpAsciiNoCase()))
@@ -111,11 +110,11 @@ Opt<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-characters
if (resolveTimePhrase(Zstr("sec" ), Zstr("%S"))) return timeStr;
//try to resolve as environment variable
- if (Opt<Zstring> value = getEnvironmentVar(macro))
+ if (std::optional<Zstring> value = getEnvironmentVar(macro))
return *value;
- return NoValue();
+ return {};
}
const Zchar MACRO_SEP = Zstr('%');
@@ -133,7 +132,7 @@ Zstring fff::expandMacros(const Zstring& text)
Zstring potentialMacro = beforeFirst(rest, MACRO_SEP, IF_MISSING_RETURN_NONE);
Zstring postfix = afterFirst (rest, MACRO_SEP, IF_MISSING_RETURN_NONE); //text == prefix + MACRO_SEP + potentialMacro + MACRO_SEP + postfix
- if (Opt<Zstring> value = tryResolveMacro(potentialMacro))
+ if (std::optional<Zstring> value = tryResolveMacro(potentialMacro))
return prefix + *value + expandMacros(postfix);
else
return prefix + MACRO_SEP + potentialMacro + expandMacros(MACRO_SEP + postfix);
@@ -183,7 +182,7 @@ void getDirectoryAliasesRecursive(const Zstring& pathPhrase, std::set<Zstring, L
//get list of useful variables
auto addEnvVar = [&](const Zstring& envName)
{
- if (Opt<Zstring> value = getEnvironmentVar(envName))
+ if (std::optional<Zstring> value = getEnvironmentVar(envName))
macroList.emplace_back(envName, *value);
};
addEnvVar("HOME"); //Linux: /home/<user> Mac: /Users/<user>
@@ -236,7 +235,7 @@ Zstring fff::getResolvedFilePath(const Zstring& pathPhrase) //noexcept
//remove leading/trailing whitespace before allowing misinterpretation in applyLongPathPrefix()
trim(path, true, false);
- //don't remove all whitespace from right, e.g. 0xa0 may be used as part of folder name
+ //don't remove all whitespace from right, e.g. 0xa0 may be used as part of a folder name
trim(path, false, true, [](Zchar c) { return c == Zstr(' '); });
@@ -257,7 +256,7 @@ Zstring fff::getResolvedFilePath(const Zstring& pathPhrase) //noexcept
path = resolveRelativePath(path);
//remove trailing slash, unless volume root:
- if (Opt<PathComponents> pc = parsePathComponents(path))
+ if (std::optional<PathComponents> pc = parsePathComponents(path))
{
if (pc->relPath.empty())
path = pc->rootPath;
diff --git a/FreeFileSync/Source/base/status_handler.h b/FreeFileSync/Source/base/status_handler.h
index 4145b795..9a3c0948 100755
--- a/FreeFileSync/Source/base/status_handler.h
+++ b/FreeFileSync/Source/base/status_handler.h
@@ -64,7 +64,7 @@ struct Statistics
virtual ProgressStats getStatsCurrent(ProcessCallback::Phase phase) const = 0;
virtual ProgressStats getStatsTotal (ProcessCallback::Phase phase) const = 0;
- virtual zen::Opt<AbortTrigger> getAbortStatus() const = 0;
+ virtual std::optional<AbortTrigger> getAbortStatus() const = 0;
virtual const std::wstring& currentStatusText() const = 0;
};
@@ -155,7 +155,7 @@ public:
const std::wstring& currentStatusText() const override { return statusText_; }
- zen::Opt<AbortTrigger> getAbortStatus() const override { return abortRequested_; }
+ std::optional<AbortTrigger> getAbortStatus() const override { return abortRequested_; }
private:
void updateData(std::vector<ProgressStats>& num, int itemsDelta, int64_t bytesDelta)
@@ -190,17 +190,17 @@ private:
std::vector<ProgressStats> statsTotal_ = std::vector<ProgressStats>(4); //
std::wstring statusText_;
- zen::Opt<AbortTrigger> abortRequested_;
+ std::optional<AbortTrigger> abortRequested_;
};
//------------------------------------------------------------------------------------------
inline
-void delayAndCountDown(const std::wstring& operationName, size_t delayInSec, const std::function<void(const std::wstring& msg)>& notifyStatus)
+void delayAndCountDown(const std::wstring& operationName, std::chrono::seconds delay, const std::function<void(const std::wstring& msg)>& notifyStatus)
{
assert(notifyStatus && !zen::endsWith(operationName, L"."));
- const auto delayUntil = std::chrono::steady_clock::now() + std::chrono::seconds(delayInSec);
+ const auto delayUntil = std::chrono::steady_clock::now() + delay;
for (auto now = std::chrono::steady_clock::now(); now < delayUntil; now = std::chrono::steady_clock::now())
{
const auto timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(delayUntil - now).count();
diff --git a/FreeFileSync/Source/base/status_handler_impl.h b/FreeFileSync/Source/base/status_handler_impl.h
index d152149f..21f108de 100755
--- a/FreeFileSync/Source/base/status_handler_impl.h
+++ b/FreeFileSync/Source/base/status_handler_impl.h
@@ -7,7 +7,6 @@
#ifndef STATUS_HANDLER_IMPL_H_07682758976
#define STATUS_HANDLER_IMPL_H_07682758976
-#include <zen/optional.h>
#include <zen/file_error.h>
#include <zen/thread.h>
#include "process_callback.h"
@@ -40,6 +39,7 @@ public:
std::lock_guard<std::mutex> dummy(lockCurrentStatus_);
if (ThreadStatus* ts = getThreadStatus()) //call while holding "lockCurrentStatus_" lock!!
ts->statusMsg = msg;
+ else assert(false);
}
zen::interruptionPoint(); //throw ThreadInterruption
}
@@ -80,8 +80,8 @@ public:
ProcessCallback::Response rv = *errorResponse_;
- errorRequest_ = zen::NoValue();
- errorResponse_ = zen::NoValue();
+ errorRequest_ = {};
+ errorResponse_ = {};
dummy.unlock(); //optimization for condition_variable::notify_all()
conditionReadyForNewRequest_.notify_all(); //=> spurious wake-up for AsyncCallback::logInfo()
@@ -111,7 +111,7 @@ public:
if (logInfoRequest_)
{
cb.logInfo(*logInfoRequest_);
- logInfoRequest_ = zen::NoValue();
+ logInfoRequest_ = {};
conditionReadyForNewRequest_.notify_all(); //=> spurious wake-up for AsyncCallback::reportError()
}
if (finishNowRequest_)
@@ -131,6 +131,7 @@ public:
void notifyTaskBegin(size_t prio) //noexcept
{
assert(!zen::runningMainThread());
+ assert(!getThreadStatus());
const uint64_t threadId = zen::getThreadId();
std::lock_guard<std::mutex> dummy(lockCurrentStatus_);
@@ -196,10 +197,9 @@ private:
const uint64_t threadId = zen::getThreadId();
for (auto& sbp : statusByPriority_)
- for (ThreadStatus& ts : sbp) //thread cound is (hopefully) small enough so that linear search won't hurt perf
+ for (ThreadStatus& ts : sbp) //thread count is (hopefully) small enough so that linear search won't hurt perf
if (ts.threadId == threadId)
return &ts;
- assert(false);
return nullptr;
}
@@ -274,9 +274,9 @@ private:
std::condition_variable conditionReadyForNewRequest_;
std::condition_variable conditionNewRequest;
std::condition_variable conditionHaveResponse_;
- zen::Opt<ErrorInfo> errorRequest_;
- zen::Opt<ProcessCallback::Response> errorResponse_;
- zen::Opt<std::wstring> logInfoRequest_;
+ std::optional<ErrorInfo> errorRequest_;
+ std::optional<ProcessCallback::Response> errorResponse_;
+ std::optional<std::wstring> logInfoRequest_;
bool finishNowRequest_ = false;
//---- status updates ----
diff --git a/FreeFileSync/Source/base/structures.cpp b/FreeFileSync/Source/base/structures.cpp
index bc9699f9..19c39aac 100755
--- a/FreeFileSync/Source/base/structures.cpp
+++ b/FreeFileSync/Source/base/structures.cpp
@@ -593,11 +593,11 @@ MainConfiguration fff::merge(const std::vector<MainConfiguration>& mainCfgs)
//if local config matches output global config we don't need local one
if (lpc.localCmpCfg &&
effectivelyEqual(*lpc.localCmpCfg, cmpCfgHead))
- lpc.localCmpCfg = NoValue();
+ lpc.localCmpCfg = {};
if (lpc.localSyncCfg &&
effectivelyEqual(*lpc.localSyncCfg, syncCfgHead))
- lpc.localSyncCfg = NoValue();
+ lpc.localSyncCfg = {};
if (allFiltersEqual) //use global filter in this case
lpc.localFilter = FilterConfig();
@@ -625,6 +625,13 @@ MainConfiguration fff::merge(const std::vector<MainConfiguration>& mainCfgs)
cfgOut.automaticRetryDelay = std::max_element(mainCfgs.begin(), mainCfgs.end(),
[](const MainConfiguration& lhs, const MainConfiguration& rhs) { return lhs.automaticRetryDelay < rhs.automaticRetryDelay; })->automaticRetryDelay;
+ for (const MainConfiguration& mainCfg : mainCfgs)
+ if (!mainCfg.altLogFolderPathPhrase.empty())
+ {
+ cfgOut.altLogFolderPathPhrase = mainCfg.altLogFolderPathPhrase;
+ break;
+ }
+
//cfgOut.postSyncCommand = mainCfgs[0].postSyncCommand; -> better leave at default ... !?
//cfgOut.postSyncCondition = mainCfgs[0].postSyncCondition; ->
return cfgOut;
diff --git a/FreeFileSync/Source/base/structures.h b/FreeFileSync/Source/base/structures.h
index 7f0ad9e1..8668acd2 100755
--- a/FreeFileSync/Source/base/structures.h
+++ b/FreeFileSync/Source/base/structures.h
@@ -9,8 +9,8 @@
#include <vector>
#include <memory>
+#include <chrono>
#include <zen/zstring.h>
-#include <zen/optional.h>
#include "../fs/abstract.h"
@@ -38,9 +38,9 @@ enum class SymLinkHandling
enum class SyncDirection : unsigned char //save space for use in FileSystemObject!
{
+ NONE,
LEFT,
- RIGHT,
- NONE
+ RIGHT
};
@@ -356,8 +356,8 @@ struct LocalPairConfig //enhanced folder pairs with (optional) alternate configu
LocalPairConfig(const Zstring& phraseLeft,
const Zstring& phraseRight,
- const zen::Opt<CompConfig>& cmpCfg,
- const zen::Opt<SyncConfig>& syncCfg,
+ const std::optional<CompConfig>& cmpCfg,
+ const std::optional<SyncConfig>& syncCfg,
const FilterConfig& filter) :
folderPathPhraseLeft (phraseLeft),
folderPathPhraseRight(phraseRight),
@@ -368,8 +368,8 @@ struct LocalPairConfig //enhanced folder pairs with (optional) alternate configu
Zstring folderPathPhraseLeft; //unresolved directory names as entered by user!
Zstring folderPathPhraseRight; //
- zen::Opt<CompConfig> localCmpCfg;
- zen::Opt<SyncConfig> localSyncCfg;
+ std::optional<CompConfig> localCmpCfg;
+ std::optional<SyncConfig> localSyncCfg;
FilterConfig localFilter;
};
@@ -407,7 +407,9 @@ struct MainConfiguration
bool ignoreErrors = false; //true: errors will still be logged
size_t automaticRetryCount = 0;
- size_t automaticRetryDelay = 5; //unit: [sec]
+ std::chrono::seconds automaticRetryDelay{5};
+
+ Zstring altLogFolderPathPhrase; //fill to use different log file folder (other than the default %appdata%\FreeFileSync\Logs)
Zstring postSyncCommand; //user-defined command line
PostSyncCondition postSyncCondition = PostSyncCondition::COMPLETION;
@@ -434,6 +436,7 @@ bool operator==(const MainConfiguration& lhs, const MainConfiguration& rhs)
lhs.ignoreErrors == rhs.ignoreErrors &&
lhs.automaticRetryCount == rhs.automaticRetryCount &&
lhs.automaticRetryDelay == rhs.automaticRetryDelay &&
+ lhs.altLogFolderPathPhrase == rhs.altLogFolderPathPhrase &&
lhs.postSyncCommand == rhs.postSyncCommand &&
lhs.postSyncCondition == rhs.postSyncCondition;
}
diff --git a/FreeFileSync/Source/base/synchronization.cpp b/FreeFileSync/Source/base/synchronization.cpp
index 96244abd..d55a57a8 100755
--- a/FreeFileSync/Source/base/synchronization.cpp
+++ b/FreeFileSync/Source/base/synchronization.cpp
@@ -387,7 +387,7 @@ std::vector<FolderPairSyncCfg> fff::extractSyncCfg(const MainConfiguration& main
namespace
{
inline
-Opt<SelectedSide> getTargetDirection(SyncOperation syncOp)
+std::optional<SelectedSide> getTargetDirection(SyncOperation syncOp)
{
switch (syncOp)
{
@@ -412,7 +412,7 @@ Opt<SelectedSide> getTargetDirection(SyncOperation syncOp)
case SO_UNRESOLVED_CONFLICT:
break; //nothing to do
}
- return NoValue();
+ return {};
}
@@ -456,7 +456,7 @@ void verifyFiles(const AbstractPath& sourcePath, const AbstractPath& targetPath,
{
//do like "copy /v": 1. flush target file buffers, 2. read again as usual (using OS buffers)
// => it seems OS buffers are not invalidated by this: snake oil???
- if (Opt<Zstring> nativeTargetPath = AFS::getNativeItemPath(targetPath))
+ if (std::optional<Zstring> nativeTargetPath = AFS::getNativeItemPath(targetPath))
flushFileBuffers(*nativeTargetPath); //throw FileError
if (!filesHaveSameContent(sourcePath, targetPath, notifyUnbufferedIO)) //throw FileError
@@ -485,7 +485,7 @@ AFS::ItemType getItemType(const AbstractPath& ap, std::mutex& singleThread) //th
{ return parallelScope([ap] { return AFS::getItemType(ap); /*throw FileError*/ }, singleThread); }
inline
-Opt<AFS::ItemType> getItemTypeIfExists(const AbstractPath& ap, std::mutex& singleThread) //throw FileError
+std::optional<AFS::ItemType> getItemTypeIfExists(const AbstractPath& ap, std::mutex& singleThread) //throw FileError
{ return parallelScope([ap] { return AFS::getItemTypeIfExists(ap); /*throw FileError*/ }, singleThread); }
inline
@@ -963,11 +963,16 @@ private:
RingBuffer<Workload::WorkItems> getFolderLevelWorkItems(PassNo pass, ContainerObject& parentFolder, Workload& workload);
- template <SelectedSide side>
- void setup2StepMove(FilePair& sourceObj, FilePair& targetObj); //throw FileError, ThreadInterruption
- bool createParentFolder(FileSystemObject& fsObj); //throw FileError, ThreadInterruption
- template <SelectedSide side>
- void resolveMoveConflicts(FilePair& sourceObj, FilePair& targetObj); //throw FileError, ThreadInterruption
+ enum class CmtfStatus //CreateMoveTargetFolderStatus
+ {
+ AVAILABLE,
+ NAME_CLASH,
+ SOURCE_MISSING
+ };
+ template <SelectedSide side> void setup2StepMove(FilePair& sourceFile, FilePair& targetFile); //throw FileError, ThreadInterruption
+ template <SelectedSide side> CmtfStatus createMoveTargetFolder(FileSystemObject& fsObj); //throw FileError, ThreadInterruption
+ template <SelectedSide side> void resolveMoveConflicts(FilePair& sourceFile, FilePair& targetFile); //throw FileError, ThreadInterruption
+
void prepareFileMove(FilePair& file); //throw ThreadInterruption
void synchronizeFile(FilePair& file); //
@@ -1028,9 +1033,9 @@ private:
| =================
============= | ... |
GUI <-- |Main Thread| \|/ \|/
-Callback ============= -------------------
- | Workload |
- -------------------
+Callback ============= --------------------
+ | Workload |
+ --------------------
Notes: - All threads share a single mutex, unlocked only during file I/O => do NOT require file_hierarchy.cpp classes to be thread-safe (i.e. internally synchronized)!
- Workload holds (folder-level-) items in buckets associated with each worker thread (FTP scenario: avoid CWDs)
@@ -1167,12 +1172,12 @@ bool haveNameClash(const Zstring& shortname, const List& m)
template <SelectedSide side>
-void FolderPairSyncer::setup2StepMove(FilePair& sourceObj, //throw FileError, ThreadInterruption
- FilePair& targetObj)
+void FolderPairSyncer::setup2StepMove(FilePair& sourceFile, //throw FileError, ThreadInterruption
+ FilePair& targetFile)
{
//generate (hopefully) unique file name to avoid clashing with some remnant ffs_tmp file
const Zstring shortGuid = printNumber<Zstring>(Zstr("%04x"), static_cast<unsigned int>(getCrc16(generateGUID())));
- const Zstring fileName = sourceObj.getItemName<side>();
+ const Zstring fileName = sourceFile.getItemName<side>();
auto it = find_last(fileName.begin(), fileName.end(), Zstr('.')); //gracefully handle case of missing "."
const Zstring sourceRelPathTmp = Zstring(fileName.begin(), it) + Zstr('.') + shortGuid + AFS::TEMP_FILE_ENDING;
@@ -1181,55 +1186,121 @@ void FolderPairSyncer::setup2StepMove(FilePair& sourceObj, //throw FileError, Th
//the very same (.ffs_tmp) name and is copied before the second step of the move is executed
//good news: even in this pathologic case, this may only prevent the copy of the other file, but not this move
- const AbstractPath sourcePathTmp = AFS::appendRelPath(sourceObj.base().getAbstractPath<side>(), sourceRelPathTmp);
+ const AbstractPath sourcePathTmp = AFS::appendRelPath(sourceFile.base().getAbstractPath<side>(), sourceRelPathTmp);
reportInfo(txtMovingFileXtoY_, //ThreadInterruption
- AFS::getDisplayPath(sourceObj.getAbstractPath<side>()),
+ AFS::getDisplayPath(sourceFile.getAbstractPath<side>()),
AFS::getDisplayPath(sourcePathTmp));
- parallel::renameItem(sourceObj.getAbstractPath<side>(), sourcePathTmp, singleThread_); //throw FileError, (ErrorDifferentVolume)
+ parallel::renameItem(sourceFile.getAbstractPath<side>(), sourcePathTmp, singleThread_); //throw FileError, (ErrorDifferentVolume)
//TODO: prepare2StepMove: consider ErrorDifferentVolume! e.g. symlink aliasing!
//update file hierarchy
- FilePair& tempFile = sourceObj.base().addSubFile<side>(afterLast(sourceRelPathTmp, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL), sourceObj.getAttributes<side>());
+ FilePair& tempFile = sourceFile.base().addSubFile<side>(afterLast(sourceRelPathTmp, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL), sourceFile.getAttributes<side>());
static_assert(std::is_same_v<ContainerObject::FileList, std::list<FilePair>>,
"ATTENTION: we're adding to the file list WHILE looping over it! This is only working because std::list iterators are not invalidated by insertion!");
- sourceObj.removeObject<side>(); //remove only *after* evaluating "sourceObj, side"!
+ sourceFile.removeObject<side>(); //remove only *after* evaluating "sourceFile, side"!
//note: this new item is *not* considered at the end of 0th pass because "!sourceWillBeDeleted && !haveNameClash"
//prepare move in second pass
tempFile.setSyncDir(side == LEFT_SIDE ? SyncDirection::LEFT : SyncDirection::RIGHT);
- targetObj.setMoveRef(tempFile .getId());
- tempFile .setMoveRef(targetObj.getId());
+ targetFile.setMoveRef(tempFile .getId());
+ tempFile .setMoveRef(targetFile.getId());
//NO statistics update!
}
-//return "false" on name clash
-bool FolderPairSyncer::createParentFolder(FileSystemObject& fsObj) //throw FileError, ThreadInterruption
+//returns: CmtfStatus::AVAILABLE
+// CmtfStatus::NAME_CLASH
+// CmtfStatus::SOURCE_MISSING
+template <SelectedSide side>
+auto FolderPairSyncer::createMoveTargetFolder(FileSystemObject& fsObj) -> CmtfStatus //throw FileError, ThreadInterruption
{
if (auto parentFolder = dynamic_cast<FolderPair*>(&fsObj.parent()))
{
- if (!createParentFolder(*parentFolder))
- return false;
+ const CmtfStatus cmtfs = createMoveTargetFolder<side>(*parentFolder);
+ if (cmtfs != CmtfStatus::AVAILABLE)
+ return cmtfs;
//detect (and try to resolve) file type conflicts: 1. symlinks 2. files
const Zstring& shortname = parentFolder->getPairItemName();
if (haveNameClash(shortname, parentFolder->parent().refSubLinks()) ||
haveNameClash(shortname, parentFolder->parent().refSubFiles()))
- return false;
+ return CmtfStatus::NAME_CLASH;
+
+ //-------- create parent folder if needed --------------
+ constexpr SelectedSide sideSrc = OtherSide<side>::value;
+ assert(!parentFolder->isEmpty<sideSrc>());
+
+ switch (parentFolder->getSyncOperation())
+ {
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ {
+ const AbstractPath targetPath = parentFolder->getAbstractPath<side>();
+ reportInfo(txtCreatingFolder_, AFS::getDisplayPath(targetPath)); //throw ThreadInterruption
+
+ //shallow-"copying" a folder might not fail if source is missing, so we need to check this first:
+ if (parallel::getItemTypeIfExists(parentFolder->getAbstractPath<sideSrc>(), singleThread_)) //throw FileError
+ {
+ AsyncItemStatReporter statReporter(1, 0, acb_);
+ try //target existing: undefined behavior! (fail/overwrite)
+ {
+ parallel::copyNewFolder(parentFolder->getAbstractPath<sideSrc>(), targetPath, copyFilePermissions_, singleThread_); //throw FileError
+ }
+ catch (FileError&)
+ {
+ bool folderAlreadyExists = false;
+ try { folderAlreadyExists = parallel::getItemType(targetPath, singleThread_) == AFS::ItemType::FOLDER; } /*throw FileError*/ catch (FileError&) {}
+ if (!folderAlreadyExists) //previous exception is more relevant; good enough? https://freefilesync.org/forum/viewtopic.php?t=5266
+ throw;
+ }
+ statReporter.reportDelta(1, 0);
+
+ parentFolder->setSyncedTo<side>(parentFolder->getItemName<sideSrc>(),
+ false /*isSymlinkTrg*/,
+ parentFolder->isFollowedSymlink<sideSrc>());
+ }
+ else //source deleted meanwhile...
+ {
+ //attention when fixing statistics due to missing folder: child items may be scheduled for move, so deletion will have move references flip back to copy + delete!
+ const SyncStatistics statsBefore(parentFolder->base()); //=> don't bother considering move operations, just calculate over the whole tree
+ parentFolder->removeObject<sideSrc>(); //DON'T physically delete child objects while we're still evaluating them, e.g. fsObj, and in caller code!!!
+ const SyncStatistics statsAfter(parentFolder->base());
- //in this context "parentFolder" cannot be scheduled for deletion since it contains a "move target"!
- //note: if parentFolder were deleted, we'd end up destroying "fsObj"!
- assert(parentFolder->getSyncOperation() != SO_DELETE_LEFT &&
- parentFolder->getSyncOperation() != SO_DELETE_RIGHT);
+ acb_.updateDataProcessed(1, 0); //even if the source item does not exist anymore, significant I/O work was done => report
+ acb_.updateDataTotal(getCUD(statsAfter) - getCUD(statsBefore) + 1, statsAfter.getBytesToProcess() - statsBefore.getBytesToProcess()); //noexcept
- synchronizeFolder(*parentFolder); //throw FileError, ThreadInterruption
+ reportInfo(txtSourceItemNotFound_, AFS::getDisplayPath(parentFolder->getAbstractPath<sideSrc>())); //throw ThreadInterruption
+ return CmtfStatus::SOURCE_MISSING;
+ }
+ }
+ break;
+
+ case SO_DO_NOTHING: //!isEmpty<side>(); see FolderPair::getSyncOperation()
+ case SO_UNRESOLVED_CONFLICT: //
+ case SO_OVERWRITE_LEFT: //possible: e.g. manually-resolved dir-traversal conflict
+ case SO_OVERWRITE_RIGHT: //
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ case SO_EQUAL:
+ assert(!parentFolder->isEmpty<side>());
+ break; //we're good
+
+ case SO_DELETE_LEFT: //not possible in the context of planning to move a child item, see FolderPair::getSyncOperation()
+ case SO_DELETE_RIGHT: //
+ case SO_MOVE_LEFT_FROM: //status not possible for folder
+ case SO_MOVE_RIGHT_FROM: //
+ case SO_MOVE_LEFT_TO: //
+ case SO_MOVE_RIGHT_TO: //
+ assert(false);
+ break;
+ }
}
- return true;
+ return CmtfStatus::AVAILABLE;
}
@@ -1243,12 +1314,11 @@ void FolderPairSyncer::resolveMoveConflicts(FilePair& sourceFile, //throw FileEr
const bool sourceWillBeDeleted = [&]
{
if (auto parentFolder = dynamic_cast<const FolderPair*>(&sourceFile.parent()))
- {
switch (parentFolder->getSyncOperation()) //evaluate comparison result and sync direction
{
case SO_DELETE_LEFT:
case SO_DELETE_RIGHT:
- return true; //we need to do something about it
+ return true; //we need to do something about this!
case SO_MOVE_LEFT_FROM:
case SO_MOVE_RIGHT_FROM:
case SO_MOVE_LEFT_TO:
@@ -1264,7 +1334,6 @@ void FolderPairSyncer::resolveMoveConflicts(FilePair& sourceFile, //throw FileEr
case SO_COPY_METADATA_TO_RIGHT:
break;
}
- }
return false;
}();
@@ -1278,15 +1347,16 @@ void FolderPairSyncer::resolveMoveConflicts(FilePair& sourceFile, //throw FileEr
{
//prepare for move now: - revert to 2-step move on name clashes
if (haveNameClash(targetFile) ||
- !createParentFolder(targetFile)) //throw FileError, ThreadInterruption
+ createMoveTargetFolder<side>(targetFile) == CmtfStatus::NAME_CLASH) //throw FileError, ThreadInterruption
return setup2StepMove<side>(sourceFile, targetFile); //throw FileError, ThreadInterruption
//finally start move! this should work now:
synchronizeFile(targetFile); //throw FileError, ThreadInterruption
- //FolderPairSyncer::synchronizeFileInt() is *not* expecting SO_MOVE_LEFT_FROM/SO_MOVE_RIGHT_FROM => start move from targetFile, not sourceFile!
+ //- FolderPairSyncer::synchronizeFileInt() is *not* expecting SO_MOVE_LEFT_FROM/SO_MOVE_RIGHT_FROM => start move from targetFile, not sourceFile!
+ //- function call will be NOOP if CmtfStatus::SOURCE_MISSING
}
//else: sourceFile will not be deleted, and is not standing in the way => delay to second pass
- //note: this case may include new "move sources" from two-step sub-routine!!!
+ //note: this also applies for new "move sources" from two-step sub-routine!!!
}
@@ -1300,7 +1370,7 @@ void FolderPairSyncer::prepareFileMove(FilePair& file) //throw ThreadInterruptio
if (FilePair* targetObj = dynamic_cast<FilePair*>(FileSystemObject::retrieve(file.getMoveRef())))
{
FilePair* sourceObj = &file;
- assert(dynamic_cast<FilePair*>(FileSystemObject::retrieve(targetObj->getMoveRef())) == sourceObj);
+ assert(targetObj->getMoveRef() == sourceObj->getId());
const std::wstring errMsg = tryReportingError([&] //throw ThreadInterruption
{
@@ -1314,20 +1384,19 @@ void FolderPairSyncer::prepareFileMove(FilePair& file) //throw ThreadInterruptio
{
//move operation has failed! We cannot allow to continue and have move source's parent directory deleted, messing up statistics!
// => revert to ordinary "copy + delete"
-
auto getStats = [&]() -> std::pair<int, int64_t>
{
SyncStatistics statSrc(*sourceObj);
SyncStatistics statTrg(*targetObj);
return { getCUD(statSrc) + getCUD(statTrg), statSrc.getBytesToProcess() + statTrg.getBytesToProcess() };
};
-
- const auto statBefore = getStats();
+ const auto [itemsBefore, bytesBefore] = getStats();
sourceObj->setMoveRef(nullptr);
targetObj->setMoveRef(nullptr);
- const auto statAfter = getStats();
+ const auto [itemsAfter, bytesAfter] = getStats();
+
//fix statistics total to match "copy + delete"
- acb_.updateDataTotal(statAfter.first - statBefore.first, statAfter.second - statBefore.second); //noexcept
+ acb_.updateDataTotal(itemsAfter - itemsBefore, bytesAfter - bytesBefore); //noexcept
}
}
else assert(false);
@@ -1491,7 +1560,7 @@ void FolderPairSyncer::synchronizeFile(FilePair& file) //throw FileError, Thread
{
const SyncOperation syncOp = file.getSyncOperation();
- if (Opt<SelectedSide> sideTrg = getTargetDirection(syncOp))
+ if (std::optional<SelectedSide> sideTrg = getTargetDirection(syncOp))
{
if (*sideTrg == LEFT_SIDE)
synchronizeFileInt<LEFT_SIDE>(file, syncOp);
@@ -1549,8 +1618,7 @@ void FolderPairSyncer::synchronizeFileInt(FilePair& file, SyncOperation syncOp)
if (sourceWasDeleted)
{
- //even if the source item does not exist anymore, significant I/O work was done => report
- statReporter.reportDelta(1, 0);
+ statReporter.reportDelta(1, 0); //even if the source item does not exist anymore, significant I/O work was done => report
file.removeObject<sideSrc>(); //source deleted meanwhile...nothing was done (logical point of view!)
reportInfo(txtSourceItemNotFound_, AFS::getDisplayPath(file.getAbstractPath<sideSrc>())); //throw ThreadInterruption
@@ -1578,6 +1646,7 @@ void FolderPairSyncer::synchronizeFileInt(FilePair& file, SyncOperation syncOp)
if (FilePair* moveFrom = dynamic_cast<FilePair*>(FileSystemObject::retrieve(file.getMoveRef())))
{
FilePair* moveTo = &file;
+ assert(moveFrom->getMoveRef() == moveTo->getId());
assert((moveFrom->getSyncOperation() == SO_MOVE_LEFT_FROM && moveTo->getSyncOperation() == SO_MOVE_LEFT_TO && sideTrg == LEFT_SIDE) ||
(moveFrom->getSyncOperation() == SO_MOVE_RIGHT_FROM && moveTo->getSyncOperation() == SO_MOVE_RIGHT_TO && sideTrg == RIGHT_SIDE));
@@ -1715,7 +1784,7 @@ void FolderPairSyncer::synchronizeLink(SymlinkPair& link) //throw FileError, Thr
{
const SyncOperation syncOp = link.getSyncOperation();
- if (Opt<SelectedSide> sideTrg = getTargetDirection(syncOp))
+ if (std::optional<SelectedSide> sideTrg = getTargetDirection(syncOp))
{
if (*sideTrg == LEFT_SIDE)
synchronizeLinkInt<LEFT_SIDE>(link, syncOp);
@@ -1859,7 +1928,7 @@ void FolderPairSyncer::synchronizeFolder(FolderPair& folder) //throw FileError,
{
const SyncOperation syncOp = folder.getSyncOperation();
- if (Opt<SelectedSide> sideTrg = getTargetDirection(syncOp))
+ if (std::optional<SelectedSide> sideTrg = getTargetDirection(syncOp))
{
if (*sideTrg == LEFT_SIDE)
synchronizeFolderInt<LEFT_SIDE>(folder, syncOp);
@@ -1915,17 +1984,16 @@ void FolderPairSyncer::synchronizeFolderInt(FolderPair& folder, SyncOperation sy
}
else //source deleted meanwhile...
{
- const SyncStatistics subStats(folder);
- AsyncItemStatReporter statReporter(1 + getCUD(subStats), subStats.getBytesToProcess(), acb_);
-
- //even if the source item does not exist anymore, significant I/O work was done => report
- statReporter.reportDelta(1, 0);
-
- //remove only *after* evaluating folder!!
+ //attention when fixing statistics due to missing folder: child items may be scheduled for move, so deletion will have move references flip back to copy + delete!
+ const SyncStatistics statsBefore(folder.base()); //=> don't bother considering move operations, just calculate over the whole tree
folder.refSubFiles ().clear(); //
folder.refSubLinks ().clear(); //update FolderPair
folder.refSubFolders().clear(); //
folder.removeObject<sideSrc>(); //
+ const SyncStatistics statsAfter(folder.base());
+
+ acb_.updateDataProcessed(1, 0); //even if the source item does not exist anymore, significant I/O work was done => report
+ acb_.updateDataTotal(getCUD(statsAfter) - getCUD(statsBefore) + 1, statsAfter.getBytesToProcess() - statsBefore.getBytesToProcess()); //noexcept
reportInfo(txtSourceItemNotFound_, AFS::getDisplayPath(folder.getAbstractPath<sideSrc>())); //throw ThreadInterruption
}
@@ -2002,8 +2070,7 @@ AFS::FileCopyResult FolderPairSyncer::copyFileWithCallback(const FileDescriptor&
const AFS::FileCopyResult result = parallel::copyFileTransactional(sourcePathTmp, sourceAttr, //throw FileError, ErrorFileLocked
targetPath,
copyFilePermissions_,
- failSafeFileCopy_,
- [&]
+ failSafeFileCopy_, [&]
{
if (onDeleteTargetFile) //running *outside* singleThread_ lock! => onDeleteTargetFile-callback expects lock being held:
{
@@ -2042,7 +2109,7 @@ AFS::FileCopyResult FolderPairSyncer::copyFileWithCallback(const FileDescriptor&
//###########################################################################################
template <SelectedSide side>
-bool baseFolderDrop(BaseFolderPair& baseFolder, int folderAccessTimeout, ProcessCallback& callback)
+bool baseFolderDrop(BaseFolderPair& baseFolder, std::chrono::seconds folderAccessTimeout, ProcessCallback& callback)
{
const AbstractPath folderPath = baseFolder.getAbstractPath<side>();
@@ -2070,7 +2137,7 @@ bool baseFolderDrop(BaseFolderPair& baseFolder, int folderAccessTimeout, Process
template <SelectedSide side> //create base directories first (if not yet existing) -> no symlink or attribute copying!
-bool createBaseFolder(BaseFolderPair& baseFolder, bool copyFilePermissions, int folderAccessTimeout, ProcessCallback& callback) //return false if fatal error occurred
+bool createBaseFolder(BaseFolderPair& baseFolder, bool copyFilePermissions, std::chrono::seconds folderAccessTimeout, ProcessCallback& callback) //return false if fatal error occurred
{
static const SelectedSide sideSrc = OtherSide<side>::value;
const AbstractPath baseFolderPath = baseFolder.getAbstractPath<side>();
@@ -2094,10 +2161,10 @@ bool createBaseFolder(BaseFolderPair& baseFolder, bool copyFilePermissions, int
{
if (baseFolder.isAvailable<sideSrc>()) //copy file permissions
{
- if (Opt<AbstractPath> parentPath = AFS::getParentFolderPath(baseFolderPath))
+ if (std::optional<AbstractPath> parentPath = AFS::getParentFolderPath(baseFolderPath))
if (AFS::getParentFolderPath(*parentPath)) //not device root
AFS::createFolderIfMissingRecursion(*parentPath); //throw FileError
-
+
AFS::copyNewFolder(baseFolder.getAbstractPath<sideSrc>(), baseFolderPath, copyFilePermissions); //throw FileError
}
else
@@ -2139,7 +2206,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
bool copyFilePermissions,
bool failSafeFileCopy,
bool runWithBackgroundPriority,
- int folderAccessTimeout,
+ std::chrono::seconds folderAccessTimeout,
const std::vector<FolderPairSyncCfg>& syncConfig,
FolderComparison& folderCmp,
const std::map<AbstractPath, size_t>& deviceParallelOps,
@@ -2431,8 +2498,8 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
if (std::get<bool>(*it)) //write access
for (auto it2 = readWriteCheckBaseFolders.begin(); it2 != readWriteCheckBaseFolders.end(); ++it2)
if (!std::get<bool>(*it2) || it < it2) //avoid duplicate comparisons
- if (Opt<PathDependency> pd = getPathDependency(std::get<AbstractPath>(*it), *std::get<const HardFilter*>(*it),
- std::get<AbstractPath>(*it2), *std::get<const HardFilter*>(*it2)))
+ if (std::optional<PathDependency> pd = getPathDependency(std::get<AbstractPath>(*it), *std::get<const HardFilter*>(*it),
+ std::get<AbstractPath>(*it2), *std::get<const HardFilter*>(*it2)))
{
dependentFolders.insert(pd->basePathParent);
dependentFolders.insert(pd->basePathChild);
@@ -2458,7 +2525,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
std::map<AbstractPath, std::wstring> uniqueMsgs; //=> at most one msg per base folder (*and* per versioningFolderPath)
for (const auto& item : verCheckBaseFolderPaths) //may contain duplicate paths, but with *different* hard filter!
- if (Opt<PathDependency> pd = getPathDependency(versioningFolderPath, NullFilter(), item.first, *item.second))
+ if (std::optional<PathDependency> pd = getPathDependency(versioningFolderPath, NullFilter(), item.first, *item.second))
{
std::wstring line = L"\n\n" + _("Versioning folder:") + L" \t" + AFS::getDisplayPath(versioningFolderPath) +
L"\n" + _("Base folder:") + L" \t" + AFS::getDisplayPath(item.first);
@@ -2632,7 +2699,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
//-----------------------------------------------------------------------------------------------------
- applyVersioningLimit(versionLimitFolders, deviceParallelOps, callback); //throw X
+ applyVersioningLimit(versionLimitFolders, folderAccessTimeout, deviceParallelOps, callback); //throw X
//------------------- show warnings after end of synchronization --------------------------------------
diff --git a/FreeFileSync/Source/base/synchronization.h b/FreeFileSync/Source/base/synchronization.h
index dcfc0114..3ac1291e 100755
--- a/FreeFileSync/Source/base/synchronization.h
+++ b/FreeFileSync/Source/base/synchronization.h
@@ -92,7 +92,7 @@ void synchronize(const std::chrono::system_clock::time_point& syncStartTime,
bool copyFilePermissions,
bool failSafeFileCopy,
bool runWithBackgroundPriority,
- int folderAccessTimeout,
+ std::chrono::seconds folderAccessTimeout,
const std::vector<FolderPairSyncCfg>& syncConfig, //CONTRACT: syncConfig and folderCmp correspond row-wise!
FolderComparison& folderCmp, //
const std::map<AbstractPath, size_t>& deviceParallelOps,
diff --git a/FreeFileSync/Source/base/versioning.cpp b/FreeFileSync/Source/base/versioning.cpp
index b8344b44..c5bc2aa6 100755
--- a/FreeFileSync/Source/base/versioning.cpp
+++ b/FreeFileSync/Source/base/versioning.cpp
@@ -1,6 +1,7 @@
#include "versioning.h"
#include "parallel_scan.h"
#include "status_handler_impl.h"
+#include "dir_exist_async.h"
using namespace zen;
using namespace fff;
@@ -80,7 +81,8 @@ AbstractPath FileVersioner::generateVersionedPath(const Zstring& relativePath) c
break;
case VersioningStyle::TIMESTAMP_FILE: //assemble time-stamped version name
versionedRelPath = relativePath + Zstr(' ') + timeStamp_ + getDotExtension(relativePath);
- assert(impl::parseVersionedFileName(versionedRelPath) == std::pair(syncStartTime_, relativePath));
+ assert(impl::parseVersionedFileName(afterLast(versionedRelPath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)) ==
+ std::pair(syncStartTime_, afterLast(relativePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)));
(void)syncStartTime_; //silence clang's "unused variable" arning
break;
}
@@ -109,7 +111,7 @@ void moveExistingItemToVersioning(const AbstractPath& sourcePath, const Abstract
auto fixTargetPathIssues = [&](const FileError& prevEx) //throw FileError
{
- Opt<AFS::PathStatus> psTmp;
+ std::optional<AFS::PathStatus> psTmp;
try { psTmp = AFS::getPathStatus(targetPath); /*throw FileError*/ }
catch (const FileError& e) { throw FileError(prevEx.toString(), e.toString()); }
const AFS::PathStatus& ps = *psTmp;
@@ -189,7 +191,7 @@ void moveExistingItemToVersioning(const AbstractPath& sourcePath, const Abstract
void FileVersioner::revisionFile(const FileDescriptor& fileDescr, const Zstring& relativePath, const IOCallback& notifyUnbufferedIO) const //throw FileError
{
- if (Opt<AFS::ItemType> type = AFS::getItemTypeIfExists(fileDescr.path)) //throw FileError
+ if (std::optional<AFS::ItemType> type = AFS::getItemTypeIfExists(fileDescr.path)) //throw FileError
{
if (*type == AFS::ItemType::SYMLINK)
revisionSymlinkImpl(fileDescr.path, relativePath, nullptr /*onBeforeMove*/); //throw FileError
@@ -251,7 +253,7 @@ void FileVersioner::revisionFolder(const AbstractPath& folderPath, const Zstring
const IOCallback& notifyUnbufferedIO) const
{
//no error situation if directory is not existing! manual deletion relies on it!
- if (Opt<AFS::ItemType> type = AFS::getItemTypeIfExists(folderPath)) //throw FileError
+ if (std::optional<AFS::ItemType> type = AFS::getItemTypeIfExists(folderPath)) //throw FileError
{
if (*type == AFS::ItemType::SYMLINK) //on Linux there is just one type of symlink, and since we do revision file symlinks, we should revision dir symlinks as well!
revisionSymlinkImpl(folderPath, relativePath, onBeforeFileMove); //throw FileError
@@ -311,9 +313,9 @@ namespace
{
struct VersionInfo
{
- time_t versionTime;
+ time_t versionTime = 0;
AbstractPath filePath;
- bool isSymlink;
+ bool isSymlink = false;
};
using VersionInfoMap = std::map<Zstring, std::vector<VersionInfo>, LessFilePath>; //relPathOrig => <version infos>
@@ -411,16 +413,46 @@ bool fff::operator<(const VersioningLimitFolder& lhs, const VersioningLimitFolde
void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolders,
+ std::chrono::seconds folderAccessTimeout,
const std::map<AbstractPath, size_t>& deviceParallelOps,
ProcessCallback& callback /*throw X*/)
{
- warn_static("what if folder does not yet exist?")
+ //--------- determine existing folder paths for traversal ---------
+ std::set<DirectoryKey> foldersToRead;
+ {
+ std::set<AbstractPath> folderPaths;
+ for (const VersioningLimitFolder& vlf : limitFolders)
+ if (vlf.versionMaxAgeDays > 0 || vlf.versionCountMax > 0) //only analyze versioning folders when needed!
+ folderPaths.emplace(vlf.versioningFolderPath);
+
+ //we don't want to show an error if version path does not yet exist!
+ tryReportingError([&]
+ {
+ const FolderStatus status = getFolderStatusNonBlocking(folderPaths, deviceParallelOps, //re-check *all* directories on each try!
+ folderAccessTimeout, false /*allowUserInteraction*/, callback); //throw X
+
+ foldersToRead.clear();
+ for (const AbstractPath& folderPath : status.existing)
+ foldersToRead.emplace(DirectoryKey({ folderPath, std::make_shared<NullFilter>(), SymLinkHandling::DIRECT }));
+
+ if (!status.failedChecks.empty())
+ {
+ std::wstring msg = _("Cannot find the following folders:") + L"\n";
+
+ for (const auto& fc : status.failedChecks)
+ msg += L"\n" + AFS::getDisplayPath(fc.first);
+
+ msg += L"\n___________________________________________";
+ for (const auto& fc : status.failedChecks)
+ msg += L"\n\n" + replaceCpy(fc.second.toString(), L"\n\n", L"\n");
+
+ throw FileError(msg);
+ }
+ }, callback); //throw X
+ }
//--------- traverse all versioning folders ---------
- std::set<DirectoryKey> foldersToRead;
- for (const VersioningLimitFolder& vlf : limitFolders)
- if (vlf.versionMaxAgeDays > 0 || vlf.versionCountMax > 0) //only analyze versioning folders when needed!
- foldersToRead.emplace(DirectoryKey({ vlf.versioningFolderPath, std::make_shared<NullFilter>(), SymLinkHandling::DIRECT }));
+ std::map<DirectoryKey, DirectoryValue> folderBuf;
auto onError = [&](const std::wstring& msg, size_t retryNumber)
{
@@ -443,8 +475,6 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
callback.reportStatus(textScanning + statusLine); //throw X
};
- std::map<DirectoryKey, DirectoryValue> folderBuf;
-
parallelDeviceTraversal(foldersToRead, folderBuf,
deviceParallelOps,
onError, onStatusUpdate, //throw X
@@ -491,15 +521,17 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
}();
for (const VersioningLimitFolder& vlf : limitFolders)
- if (vlf.versionMaxAgeDays > 0 || vlf.versionCountMax > 0) //NOT redundant regarding the same check above
- for (auto& item : versionDetails.find(vlf.versioningFolderPath)->second) //exists after construction above!
+ {
+ auto it = versionDetails.find(vlf.versioningFolderPath);
+ if (it != versionDetails.end())
+ for (auto& item : it->second)
{
std::vector<VersionInfo>& versions = item.second;
size_t versionsToKeep = versions.size();
if (vlf.versionMaxAgeDays > 0)
{
- const time_t cutOffTime = lastMidnightTime - vlf.versionMaxAgeDays * 24 * 3600;
+ const time_t cutOffTime = lastMidnightTime - static_cast<time_t>(vlf.versionMaxAgeDays) * 24 * 3600;
versionsToKeep = std::count_if(versions.begin(), versions.end(), [cutOffTime](const VersionInfo& vi) { return vi.versionTime >= cutOffTime; });
@@ -521,6 +553,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
});
}
}
+ }
//--------- remove excess file versions ---------
Protected<std::map<AbstractPath, size_t>&> folderItemCountShared(folderItemCount);
@@ -528,7 +561,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
const std::wstring textDeletingFolder = _("Deleting folder %x");
ParallelWorkItem deleteEmptyFolderTask;
- deleteEmptyFolderTask = [&textDeletingFolder, &folderItemCountShared, &deleteEmptyFolderTask](ParallelContext& ctx) /*throw ThreadInterruption*/
+ deleteEmptyFolderTask = [&textDeletingFolder, &folderItemCountShared, &deleteEmptyFolderTask](ParallelContext& ctx) //throw ThreadInterruption
{
const std::wstring errMsg = tryReportingError([&] //throw ThreadInterruption
{
@@ -537,7 +570,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
}, ctx.acb);
if (errMsg.empty())
- if (Opt<AbstractPath> parentPath = AFS::getParentFolderPath(ctx.itemPath))
+ if (std::optional<AbstractPath> parentPath = AFS::getParentFolderPath(ctx.itemPath))
{
bool scheduleDelete = false;
folderItemCountShared.access([&](auto& folderItemCount2) { scheduleDelete = --folderItemCount2[*parentPath] == 0; });
@@ -553,7 +586,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
parallelWorkload.emplace_back(item.first, deleteEmptyFolderTask);
for (const auto& item : itemsToDelete)
- parallelWorkload.emplace_back(item.first, [isSymlink = item.second, &textRemoving, &folderItemCountShared, &deleteEmptyFolderTask](ParallelContext& ctx) /*throw ThreadInterruption*/
+ parallelWorkload.emplace_back(item.first, [isSymlink = item.second, &textRemoving, &folderItemCountShared, &deleteEmptyFolderTask](ParallelContext& ctx) //throw ThreadInterruption
{
const std::wstring errMsg = tryReportingError([&] //throw ThreadInterruption
{
@@ -565,7 +598,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
}, ctx.acb);
if (errMsg.empty())
- if (Opt<AbstractPath> parentPath = AFS::getParentFolderPath(ctx.itemPath))
+ if (std::optional<AbstractPath> parentPath = AFS::getParentFolderPath(ctx.itemPath))
{
bool scheduleDelete = false;
folderItemCountShared.access([&](auto& folderItemCount2) { scheduleDelete = --folderItemCount2[*parentPath] == 0; });
@@ -573,6 +606,8 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolde
ctx.scheduleExtraTask(AfsPath(AFS::getRootRelativePath(*parentPath)), deleteEmptyFolderTask); //throw ThreadInterruption
assert(AFS::getRootPath(*parentPath) == AFS::getRootPath(ctx.itemPath));
}
+
+ warn_static("get rid of scheduleExtraTask and recursively delete parent folders!? need scheduleExtraTask for something else?")
});
massParallelExecute(parallelWorkload, deviceParallelOps, "Versioning Limit", callback /*throw X*/);
diff --git a/FreeFileSync/Source/base/versioning.h b/FreeFileSync/Source/base/versioning.h
index 835ba67e..a2743e94 100755
--- a/FreeFileSync/Source/base/versioning.h
+++ b/FreeFileSync/Source/base/versioning.h
@@ -103,6 +103,7 @@ bool operator<(const VersioningLimitFolder& lhs, const VersioningLimitFolder& rh
void applyVersioningLimit(const std::set<VersioningLimitFolder>& limitFolders,
+ std::chrono::seconds folderAccessTimeout,
const std::map<AbstractPath, size_t>& deviceParallelOps,
ProcessCallback& callback /*throw X*/);
diff --git a/FreeFileSync/Source/fs/abstract.cpp b/FreeFileSync/Source/fs/abstract.cpp
index d53019be..e43de243 100755
--- a/FreeFileSync/Source/fs/abstract.cpp
+++ b/FreeFileSync/Source/fs/abstract.cpp
@@ -44,19 +44,19 @@ int AFS::compareAbstractPath(const AbstractPath& lhs, const AbstractPath& rhs)
}
-Opt<AbstractPath> AFS::getParentFolderPath(const AbstractPath& ap)
+std::optional<AbstractPath> AFS::getParentFolderPath(const AbstractPath& ap)
{
- if (const Opt<AfsPath> parentAfsPath = getParentAfsPath(ap.afsPath))
+ if (const std::optional<AfsPath> parentAfsPath = getParentAfsPath(ap.afsPath))
return AbstractPath(ap.afs, *parentAfsPath);
- return NoValue();
+ return {};
}
-Opt<AfsPath> AFS::getParentAfsPath(const AfsPath& afsPath)
+std::optional<AfsPath> AFS::getParentAfsPath(const AfsPath& afsPath)
{
if (afsPath.value.empty())
- return NoValue();
+ return {};
return AfsPath(beforeLast(afsPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE));
}
@@ -127,7 +127,7 @@ AFS::FileCopyResult AFS::copyFileAsStream(const AfsPath& afsPathSource, const St
StreamAttributes attrSourceNew = {};
//try to get the most current attributes if possible (input file might have changed after comparison!)
- if (Opt<StreamAttributes> attr = streamIn->getAttributesBuffered()) //throw FileError
+ if (std::optional<StreamAttributes> attr = streamIn->getAttributesBuffered()) //throw FileError
attrSourceNew = *attr; //Native/MTP
else //use more stale ones:
attrSourceNew = attrSource; //SFTP/FTP
@@ -148,7 +148,7 @@ AFS::FileCopyResult AFS::copyFileAsStream(const AfsPath& afsPathSource, const St
L"%x", numberTo<std::wstring>(2 * attrSourceNew.fileSize)),
L"%y", numberTo<std::wstring>(totalUnbufferedIO)) + L" [notifyUnbufferedIO]");
- Opt<FileError> errorModTime;
+ std::optional<FileError> errorModTime;
try
{
/*
@@ -210,7 +210,7 @@ AFS::FileCopyResult AFS::copyFileTransactional(const AbstractPath& apSource, con
if (transactionalCopy)
{
- Opt<AbstractPath> parentPath = AFS::getParentFolderPath(apTarget);
+ std::optional<AbstractPath> parentPath = AFS::getParentFolderPath(apTarget);
if (!parentPath)
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(AFS::getDisplayPath(apTarget))), L"Path is device root.");
const Zstring fileName = AFS::getItemName(apTarget);
@@ -305,7 +305,7 @@ void AFS::createFolderIfMissingRecursion(const AbstractPath& ap) //throw FileErr
//essentially a(n abstract) duplicate of zen::getPathStatus()
AFS::PathStatusImpl AFS::getPathStatusViaFolderTraversal(const AfsPath& afsPath) const //throw FileError
{
- const Opt<AfsPath> parentAfsPath = getParentAfsPath(afsPath);
+ const std::optional<AfsPath> parentAfsPath = getParentAfsPath(afsPath);
try
{
return { getItemType(afsPath), afsPath, {} }; //throw FileError
@@ -339,12 +339,12 @@ AFS::PathStatusImpl AFS::getPathStatusViaFolderTraversal(const AfsPath& afsPath)
}
-Opt<AFS::ItemType> AFS::getItemTypeIfExists(const AbstractPath& ap) //throw FileError
+std::optional<AFS::ItemType> AFS::getItemTypeIfExists(const AbstractPath& ap) //throw FileError
{
const PathStatus ps = getPathStatus(ap); //throw FileError
if (ps.relPath.empty())
return ps.existingType;
- return NoValue();
+ return {};
}
@@ -355,62 +355,54 @@ AFS::PathStatus AFS::getPathStatus(const AbstractPath& ap) //throw FileError
}
-namespace
-{
-void removeFolderIfExistsRecursionImpl(const AbstractPath& folderPath, //throw FileError
- const std::function<void (const std::wstring& displayPath)>& onBeforeFileDeletion, //optional
- const std::function<void (const std::wstring& displayPath)>& onBeforeFolderDeletion) //one call for each *existing* object!
+void AFS::removeFolderIfExistsRecursion(const AbstractPath& ap, //throw FileError
+ const std::function<void (const std::wstring& displayPath)>& onBeforeFileDeletion, //optional
+ const std::function<void (const std::wstring& displayPath)>& onBeforeFolderDeletion) //one call for each object!
{
-
- //deferred recursion => save stack space and allow deletion of extremely deep hierarchies!
- std::vector<Zstring> fileNames;
- std::vector<Zstring> folderNames;
- std::vector<Zstring> symlinkNames;
-
- AFS::traverseFolderFlat(folderPath, //throw FileError
- [&](const AFS::FileInfo& fi) { fileNames .push_back(fi.itemName); },
- [&](const AFS::FolderInfo& fi) { folderNames .push_back(fi.itemName); },
- [&](const AFS::SymlinkInfo& si) { symlinkNames.push_back(si.itemName); });
-
-
- for (const Zstring& fileName : fileNames)
+ std::function<void(const AbstractPath& folderPath)> removeFolderRecursionImpl;
+ removeFolderRecursionImpl = [&onBeforeFileDeletion, &onBeforeFolderDeletion, &removeFolderRecursionImpl](const AbstractPath& folderPath) //throw FileError
{
- const AbstractPath filePath = AFS::appendRelPath(folderPath, fileName);
- if (onBeforeFileDeletion)
- onBeforeFileDeletion(AFS::getDisplayPath(filePath));
+ //deferred recursion => save stack space and allow deletion of extremely deep hierarchies!
+ std::vector<Zstring> fileNames;
+ std::vector<Zstring> folderNames;
+ std::vector<Zstring> symlinkNames;
- AFS::removeFilePlain(filePath); //throw FileError
- }
+ AFS::traverseFolderFlat(folderPath, //throw FileError
+ [&](const AFS::FileInfo& fi) { fileNames .push_back(fi.itemName); },
+ [&](const AFS::FolderInfo& fi) { folderNames .push_back(fi.itemName); },
+ [&](const AFS::SymlinkInfo& si) { symlinkNames.push_back(si.itemName); });
- for (const Zstring& symlinkName : symlinkNames)
- {
- const AbstractPath linkPath = AFS::appendRelPath(folderPath, symlinkName);
- if (onBeforeFileDeletion)
- onBeforeFileDeletion(AFS::getDisplayPath(linkPath));
+ for (const Zstring& fileName : fileNames)
+ {
+ const AbstractPath filePath = AFS::appendRelPath(folderPath, fileName);
+ if (onBeforeFileDeletion)
+ onBeforeFileDeletion(AFS::getDisplayPath(filePath));
- AFS::removeSymlinkPlain(linkPath); //throw FileError
- }
+ AFS::removeFilePlain(filePath); //throw FileError
+ }
- for (const Zstring& folderName : folderNames)
- removeFolderIfExistsRecursionImpl(AFS::appendRelPath(folderPath, folderName), //throw FileError
- onBeforeFileDeletion, onBeforeFolderDeletion);
+ for (const Zstring& symlinkName : symlinkNames)
+ {
+ const AbstractPath linkPath = AFS::appendRelPath(folderPath, symlinkName);
+ if (onBeforeFileDeletion)
+ onBeforeFileDeletion(AFS::getDisplayPath(linkPath)); //throw X
- if (onBeforeFolderDeletion)
- onBeforeFolderDeletion(AFS::getDisplayPath(folderPath));
+ AFS::removeSymlinkPlain(linkPath); //throw FileError
+ }
- AFS::removeFolderPlain(folderPath); //throw FileError
-}
-}
+ for (const Zstring& folderName : folderNames)
+ removeFolderRecursionImpl(AFS::appendRelPath(folderPath, folderName)); //throw FileError
+ if (onBeforeFolderDeletion)
+ onBeforeFolderDeletion(AFS::getDisplayPath(folderPath)); //throw X
-void AFS::removeFolderIfExistsRecursion(const AbstractPath& ap, //throw FileError
- const std::function<void (const std::wstring& displayPath)>& onBeforeFileDeletion, //optional
- const std::function<void (const std::wstring& displayPath)>& onBeforeFolderDeletion) //one call for each object!
-{
+ AFS::removeFolderPlain(folderPath); //throw FileError
+ };
+ //--------------------------------------------------------------------------------------------------------------
warn_static("what about parallelOps?")
//no error situation if directory is not existing! manual deletion relies on it!
- if (Opt<ItemType> type = AFS::getItemTypeIfExists(ap)) //throw FileError
+ if (std::optional<ItemType> type = AFS::getItemTypeIfExists(ap)) //throw FileError
{
if (*type == AFS::ItemType::SYMLINK)
{
@@ -420,7 +412,7 @@ void AFS::removeFolderIfExistsRecursion(const AbstractPath& ap, //throw FileErro
AFS::removeSymlinkPlain(ap); //throw FileError
}
else
- removeFolderIfExistsRecursionImpl(ap, onBeforeFileDeletion, onBeforeFolderDeletion); //throw FileError
+ removeFolderRecursionImpl(ap); //throw FileError
}
else //even if the folder did not exist anymore, significant I/O work was done => report
if (onBeforeFolderDeletion) onBeforeFolderDeletion(AFS::getDisplayPath(ap));
diff --git a/FreeFileSync/Source/fs/abstract.h b/FreeFileSync/Source/fs/abstract.h
index d5b08c73..887f6b8f 100755
--- a/FreeFileSync/Source/fs/abstract.h
+++ b/FreeFileSync/Source/fs/abstract.h
@@ -10,7 +10,6 @@
#include <functional>
#include <zen/file_error.h>
#include <zen/zstring.h>
-#include <zen/optional.h>
#include <zen/serialize.h> //InputStream/OutputStream support buffered stream concept
#include <wx+/image_holder.h> //NOT a wxWidgets dependency!
@@ -52,19 +51,19 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
static bool equalAbstractPath(const AbstractPath& lhs, const AbstractPath& rhs) { return compareAbstractPath(lhs, rhs) == 0; }
- static Zstring getInitPathPhrase(const AbstractPath& ap) { return ap.afs->getInitPathPhrase(ap.afsPath); }
+ static bool isNullPath(const AbstractPath& ap) { return ap.afs->isNullFileSystem() /*&& ap.afsPath.value.empty()*/; }
static std::wstring getDisplayPath(const AbstractPath& ap) { return ap.afs->getDisplayPath(ap.afsPath); }
- static bool isNullPath(const AbstractPath& ap) { return ap.afs->isNullFileSystem() /*&& ap.afsPath.value.empty()*/; }
+ static Zstring getInitPathPhrase(const AbstractPath& ap) { return ap.afs->getInitPathPhrase(ap.afsPath); }
+
+ static std::optional<Zstring> getNativeItemPath(const AbstractPath& ap) { return ap.afs->getNativeItemPath(ap.afsPath); }
static AbstractPath appendRelPath(const AbstractPath& ap, const Zstring& relPath);
static Zstring getItemName(const AbstractPath& ap) { assert(getParentFolderPath(ap)); return getItemName(ap.afsPath); }
- static zen::Opt<Zstring> getNativeItemPath(const AbstractPath& ap) { return ap.afs->getNativeItemPath(ap.afsPath); }
-
- static zen::Opt<AbstractPath> getParentFolderPath(const AbstractPath& ap);
+ static std::optional<AbstractPath> getParentFolderPath(const AbstractPath& ap);
static AbstractPath getRootPath (const AbstractPath& ap) { return AbstractPath(ap.afs, AfsPath()); }
static Zstring getRootRelativePath(const AbstractPath& ap) { return ap.afsPath.value; }
@@ -85,7 +84,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
//(hopefully) fast: does not distinguish between error/not existing
static ItemType getItemType(const AbstractPath& ap) { return ap.afs->getItemType(ap.afsPath); } //throw FileError
//execute potentially SLOW folder traversal but distinguish error/not existing
- static zen::Opt<ItemType> getItemTypeIfExists(const AbstractPath& ap); //throw FileError
+ static std::optional<ItemType> getItemTypeIfExists(const AbstractPath& ap); //throw FileError
static PathStatus getPathStatus(const AbstractPath& ap); //throw FileError
//----------------------------------------------------------------------------------------------------------------
@@ -137,7 +136,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
virtual size_t getBlockSize() const = 0; //non-zero block size is AFS contract! it's implementer's job to always give a reasonable buffer size!
//only returns attributes if they are already buffered within stream handle and determination would be otherwise expensive (e.g. FTP/SFTP):
- virtual zen::Opt<StreamAttributes> getAttributesBuffered() = 0; //throw FileError
+ virtual std::optional<StreamAttributes> getAttributesBuffered() = 0; //throw FileError
};
struct OutputStreamImpl
@@ -159,7 +158,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
std::unique_ptr<OutputStreamImpl> outStream_; //bound!
const AbstractPath filePath_;
bool finalizeSucceeded_ = false;
- zen::Opt<uint64_t> bytesExpected_;
+ std::optional<uint64_t> bytesExpected_;
uint64_t bytesWrittenTotal_ = 0;
};
@@ -247,7 +246,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC
FileId sourceFileId;
FileId targetFileId;
- zen::Opt<zen::FileError> errorModTime; //failure to set modification time
+ std::optional<zen::FileError> errorModTime; //failure to set modification time
};
//symlink handling: follow
@@ -302,7 +301,7 @@ protected: //grant derived classes access to AbstractPath:
static AfsPath getAfsPath(const AbstractPath& ap) { return ap.afsPath; }
static Zstring getItemName(const AfsPath& afsPath) { using namespace zen; return afterLast(afsPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL); }
- static zen::Opt<AfsPath> getParentAfsPath(const AfsPath& afsPath);
+ static std::optional<AfsPath> getParentAfsPath(const AfsPath& afsPath);
struct PathStatusImpl
{
@@ -324,7 +323,7 @@ protected: //grant derived classes access to AbstractPath:
using TraverserWorkloadImpl = std::vector<std::pair<AfsPath, std::shared_ptr<TraverserCallback> /*throw X*/>>;
private:
- virtual zen::Opt<Zstring> getNativeItemPath(const AfsPath& afsPath) const { return zen::NoValue(); };
+ virtual std::optional<Zstring> getNativeItemPath(const AfsPath& afsPath) const { return {}; };
virtual Zstring getInitPathPhrase(const AfsPath& afsPath) const = 0;
diff --git a/FreeFileSync/Source/fs/concrete_impl.h b/FreeFileSync/Source/fs/concrete_impl.h
index 03e381bc..e08d9574 100755
--- a/FreeFileSync/Source/fs/concrete_impl.h
+++ b/FreeFileSync/Source/fs/concrete_impl.h
@@ -65,7 +65,7 @@ public:
TaskScheduler(size_t threadCount, const std::string& groupName) :
threadGroup_(zen::ThreadGroup<std::function<void()>>(threadCount, groupName)) {}
- ~TaskScheduler() { threadGroup_ = zen::NoValue(); } //TaskScheduler must out-live threadGroup! (captured "this")
+ ~TaskScheduler() { threadGroup_ = {}; } //TaskScheduler must out-live threadGroup! (captured "this")
//context of controlling thread, non-blocking:
template <class Function>
@@ -121,7 +121,7 @@ private:
conditionNewResult_.notify_all();
}
- zen::Opt<zen::ThreadGroup<std::function<void()>>> threadGroup_;
+ std::optional<zen::ThreadGroup<std::function<void()>>> threadGroup_;
std::mutex lockResult_;
size_t resultsPending_ = 0;
diff --git a/FreeFileSync/Source/fs/native.cpp b/FreeFileSync/Source/fs/native.cpp
index ad8f9be1..fc260d7f 100755
--- a/FreeFileSync/Source/fs/native.cpp
+++ b/FreeFileSync/Source/fs/native.cpp
@@ -308,14 +308,14 @@ struct InputStreamNative : public AbstractFileSystem::InputStream
size_t read(void* buffer, size_t bytesToRead) override { return fi_.read(buffer, bytesToRead); } //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream!
size_t getBlockSize() const override { return fi_.getBlockSize(); } //non-zero block size is AFS contract!
- Opt<AFS::StreamAttributes> getAttributesBuffered() override; //throw FileError
+ std::optional<AFS::StreamAttributes> getAttributesBuffered() override; //throw FileError
private:
FileInput fi_;
};
-Opt<AFS::StreamAttributes> InputStreamNative::getAttributesBuffered() //throw FileError
+std::optional<AFS::StreamAttributes> InputStreamNative::getAttributesBuffered() //throw FileError
{
const FileAttribs fileAttr = getFileAttributes(fi_.getHandle(), fi_.getFilePath()); //throw FileError
@@ -364,7 +364,7 @@ public:
private:
Zstring getNativePath(const AfsPath& afsPath) const { return appendPaths(rootPath_, afsPath.value, FILE_NAME_SEPARATOR); }
- Opt<Zstring> getNativeItemPath(const AfsPath& afsPath) const override { return getNativePath(afsPath); }
+ std::optional<Zstring> getNativeItemPath(const AfsPath& afsPath) const override { return getNativePath(afsPath); }
Zstring getInitPathPhrase(const AfsPath& afsPath) const override { return getNativePath(afsPath); }
@@ -441,7 +441,7 @@ private:
const Zstring nativePath = getNativePath(afsPath);
const Zstring resolvedPath = zen::getSymlinkResolvedPath(nativePath); //throw FileError
- const Opt<zen::PathComponents> comp = parsePathComponents(resolvedPath);
+ const std::optional<zen::PathComponents> comp = parsePathComponents(resolvedPath);
if (!comp)
throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(nativePath)),
replaceCpy<std::wstring>(L"Invalid path %x.", L"%x", fmtPath(resolvedPath)));
@@ -627,7 +627,7 @@ bool RecycleSessionNative::recycleItem(const AbstractPath& itemPath, const Zstri
{
assert(!startsWith(logicalRelPath, FILE_NAME_SEPARATOR));
- Opt<Zstring> itemPathNative = AFS::getNativeItemPath(itemPath);
+ std::optional<Zstring> itemPathNative = AFS::getNativeItemPath(itemPath);
if (!itemPathNative)
throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
@@ -668,7 +668,7 @@ AbstractPath fff::createItemPathNative(const Zstring& itemPathPhrase) //noexcept
AbstractPath fff::createItemPathNativeNoFormatting(const Zstring& nativePath) //noexcept
{
- if (const Opt<PathComponents> comp = parsePathComponents(nativePath))
+ if (const std::optional<PathComponents> comp = parsePathComponents(nativePath))
return AbstractPath(std::make_shared<NativeFileSystem>(comp->rootPath), AfsPath(comp->relPath));
else //path syntax broken
return AbstractPath(std::make_shared<NativeFileSystem>(nativePath), AfsPath());
diff --git a/FreeFileSync/Source/fs/native.h b/FreeFileSync/Source/fs/native.h
index d7d8c1bb..657109b9 100755
--- a/FreeFileSync/Source/fs/native.h
+++ b/FreeFileSync/Source/fs/native.h
@@ -15,6 +15,9 @@ bool acceptsItemPathPhraseNative (const Zstring& itemPathPhrase); //noexcept
AbstractPath createItemPathNative(const Zstring& itemPathPhrase); //noexcept
AbstractPath createItemPathNativeNoFormatting(const Zstring& nativePath); //noexcept
+
+inline
+AbstractPath getNullPath() { return createItemPathNativeNoFormatting(Zstring()); }
}
#endif //FS_NATIVE_183247018532434563465
diff --git a/FreeFileSync/Source/ui/batch_config.cpp b/FreeFileSync/Source/ui/batch_config.cpp
index 83d297d5..e0b248de 100755
--- a/FreeFileSync/Source/ui/batch_config.cpp
+++ b/FreeFileSync/Source/ui/batch_config.cpp
@@ -15,7 +15,6 @@
#include "gui_generated.h"
#include "folder_selector.h"
#include "../base/help_provider.h"
-#include "../base/generate_logfile.h"
using namespace zen;
@@ -50,9 +49,6 @@ private:
void OnHelpScheduleBatch(wxHyperlinkEvent& event) override { displayHelpEntry(L"schedule-a-batch-job", this); }
- void OnToggleGenerateLogfile(wxCommandEvent& event) override { updateGui(); }
- void OnToggleLogfilesLimit (wxCommandEvent& event) override { updateGui(); }
-
void onLocalKeyEvent(wxKeyEvent& event);
void updateGui(); //re-evaluate gui after config changes
@@ -63,8 +59,6 @@ private:
//output-only parameters
BatchDialogConfig& dlgCfgOut_;
- std::unique_ptr<FolderSelector> logfileDir_; //always bound, solve circular compile-time dependency
-
EnumDescrList<PostSyncAction> enumPostSyncAction_;
};
@@ -79,17 +73,8 @@ BatchDialog::BatchDialog(wxWindow* parent, BatchDialogConfig& dlgCfg) :
m_staticTextHeader->SetLabel(replaceCpy(m_staticTextHeader->GetLabel(), L"%x", L"FreeFileSync.exe <" + _("job name") + L">.ffs_batch"));
m_staticTextHeader->Wrap(fastFromDIP(520));
- m_spinCtrlLogfileLimit->SetMinSize(wxSize(fastFromDIP(70), -1)); //Hack: set size (why does wxWindow::Size() not work?)
-
m_bitmapBatchJob->SetBitmap(getResourceImage(L"file_batch"));
- logfileDir_ = std::make_unique<FolderSelector>(*m_panelLogfile, *m_buttonSelectLogFolder, *m_bpButtonSelectAltLogFolder, *m_logFolderPath, nullptr /*staticText*/, nullptr /*wxWindow*/,
- nullptr /*droppedPathsFilter*/,
- [](const Zstring& folderPathPhrase) { return 1; } /*getDeviceParallelOps*/,
- nullptr /*setDeviceParallelOps*/);
-
- //logfileDir_->setBackgroundText(utfTo<std::wstring>(getDefaultLogFolderPath()));
-
enumPostSyncAction_.
add(PostSyncAction::NONE, L"").
add(PostSyncAction::SLEEP, _("System: Sleep")).
@@ -97,15 +82,6 @@ BatchDialog::BatchDialog(wxWindow* parent, BatchDialogConfig& dlgCfg) :
setConfig(dlgCfg);
- warn_static("consider for removal after FFS 10.3 release")
-#if 1
- m_panelLogfile->Hide();
- m_bitmapLogFile->Hide();
- m_checkBoxSaveLog->Hide();
- m_checkBoxLogfilesLimit->Hide();
- m_spinCtrlLogfileLimit->Hide();
-#endif
-
//enable dialog-specific key events
Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(BatchDialog::onLocalKeyEvent), nullptr, this);
@@ -127,11 +103,6 @@ void BatchDialog::updateGui() //re-evaluate gui after config changes
m_radioBtnErrorDialogCancel->Enable(!dlgCfg.ignoreErrors);
m_bitmapMinimizeToTray->SetBitmap(dlgCfg.batchExCfg.runMinimized ? getResourceImage(L"minimize_to_tray") : greyScale(getResourceImage(L"minimize_to_tray")));
-
- m_panelLogfile ->Enable (m_checkBoxSaveLog->GetValue()); //enabled status is *not* directly dependent from resolved config! (but transitively)
- m_bitmapLogFile->SetBitmap(m_checkBoxSaveLog->GetValue() ? getResourceImage(L"log_file") : greyScale(getResourceImage(L"log_file")));
- m_checkBoxLogfilesLimit->Enable(m_checkBoxSaveLog->GetValue());
- m_spinCtrlLogfileLimit ->Enable(m_checkBoxSaveLog->GetValue() && m_checkBoxLogfilesLimit->GetValue());
}
@@ -158,12 +129,6 @@ void BatchDialog::setConfig(const BatchDialogConfig& dlgCfg)
m_checkBoxAutoClose ->SetValue(dlgCfg.batchExCfg.autoCloseSummary);
setEnumVal(enumPostSyncAction_, *m_choicePostSyncAction, dlgCfg.batchExCfg.postSyncAction);
- logfileDir_->setPath(dlgCfg.batchExCfg.altLogFolderPathPhrase);
- m_checkBoxSaveLog ->SetValue(dlgCfg.batchExCfg.altLogfileCountMax != 0);
- m_checkBoxLogfilesLimit->SetValue(dlgCfg.batchExCfg.altLogfileCountMax > 0);
- m_spinCtrlLogfileLimit ->SetValue(dlgCfg.batchExCfg.altLogfileCountMax > 0 ? dlgCfg.batchExCfg.altLogfileCountMax : 100);
- //attention: emits a "change value" event!! => updateGui() called implicitly!
-
updateGui(); //re-evaluate gui after config changes
}
@@ -179,14 +144,6 @@ BatchDialogConfig BatchDialog::getConfig() const
dlgCfg.batchExCfg.autoCloseSummary = m_checkBoxAutoClose ->GetValue();
dlgCfg.batchExCfg.postSyncAction = getEnumVal(enumPostSyncAction_, *m_choicePostSyncAction);
- dlgCfg.batchExCfg.altLogFolderPathPhrase = utfTo<Zstring>(logfileDir_->getPath());
- dlgCfg.batchExCfg.altLogfileCountMax = m_checkBoxSaveLog->GetValue() ? (m_checkBoxLogfilesLimit->GetValue() ? m_spinCtrlLogfileLimit->GetValue() : -1) : 0;
-
- warn_static("consider for removal after FFS 10.3 release")
-#if 1
- dlgCfg.batchExCfg.altLogfileCountMax = 0;
-#endif
-
return dlgCfg;
}
@@ -199,20 +156,10 @@ void BatchDialog::onLocalKeyEvent(wxKeyEvent& event)
void BatchDialog::OnSaveBatchJob(wxCommandEvent& event)
{
- BatchDialogConfig dlgCfg = getConfig();
+ //BatchDialogConfig dlgCfg = getConfig();
//------- parameter validation (BEFORE writing output!) -------
- warn_static("consider for removal after FFS 10.3 release")
-#if 0
- if (dlgCfg.batchExCfg.altLogfileCountMax != 0 &&
- trimCpy(dlgCfg.batchExCfg.altLogFolderPathPhrase).empty())
- {
- showNotificationDialog(this, DialogInfoType::INFO, PopupDialogCfg().setMainInstructions(_("A folder input field is empty.")));
- //don't show error icon to follow "Windows' encouraging tone"
- m_logFolderPath->SetFocus();
- return;
- }
-#endif
+
//-------------------------------------------------------------
dlgCfgOut_ = getConfig();
diff --git a/FreeFileSync/Source/ui/batch_status_handler.cpp b/FreeFileSync/Source/ui/batch_status_handler.cpp
index 04201a9d..a4e45c50 100755
--- a/FreeFileSync/Source/ui/batch_status_handler.cpp
+++ b/FreeFileSync/Source/ui/batch_status_handler.cpp
@@ -22,12 +22,10 @@ BatchStatusHandler::BatchStatusHandler(bool showProgress,
const std::wstring& jobName,
const Zstring& soundFileSyncComplete,
const std::chrono::system_clock::time_point& startTime,
- int altLogfileCountMax, //0: logging inactive; < 0: no limit
- const Zstring& altLogFolderPathPhrase,
bool ignoreErrors,
BatchErrorHandling batchErrorHandling,
size_t automaticRetryCount,
- size_t automaticRetryDelay,
+ std::chrono::seconds automaticRetryDelay,
const Zstring& postSyncCommand,
PostSyncCondition postSyncCondition,
PostSyncAction postSyncAction) :
@@ -52,9 +50,7 @@ jobName, soundFileSyncComplete, ignoreErrors, automaticRetryCount, [&]
jobName_(jobName),
startTime_(startTime),
postSyncCommand_(postSyncCommand),
- postSyncCondition_(postSyncCondition),
- altLogfileCountMax_(altLogfileCountMax),
- altLogFolderPathPhrase_(altLogFolderPathPhrase)
+ postSyncCondition_(postSyncCondition)
{
//ATTENTION: "progressDlg_" is an unmanaged resource!!! However, at this point we already consider construction complete! =>
//ZEN_ON_SCOPE_FAIL( cleanup(); ); //destructor call would lead to member double clean-up!!!
@@ -73,7 +69,7 @@ BatchStatusHandler::~BatchStatusHandler()
}
-BatchStatusHandler::Result BatchStatusHandler::reportFinalStatus(int logfilesMaxAgeDays, const std::set<Zstring, LessFilePath>& logFilePathsToKeep) //noexcept!!
+BatchStatusHandler::Result BatchStatusHandler::reportFinalStatus(const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep) //noexcept!!
{
const auto totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime_);
@@ -139,29 +135,21 @@ BatchStatusHandler::Result BatchStatusHandler::reportFinalStatus(int logfilesMax
//----------------- always save log under %appdata%\FreeFileSync\Logs ------------------------
//create not before destruction: 1. avoid issues with FFS trying to sync open log file 2. simplify transactional retry on failure 3. include status in log file name without rename
// 4. failure to write to particular stream must not be retried!
- Zstring logFilePath;
+ AbstractPath logFilePath = getNullPath();
try
{
//do NOT use tryReportingError()! saving log files should not be cancellable!
auto notifyStatusNoThrow = [&](const std::wstring& msg) { try { reportStatus(msg); /*throw X*/ } catch (...) {} };
- logFilePath = saveLogFile(summary, errorLog_, startTime_, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatusNoThrow /*throw X*/); //throw FileError
+ logFilePath = saveLogFile(summary, errorLog_, startTime_, altLogFolderPathPhrase, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatusNoThrow /*throw X*/); //throw FileError
}
catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
- warn_static("consider for removal after FFS 10.3 release")
-#if 1
- ////save additional logfile copy to user-defined path if requested
- //doSaveLogFile(altLogFolderPathPhrase_, altLogfileCountMax_);
- (void)altLogFolderPathPhrase_;
- (void)altLogfileCountMax_;
-#endif
-
//execute post sync command *after* writing log files, so that user can refer to the log via the command!
if (!commandLine.empty())
try
{
//----------------------------------------------------------------------
- ::wxSetEnv(L"logfile_path", utfTo<wxString>(logFilePath));
+ ::wxSetEnv(L"logfile_path", AFS::getDisplayPath(logFilePath));
//----------------------------------------------------------------------
//use ExecutionType::ASYNC until there is reason not to: https://freefilesync.org/forum/viewtopic.php?t=31
shellExecute(expandMacros(commandLine), ExecutionType::ASYNC); //throw FileError
@@ -191,7 +179,7 @@ BatchStatusHandler::Result BatchStatusHandler::reportFinalStatus(int logfilesMax
if (progressDlg_->getWindowIfVisible())
try
{
- delayAndCountDown(operationName, 5 /*delayInSec*/, notifyStatusThrowOnCancel); //throw X
+ delayAndCountDown(operationName, std::chrono::seconds(5), notifyStatusThrowOnCancel); //throw X
}
catch (...) { return false; }
diff --git a/FreeFileSync/Source/ui/batch_status_handler.h b/FreeFileSync/Source/ui/batch_status_handler.h
index 3ed11e4d..847e03d6 100755
--- a/FreeFileSync/Source/ui/batch_status_handler.h
+++ b/FreeFileSync/Source/ui/batch_status_handler.h
@@ -26,12 +26,10 @@ public:
const std::wstring& jobName, //should not be empty for a batch job!
const Zstring& soundFileSyncComplete,
const std::chrono::system_clock::time_point& startTime,
- int altLogfileCountMax, //0: logging inactive; < 0: no limit
- const Zstring& altLogFolderPathPhrase,
bool ignoreErrors,
BatchErrorHandling batchErrorHandling,
size_t automaticRetryCount,
- size_t automaticRetryDelay,
+ std::chrono::seconds automaticRetryDelay,
const Zstring& postSyncCommand,
PostSyncCondition postSyncCondition,
PostSyncAction postSyncAction); //noexcept!!
@@ -50,9 +48,9 @@ public:
{
SyncResult finalStatus;
bool switchToGuiRequested;
- Zstring logFilePath;
+ AbstractPath logFilePath;
};
- Result reportFinalStatus(int logfilesMaxAgeDays, const std::set<Zstring, LessFilePath>& logFilePathsToKeep); //noexcept!!
+ Result reportFinalStatus(const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep); //noexcept!!
private:
void onProgressDialogTerminate();
@@ -63,7 +61,7 @@ private:
zen::ErrorLog errorLog_; //list of non-resolved errors and warnings
const size_t automaticRetryCount_;
- const size_t automaticRetryDelay_;
+ const std::chrono::seconds automaticRetryDelay_;
SyncProgressDialog* progressDlg_; //managed to have shorter lifetime than this handler!
@@ -72,9 +70,6 @@ private:
const Zstring postSyncCommand_;
const PostSyncCondition postSyncCondition_;
-
- const int altLogfileCountMax_;
- const Zstring altLogFolderPathPhrase_;
};
}
diff --git a/FreeFileSync/Source/ui/cfg_grid.cpp b/FreeFileSync/Source/ui/cfg_grid.cpp
index 939050d6..72acf4a6 100755
--- a/FreeFileSync/Source/ui/cfg_grid.cpp
+++ b/FreeFileSync/Source/ui/cfg_grid.cpp
@@ -15,9 +15,11 @@
#include <wx/settings.h>
#include "../base/icon_buffer.h"
#include "../base/ffs_paths.h"
+//#include "../fs/mtp.h"
using namespace zen;
using namespace fff;
+using AFS = AbstractFileSystem;
Zstring fff::getLastRunConfigPath()
@@ -131,7 +133,7 @@ void ConfigView::setLastRunStats(const std::vector<Zstring>& filePaths, const La
if (lastRun.result != SyncResult::ABORTED)
it->second.cfgItem.lastSyncTime = lastRun.lastRunTime;
- if (!lastRun.logFilePath.empty())
+ if (!AFS::isNullPath(lastRun.logFilePath))
{
it->second.cfgItem.logFilePath = lastRun.logFilePath;
it->second.cfgItem.logResult = lastRun.result;
@@ -184,8 +186,8 @@ void ConfigView::sortListViewImpl()
if (lhs->second.isLastRunCfg != rhs->second.isLastRunCfg)
return lhs->second.isLastRunCfg < rhs->second.isLastRunCfg; //"last session" label should be (always) last
- const bool hasLogL = !lhs->second.cfgItem.logFilePath.empty();
- const bool hasLogR = !rhs->second.cfgItem.logFilePath.empty();
+ const bool hasLogL = !AFS::isNullPath(lhs->second.cfgItem.logFilePath);
+ const bool hasLogR = !AFS::isNullPath(rhs->second.cfgItem.logFilePath);
if (hasLogL != hasLogR)
return hasLogL > hasLogR; //move sync jobs that were never run to the back
@@ -288,7 +290,7 @@ private:
case ColumnTypeCfg::LAST_LOG:
if (!item->isLastRunCfg &&
- !item->cfgItem.logFilePath.empty())
+ !AFS::isNullPath(item->cfgItem.logFilePath))
return getFinalStatusLabel(item->cfgItem.logResult);
break;
}
@@ -360,7 +362,7 @@ private:
case ColumnTypeCfg::LAST_LOG:
if (!item->isLastRunCfg &&
- !item->cfgItem.logFilePath.empty())
+ !AFS::isNullPath(item->cfgItem.logFilePath))
{
const wxBitmap statusIcon = [&]
{
@@ -423,7 +425,8 @@ private:
case ColumnTypeCfg::LAST_LOG:
if (!item->isLastRunCfg &&
- !item->cfgItem.logFilePath.empty())
+ !AFS::isNullPath(item->cfgItem.logFilePath) &&
+ AFS::getNativeItemPath(item->cfgItem.logFilePath))
return static_cast<HoverArea>(HoverAreaLog::LINK);
break;
}
@@ -506,8 +509,8 @@ private:
case ColumnTypeCfg::LAST_LOG:
if (!item->isLastRunCfg &&
- !item->cfgItem.logFilePath.empty())
- return getFinalStatusLabel(item->cfgItem.logResult) + SPACED_DASH + utfTo<std::wstring>(item->cfgItem.logFilePath);
+ !AFS::isNullPath(item->cfgItem.logFilePath))
+ return getFinalStatusLabel(item->cfgItem.logResult) + SPACED_DASH + AFS::getDisplayPath(item->cfgItem.logFilePath);
break;
}
return std::wstring();
@@ -519,10 +522,13 @@ private:
switch (static_cast<HoverAreaLog>(event.hoverArea_))
{
case HoverAreaLog::LINK:
- assert(!item->cfgItem.logFilePath.empty()); //see getRowMouseHover()
try
{
- openWithDefaultApplication(item->cfgItem.logFilePath); //throw FileError
+ if (std::optional<Zstring> nativePath = AFS::getNativeItemPath(item->cfgItem.logFilePath))
+ openWithDefaultApplication(*nativePath); //throw FileError
+ else
+ assert(false);
+ assert(!AFS::isNullPath(item->cfgItem.logFilePath)); //see getRowMouseHover()
}
catch (const FileError& e) { showNotificationDialog(&grid_, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString())); }
return;
@@ -532,11 +538,11 @@ private:
void onMouseLeftDouble(GridClickEvent& event)
{
- switch (static_cast<HoverAreaLog>(event.hoverArea_))
- {
- case HoverAreaLog::LINK:
- return; //swallow event here before MainDialog considers it as a request to start comparison
- }
+ switch (static_cast<HoverAreaLog>(event.hoverArea_))
+ {
+ case HoverAreaLog::LINK:
+ return; //swallow event here before MainDialog considers it as a request to start comparison
+ }
event.Skip();
}
@@ -576,7 +582,7 @@ void cfggrid::addAndSelect(Grid& grid, const std::vector<Zstring>& filePaths, bo
grid.clearSelection(GridEventPolicy::DENY);
const std::set<Zstring, LessFilePath> pathsSorted(filePaths.begin(), filePaths.end());
- Opt<size_t> selectionTopRow;
+ std::optional<size_t> selectionTopRow;
for (size_t i = 0; i < grid.getRowCount(); ++i)
if (pathsSorted.find(getDataView(grid).getItem(i)->cfgItem.cfgFilePath) != pathsSorted.end())
diff --git a/FreeFileSync/Source/ui/cfg_grid.h b/FreeFileSync/Source/ui/cfg_grid.h
index fc99a40d..37947867 100755
--- a/FreeFileSync/Source/ui/cfg_grid.h
+++ b/FreeFileSync/Source/ui/cfg_grid.h
@@ -11,6 +11,7 @@
#include <wx+/dc.h>
#include <zen/zstring.h>
#include "../base/return_codes.h"
+#include "../fs/native.h"
namespace fff
@@ -20,7 +21,7 @@ struct ConfigFileItem
ConfigFileItem() {}
ConfigFileItem(const Zstring& filePath,
time_t syncTime,
- const Zstring& logPath,
+ const AbstractPath& logPath,
SyncResult result) :
cfgFilePath(filePath),
lastSyncTime(syncTime),
@@ -28,9 +29,9 @@ struct ConfigFileItem
logResult(result) {}
Zstring cfgFilePath;
- time_t lastSyncTime = 0; //last COMPLETED sync (aborted syncs don't count)
- Zstring logFilePath; //ANY last sync attempt (including aborted syncs)
- SyncResult logResult = SyncResult::ABORTED; //
+ time_t lastSyncTime = 0; //last COMPLETED sync (aborted syncs don't count)
+ AbstractPath logFilePath = getNullPath(); //ANY last sync attempt (including aborted syncs)
+ SyncResult logResult = SyncResult::ABORTED; //
};
@@ -96,9 +97,9 @@ public:
struct LastRunStats
{
- time_t lastRunTime = 0;
- SyncResult result = SyncResult::ABORTED;
- Zstring logFilePath; //optional
+ time_t lastRunTime = 0;
+ SyncResult result = SyncResult::ABORTED;
+ AbstractPath logFilePath; //optional
};
void setLastRunStats(const std::vector<Zstring>& filePaths, const LastRunStats& lastRun);
diff --git a/FreeFileSync/Source/ui/file_grid.cpp b/FreeFileSync/Source/ui/file_grid.cpp
index cc1c5ece..1f634cd4 100755
--- a/FreeFileSync/Source/ui/file_grid.cpp
+++ b/FreeFileSync/Source/ui/file_grid.cpp
@@ -544,7 +544,7 @@ private:
break;
case IconInfo::ICON_PATH:
- if (Opt<wxBitmap> tmpIco = iconMgr_->refIconBuffer().retrieveFileIcon(ii.fsObj->template getAbstractPath<side>()))
+ if (std::optional<wxBitmap> tmpIco = iconMgr_->refIconBuffer().retrieveFileIcon(ii.fsObj->template getAbstractPath<side>()))
fileIcon = *tmpIco;
else
{
@@ -679,17 +679,12 @@ private:
//draw sort marker
if (getGridDataView())
- {
- auto sortInfo = getGridDataView()->getSortInfo();
- if (sortInfo)
- {
+ if (auto sortInfo = getGridDataView()->getSortInfo())
if (colType == static_cast<ColumnType>(sortInfo->type) && (side == LEFT_SIDE) == sortInfo->onLeft)
{
const wxBitmap& marker = getResourceImage(sortInfo->ascending ? L"sort_ascending" : L"sort_descending");
drawBitmapRtlNoMirror(dc, marker, rectInner, wxALIGN_CENTER_HORIZONTAL);
}
- }
- }
}
struct IconInfo
@@ -769,7 +764,7 @@ private:
ItemPathFormat itemPathFormat_ = ItemPathFormat::FULL_PATH;
std::vector<char> failedLoads_; //effectively a vector<bool> of size "number of rows"
- Opt<wxBitmap> renderBuf_; //avoid costs of recreating this temporary variable
+ std::optional<wxBitmap> renderBuf_; //avoid costs of recreating this temporary variable
};
@@ -1285,7 +1280,7 @@ private:
bool highlightSyncAction_ = false;
bool selectionInProgress_ = false;
- Opt<wxBitmap> renderBuf_; //avoid costs of recreating this temporary variable
+ std::optional<wxBitmap> renderBuf_; //avoid costs of recreating this temporary variable
Tooltip toolTip_;
wxImage notch_ = getResourceImage(L"notch").ConvertToImage();
};
diff --git a/FreeFileSync/Source/ui/file_view.cpp b/FreeFileSync/Source/ui/file_view.cpp
index 09986aac..1d602540 100755
--- a/FreeFileSync/Source/ui/file_view.cpp
+++ b/FreeFileSync/Source/ui/file_view.cpp
@@ -176,7 +176,7 @@ FileView::StatusSyncPreview FileView::updateSyncPreview(bool showExcluded, //map
{
StatusSyncPreview output;
- updateView([&](const FileSystemObject& fsObj) -> bool
+ updateView([&](const FileSystemObject& fsObj)
{
if (!fsObj.isActive())
{
@@ -322,7 +322,7 @@ void FileView::setData(FolderComparison& folderCmp)
//clear everything
std::vector<FileSystemObject::ObjectId>().swap(viewRef_); //free mem
std::vector<RefIndex>().swap(sortedRef_); //
- currentSort_ = NoValue();
+ currentSort_ = {};
folderPairCount_ = std::count_if(begin(folderCmp), end(folderCmp),
[](const BaseFolderPair& baseObj) //count non-empty pairs to distinguish single/multiple folder pair cases
diff --git a/FreeFileSync/Source/ui/file_view.h b/FreeFileSync/Source/ui/file_view.h
index c87590e7..2bef757c 100755
--- a/FreeFileSync/Source/ui/file_view.h
+++ b/FreeFileSync/Source/ui/file_view.h
@@ -9,6 +9,7 @@
#include <vector>
#include <unordered_map>
+#include <zen/stl_tools.h>
#include "file_grid_attr.h"
#include "../base/file_hierarchy.h"
@@ -108,7 +109,7 @@ public:
bool onLeft = false;
bool ascending = false;
};
- const SortInfo* getSortInfo() const { return currentSort_.get(); } //return nullptr if currently not sorted
+ const SortInfo* getSortInfo() const { return zen::get(currentSort_); } //return nullptr if currently not sorted
ptrdiff_t findRowDirect(FileSystemObject::ObjectIdConst objId) const; // find an object's row position on view list directly, return < 0 if not found
ptrdiff_t findRowFirstChild(const ContainerObject* hierObj) const; // find first child of FolderPair or BaseFolderPair *on sorted sub view*
@@ -172,7 +173,7 @@ private:
template <bool ascending>
struct LessSyncDirection;
- zen::Opt<SortInfo> currentSort_;
+ std::optional<SortInfo> currentSort_;
};
diff --git a/FreeFileSync/Source/ui/folder_pair.h b/FreeFileSync/Source/ui/folder_pair.h
index 4ac801dd..357de4d3 100755
--- a/FreeFileSync/Source/ui/folder_pair.h
+++ b/FreeFileSync/Source/ui/folder_pair.h
@@ -28,7 +28,7 @@ template <class GuiPanel>
class FolderPairPanelBasic : private wxEvtHandler
{
public:
- void setConfig(const zen::Opt<CompConfig>& compConfig, const zen::Opt<SyncConfig>& syncCfg, const FilterConfig& filter)
+ void setConfig(const std::optional<CompConfig>& compConfig, const std::optional<SyncConfig>& syncCfg, const FilterConfig& filter)
{
localCmpCfg_ = compConfig;
localSyncCfg_ = syncCfg;
@@ -36,8 +36,8 @@ public:
refreshButtons();
}
- zen::Opt<CompConfig> getCompConfig () const { return localCmpCfg_; }
- zen::Opt<SyncConfig> getSyncConfig () const { return localSyncCfg_; }
+ std::optional<CompConfig> getCompConfig () const { return localCmpCfg_; }
+ std::optional<SyncConfig> getSyncConfig () const { return localSyncCfg_; }
FilterConfig getFilterConfig() const { return localFilter_; }
@@ -95,7 +95,7 @@ private:
{
auto removeLocalCompCfg = [&]
{
- this->localCmpCfg_ = zen::NoValue(); //"this->" galore: workaround GCC compiler bugs
+ this->localCmpCfg_ = {}; //"this->" galore: workaround GCC compiler bugs
this->refreshButtons();
this->onLocalCompCfgChange();
};
@@ -109,7 +109,7 @@ private:
{
auto removeLocalSyncCfg = [&]
{
- this->localSyncCfg_ = zen::NoValue();
+ this->localSyncCfg_ = {};
this->refreshButtons();
this->onLocalSyncCfgChange();
};
@@ -161,8 +161,8 @@ private:
GuiPanel& basicPanel_; //panel to be enhanced by this template
//alternate configuration attached to it
- zen::Opt<CompConfig> localCmpCfg_;
- zen::Opt<SyncConfig> localSyncCfg_;
+ std::optional<CompConfig> localCmpCfg_;
+ std::optional<SyncConfig> localSyncCfg_;
FilterConfig localFilter_;
};
}
diff --git a/FreeFileSync/Source/ui/folder_selector.cpp b/FreeFileSync/Source/ui/folder_selector.cpp
index babef8bb..0d68ccad 100755
--- a/FreeFileSync/Source/ui/folder_selector.cpp
+++ b/FreeFileSync/Source/ui/folder_selector.cpp
@@ -36,8 +36,10 @@ void setFolderPathPhrase(const Zstring& folderPathPhrase, FolderHistoryBox* comb
const Zstring folderPathPhraseFmt = AFS::getInitPathPhrase(createAbstractPath(folderPathPhrase)); //noexcept
//may block when resolving [<volume name>]
- tooltipWnd.SetToolTip(nullptr); //workaround wxComboBox bug http://trac.wxwidgets.org/ticket/10512 / http://trac.wxwidgets.org/ticket/12659
- tooltipWnd.SetToolTip(utfTo<wxString>(folderPathPhraseFmt)); //who knows when the real bugfix reaches mere mortals via an official release...
+ if (folderPathPhraseFmt.empty())
+ tooltipWnd.UnsetToolTip(); //wxGTK doesn't allow wxToolTip with empty text!
+ else
+ tooltipWnd.SetToolTip(utfTo<wxString>(folderPathPhraseFmt));
if (staticText)
{
@@ -143,7 +145,7 @@ void FolderSelector::onItemPathDropped(FileDropEvent& event)
try
{
if (AFS::getItemType(itemPath) == AFS::ItemType::FILE) //throw FileError
- if (Opt<AbstractPath> parentPath = AFS::getParentFolderPath(itemPath))
+ if (std::optional<AbstractPath> parentPath = AFS::getParentFolderPath(itemPath))
return AFS::getInitPathPhrase(*parentPath);
}
catch (FileError&) {} //e.g. good for inactive mapped network shares, not so nice for C:\pagefile.sys
@@ -198,7 +200,7 @@ void FolderSelector::onSelectFolder(wxCommandEvent& event)
{
const AbstractPath folderPath = createItemPathNative(folderPathPhrase);
if (folderExistsTimed(folderPath))
- if (Opt<Zstring> nativeFolderPath = AFS::getNativeItemPath(folderPath))
+ if (std::optional<Zstring> nativeFolderPath = AFS::getNativeItemPath(folderPath))
defaultFolderPath = *nativeFolderPath;
}
}
diff --git a/FreeFileSync/Source/ui/gui_generated.cpp b/FreeFileSync/Source/ui/gui_generated.cpp
index 820b5f6f..00b3ff64 100755
--- a/FreeFileSync/Source/ui/gui_generated.cpp
+++ b/FreeFileSync/Source/ui/gui_generated.cpp
@@ -1498,6 +1498,61 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_staticline331 = new wxStaticLine( m_panelComparisonSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer159->Add( m_staticline331, 0, wxEXPAND, 5 );
+ bSizerCompMisc = new wxBoxSizer( wxVERTICAL );
+
+ wxBoxSizer* bSizer2781;
+ bSizer2781 = new wxBoxSizer( wxHORIZONTAL );
+
+ wxFlexGridSizer* fgSizer61;
+ fgSizer61 = new wxFlexGridSizer( 0, 2, 5, 5 );
+ fgSizer61->SetFlexibleDirection( wxBOTH );
+ fgSizer61->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+
+ m_bitmapIgnoreErrors = new wxStaticBitmap( m_panelComparisonSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ fgSizer61->Add( m_bitmapIgnoreErrors, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_checkBoxIgnoreErrors = new wxCheckBox( m_panelComparisonSettings, wxID_ANY, _("Ignore errors"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ fgSizer61->Add( m_checkBoxIgnoreErrors, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+
+ m_bitmapRetryErrors = new wxStaticBitmap( m_panelComparisonSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ fgSizer61->Add( m_bitmapRetryErrors, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+
+ m_checkBoxAutoRetry = new wxCheckBox( m_panelComparisonSettings, wxID_ANY, _("Automatic retry"), wxDefaultPosition, wxDefaultSize, 0 );
+ fgSizer61->Add( m_checkBoxAutoRetry, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+
+
+ bSizer2781->Add( fgSizer61, 0, wxALIGN_CENTER_VERTICAL|wxALL, 10 );
+
+ fgSizerAutoRetry = new wxFlexGridSizer( 0, 2, 5, 10 );
+ fgSizerAutoRetry->SetFlexibleDirection( wxBOTH );
+ fgSizerAutoRetry->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+
+ m_staticText96 = new wxStaticText( m_panelComparisonSettings, wxID_ANY, _("Retry count:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText96->Wrap( -1 );
+ fgSizerAutoRetry->Add( m_staticText96, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_staticTextAutoRetryDelay = new wxStaticText( m_panelComparisonSettings, wxID_ANY, _("Delay (in seconds):"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextAutoRetryDelay->Wrap( -1 );
+ fgSizerAutoRetry->Add( m_staticTextAutoRetryDelay, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_spinCtrlAutoRetryCount = new wxSpinCtrl( m_panelComparisonSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 );
+ fgSizerAutoRetry->Add( m_spinCtrlAutoRetryCount, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_spinCtrlAutoRetryDelay = new wxSpinCtrl( m_panelComparisonSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 0, 2000000000, 0 );
+ fgSizerAutoRetry->Add( m_spinCtrlAutoRetryDelay, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+
+ bSizer2781->Add( fgSizerAutoRetry, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER_VERTICAL, 10 );
+
+
+ bSizerCompMisc->Add( bSizer2781, 0, wxEXPAND, 5 );
+
+ m_staticline3311 = new wxStaticLine( m_panelComparisonSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ bSizerCompMisc->Add( m_staticline3311, 0, wxEXPAND, 5 );
+
+
+ bSizer159->Add( bSizerCompMisc, 0, wxEXPAND, 5 );
+
bSizer2561->Add( bSizer159, 1, wxEXPAND, 5 );
@@ -1855,6 +1910,9 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer237->Add( bSizer235, 0, wxALL, 5 );
+
+ bSizer237->Add( 10, 0, 0, 0, 5 );
+
wxBoxSizer* bSizer238;
bSizer238 = new wxBoxSizer( wxVERTICAL );
@@ -1956,7 +2014,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizerSyncDirHolder->Add( m_staticTextSyncVarDescription, 0, wxALL|wxALIGN_CENTER_VERTICAL, 10 );
- bSizer238->Add( bSizerSyncDirHolder, 0, wxALL, 10 );
+ bSizer238->Add( bSizerSyncDirHolder, 0, wxTOP|wxBOTTOM|wxRIGHT, 10 );
bSizer238->Add( 0, 0, 1, wxEXPAND, 5 );
@@ -2090,10 +2148,10 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer156->Add( m_buttonSelectVersioningFolder, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_bpButtonSelectAltFolder = new wxBitmapButton( m_panelVersioning, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW );
- m_bpButtonSelectAltFolder->SetToolTip( _("Access online storage") );
+ m_bpButtonSelectVersioningAltFolder = new wxBitmapButton( m_panelVersioning, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW );
+ m_bpButtonSelectVersioningAltFolder->SetToolTip( _("Access online storage") );
- bSizer156->Add( m_bpButtonSelectAltFolder, 0, wxEXPAND, 5 );
+ bSizer156->Add( m_bpButtonSelectVersioningAltFolder, 0, wxEXPAND, 5 );
bSizer253->Add( bSizer156, 0, wxEXPAND, 5 );
@@ -2212,78 +2270,83 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_staticline582 = new wxStaticLine( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer232->Add( m_staticline582, 0, wxEXPAND, 5 );
- bSizerMiscConfig = new wxBoxSizer( wxHORIZONTAL );
+ bSizerSyncMisc = new wxBoxSizer( wxHORIZONTAL );
- wxFlexGridSizer* fgSizer61;
- fgSizer61 = new wxFlexGridSizer( 0, 2, 5, 5 );
- fgSizer61->SetFlexibleDirection( wxBOTH );
- fgSizer61->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+ wxBoxSizer* bSizer2372;
+ bSizer2372 = new wxBoxSizer( wxHORIZONTAL );
- m_bitmapIgnoreErrors = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- fgSizer61->Add( m_bitmapIgnoreErrors, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
+ m_panelLogfile = new wxPanel( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_panelLogfile->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
- m_checkBoxIgnoreErrors = new wxCheckBox( m_panelSyncSettings, wxID_ANY, _("Ignore errors"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
- fgSizer61->Add( m_checkBoxIgnoreErrors, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+ wxBoxSizer* bSizer1912;
+ bSizer1912 = new wxBoxSizer( wxVERTICAL );
- m_bitmapRetryErrors = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- fgSizer61->Add( m_bitmapRetryErrors, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
+ wxBoxSizer* bSizer279;
+ bSizer279 = new wxBoxSizer( wxHORIZONTAL );
- m_checkBoxAutoRetry = new wxCheckBox( m_panelSyncSettings, wxID_ANY, _("Automatic retry"), wxDefaultPosition, wxDefaultSize, 0 );
- fgSizer61->Add( m_checkBoxAutoRetry, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+ m_bitmapLogFile = new wxStaticBitmap( m_panelLogfile, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ bSizer279->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ m_checkBoxSaveLog = new wxCheckBox( m_panelLogfile, wxID_ANY, _("&Override default log path:"), wxDefaultPosition, wxDefaultSize, 0 );
+ bSizer279->Add( m_checkBoxSaveLog, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
- bSizerMiscConfig->Add( fgSizer61, 0, wxALIGN_CENTER_VERTICAL|wxALL, 10 );
+ m_buttonSelectLogFolder = new wxButton( m_panelLogfile, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_buttonSelectLogFolder->SetToolTip( _("Select a folder") );
- fgSizerAutoRetry = new wxFlexGridSizer( 0, 2, 5, 10 );
- fgSizerAutoRetry->SetFlexibleDirection( wxBOTH );
- fgSizerAutoRetry->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+ bSizer279->Add( m_buttonSelectLogFolder, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_staticText96 = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("Retry count:"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText96->Wrap( -1 );
- fgSizerAutoRetry->Add( m_staticText96, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ m_bpButtonSelectAltLogFolder = new wxBitmapButton( m_panelLogfile, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW );
+ m_bpButtonSelectAltLogFolder->SetToolTip( _("Access online storage") );
- m_staticTextAutoRetryDelay = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("Delay (in seconds):"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticTextAutoRetryDelay->Wrap( -1 );
- fgSizerAutoRetry->Add( m_staticTextAutoRetryDelay, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer279->Add( m_bpButtonSelectAltLogFolder, 0, wxEXPAND, 5 );
- m_spinCtrlAutoRetryCount = new wxSpinCtrl( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 );
- fgSizerAutoRetry->Add( m_spinCtrlAutoRetryCount, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_spinCtrlAutoRetryDelay = new wxSpinCtrl( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 0, 2000000000, 0 );
- fgSizerAutoRetry->Add( m_spinCtrlAutoRetryDelay, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer1912->Add( bSizer279, 0, wxEXPAND, 5 );
+
+ m_logFolderPath = new fff::FolderHistoryBox( m_panelLogfile, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ bSizer1912->Add( m_logFolderPath, 0, wxEXPAND|wxTOP, 5 );
- bSizerMiscConfig->Add( fgSizerAutoRetry, 0, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_CENTER_VERTICAL, 10 );
+ m_panelLogfile->SetSizer( bSizer1912 );
+ m_panelLogfile->Layout();
+ bSizer1912->Fit( m_panelLogfile );
+ bSizer2372->Add( m_panelLogfile, 1, 0, 5 );
+
+
+ bSizerSyncMisc->Add( bSizer2372, 1, wxALL|wxALIGN_CENTER_VERTICAL, 10 );
m_staticline57 = new wxStaticLine( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
- bSizerMiscConfig->Add( m_staticline57, 0, wxEXPAND, 5 );
+ bSizerSyncMisc->Add( m_staticline57, 0, wxEXPAND, 5 );
wxBoxSizer* bSizer247;
bSizer247 = new wxBoxSizer( wxVERTICAL );
+ wxBoxSizer* bSizer251;
+ bSizer251 = new wxBoxSizer( wxHORIZONTAL );
+
m_staticText89 = new wxStaticText( m_panelSyncSettings, wxID_ANY, _("Run a command after synchronization:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText89->Wrap( -1 );
- bSizer247->Add( m_staticText89, 0, wxBOTTOM, 5 );
+ bSizer251->Add( m_staticText89, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
- wxBoxSizer* bSizer251;
- bSizer251 = new wxBoxSizer( wxHORIZONTAL );
+
+ bSizer251->Add( 0, 0, 1, 0, 5 );
wxArrayString m_choicePostSyncConditionChoices;
m_choicePostSyncCondition = new wxChoice( m_panelSyncSettings, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choicePostSyncConditionChoices, 0 );
m_choicePostSyncCondition->SetSelection( 0 );
bSizer251->Add( m_choicePostSyncCondition, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_comboBoxPostSyncCommand = new fff::CommandBox( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
- bSizer251->Add( m_comboBoxPostSyncCommand, 1, wxALIGN_CENTER_VERTICAL, 5 );
-
bSizer247->Add( bSizer251, 0, wxEXPAND, 5 );
+ m_comboBoxPostSyncCommand = new fff::CommandBox( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ bSizer247->Add( m_comboBoxPostSyncCommand, 0, wxTOP|wxEXPAND, 5 );
+
- bSizerMiscConfig->Add( bSizer247, 1, wxALL|wxALIGN_CENTER_VERTICAL, 10 );
+ bSizerSyncMisc->Add( bSizer247, 1, wxALL|wxALIGN_CENTER_VERTICAL, 10 );
- bSizer232->Add( bSizerMiscConfig, 1, wxEXPAND, 5 );
+ bSizer232->Add( bSizerSyncMisc, 0, wxEXPAND, 5 );
m_panelSyncSettings->SetSizer( bSizer232 );
@@ -2338,6 +2401,8 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_hyperlink24->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpComparisonSettings ), NULL, this );
m_textCtrlTimeShift->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( ConfigDlgGenerated::onlTimeShiftKeyDown ), NULL, this );
m_hyperlink241->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpTimeShift ), NULL, this );
+ m_checkBoxIgnoreErrors->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleIgnoreErrors ), NULL, this );
+ m_checkBoxAutoRetry->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleAutoRetry ), NULL, this );
m_hyperlink1711->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpPerformance ), NULL, this );
m_textCtrlInclude->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( ConfigDlgGenerated::OnChangeFilterOption ), NULL, this );
m_hyperlink171->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpShowExamples ), NULL, this );
@@ -2371,8 +2436,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_checkBoxVersionMaxDays->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleVersioningLimit ), NULL, this );
m_checkBoxVersionCountMin->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleVersioningLimit ), NULL, this );
m_checkBoxVersionCountMax->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleVersioningLimit ), NULL, this );
- m_checkBoxIgnoreErrors->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleIgnoreErrors ), NULL, this );
- m_checkBoxAutoRetry->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleAutoRetry ), NULL, this );
+ m_checkBoxSaveLog->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleSaveLogfile ), NULL, this );
m_buttonOkay->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnOkay ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnCancel ), NULL, this );
}
@@ -3714,64 +3778,6 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_staticline25 = new wxStaticLine( m_panel35, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer172->Add( m_staticline25, 0, wxEXPAND, 5 );
- wxBoxSizer* bSizer237;
- bSizer237 = new wxBoxSizer( wxHORIZONTAL );
-
- m_bitmapLogFile = new wxStaticBitmap( m_panel35, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer237->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
-
- wxBoxSizer* bSizer191;
- bSizer191 = new wxBoxSizer( wxVERTICAL );
-
- wxBoxSizer* bSizer238;
- bSizer238 = new wxBoxSizer( wxHORIZONTAL );
-
- m_checkBoxSaveLog = new wxCheckBox( m_panel35, wxID_ANY, _("Save log:"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer238->Add( m_checkBoxSaveLog, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
-
-
- bSizer238->Add( 0, 0, 1, wxEXPAND, 5 );
-
- m_checkBoxLogfilesLimit = new wxCheckBox( m_panel35, wxID_ANY, _("Limit number of log files:"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer238->Add( m_checkBoxLogfilesLimit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
-
- m_spinCtrlLogfileLimit = new wxSpinCtrl( m_panel35, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 );
- bSizer238->Add( m_spinCtrlLogfileLimit, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
-
-
- bSizer191->Add( bSizer238, 0, wxEXPAND, 5 );
-
- m_panelLogfile = new wxPanel( m_panel35, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
- m_panelLogfile->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- wxBoxSizer* bSizer1721;
- bSizer1721 = new wxBoxSizer( wxHORIZONTAL );
-
- m_logFolderPath = new fff::FolderHistoryBox( m_panelLogfile, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
- bSizer1721->Add( m_logFolderPath, 1, wxALIGN_CENTER_VERTICAL, 5 );
-
- m_buttonSelectLogFolder = new wxButton( m_panelLogfile, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
- m_buttonSelectLogFolder->SetToolTip( _("Select a folder") );
-
- bSizer1721->Add( m_buttonSelectLogFolder, 0, wxALIGN_CENTER_VERTICAL, 5 );
-
- m_bpButtonSelectAltLogFolder = new wxBitmapButton( m_panelLogfile, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), wxBU_AUTODRAW );
- m_bpButtonSelectAltLogFolder->SetToolTip( _("Access online storage") );
-
- bSizer1721->Add( m_bpButtonSelectAltLogFolder, 0, wxEXPAND, 5 );
-
-
- m_panelLogfile->SetSizer( bSizer1721 );
- m_panelLogfile->Layout();
- bSizer1721->Fit( m_panelLogfile );
- bSizer191->Add( m_panelLogfile, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
-
-
- bSizer237->Add( bSizer191, 1, 0, 5 );
-
-
- bSizer172->Add( bSizer237, 0, wxEXPAND|wxALL, 5 );
-
m_hyperlink17 = new wxHyperlinkCtrl( m_panel35, wxID_ANY, _("How can I schedule a batch job?"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
bSizer172->Add( m_hyperlink17, 0, wxALL, 10 );
@@ -3811,8 +3817,6 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_checkBoxIgnoreErrors->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnToggleIgnoreErrors ), NULL, this );
m_radioBtnErrorDialogShow->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnErrorDialogShow ), NULL, this );
m_radioBtnErrorDialogCancel->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnErrorDialogCancel ), NULL, this );
- m_checkBoxSaveLog->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnToggleGenerateLogfile ), NULL, this );
- m_checkBoxLogfilesLimit->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnToggleLogfilesLimit ), NULL, this );
m_hyperlink17->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( BatchDlgGenerated::OnHelpScheduleBatch ), NULL, this );
m_buttonSaveAs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this );
@@ -4190,28 +4194,32 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
bSizer258 = new wxBoxSizer( wxHORIZONTAL );
m_bitmapLogFile = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer258->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ bSizer258->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_staticText163 = new wxStaticText( m_panel39, wxID_ANY, _("Default log path:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText163->Wrap( -1 );
+ bSizer258->Add( m_staticText163, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_hyperlinkLogFolder = new wxHyperlinkCtrl( m_panel39, wxID_ANY, _("dummy"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
bSizer258->Add( m_hyperlinkLogFolder, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
- bSizer259->Add( bSizer258, 0, wxEXPAND|wxALL, 5 );
+ bSizer259->Add( bSizer258, 0, wxALL|wxEXPAND, 5 );
- wxBoxSizer* bSizer260;
- bSizer260 = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* bSizer282;
+ bSizer282 = new wxBoxSizer( wxHORIZONTAL );
m_checkBoxLogFilesMaxAge = new wxCheckBox( m_panel39, wxID_ANY, _("Remove old log files after x days:"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer260->Add( m_checkBoxLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+ bSizer282->Add( m_checkBoxLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
m_spinCtrlLogFilesMaxAge = new wxSpinCtrl( m_panel39, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 );
- bSizer260->Add( m_spinCtrlLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer282->Add( m_spinCtrlLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL, 5 );
- bSizer259->Add( bSizer260, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+ bSizer259->Add( bSizer282, 0, wxALL, 5 );
- bSizer166->Add( bSizer259, 0, wxALL, 5 );
+ bSizer166->Add( bSizer259, 0, wxALL|wxEXPAND, 5 );
m_staticline361 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer166->Add( m_staticline361, 0, wxEXPAND, 5 );
diff --git a/FreeFileSync/Source/ui/gui_generated.h b/FreeFileSync/Source/ui/gui_generated.h
index 7f6b8843..757634e8 100755
--- a/FreeFileSync/Source/ui/gui_generated.h
+++ b/FreeFileSync/Source/ui/gui_generated.h
@@ -342,6 +342,16 @@ protected:
wxHyperlinkCtrl* m_hyperlink241;
wxStaticLine* m_staticline441;
wxStaticLine* m_staticline331;
+ wxBoxSizer* bSizerCompMisc;
+ wxStaticBitmap* m_bitmapIgnoreErrors;
+ wxCheckBox* m_checkBoxIgnoreErrors;
+ wxCheckBox* m_checkBoxAutoRetry;
+ wxFlexGridSizer* fgSizerAutoRetry;
+ wxStaticText* m_staticText96;
+ wxStaticText* m_staticTextAutoRetryDelay;
+ wxSpinCtrl* m_spinCtrlAutoRetryCount;
+ wxSpinCtrl* m_spinCtrlAutoRetryDelay;
+ wxStaticLine* m_staticline3311;
wxStaticLine* m_staticlinePerformance;
wxBoxSizer* bSizerPerformance;
wxStaticText* m_staticTextPerfDeRequired;
@@ -449,15 +459,11 @@ protected:
wxSpinCtrl* m_spinCtrlVersionCountMin;
wxSpinCtrl* m_spinCtrlVersionCountMax;
wxStaticLine* m_staticline582;
- wxBoxSizer* bSizerMiscConfig;
- wxStaticBitmap* m_bitmapIgnoreErrors;
- wxCheckBox* m_checkBoxIgnoreErrors;
- wxCheckBox* m_checkBoxAutoRetry;
- wxFlexGridSizer* fgSizerAutoRetry;
- wxStaticText* m_staticText96;
- wxStaticText* m_staticTextAutoRetryDelay;
- wxSpinCtrl* m_spinCtrlAutoRetryCount;
- wxSpinCtrl* m_spinCtrlAutoRetryDelay;
+ wxBoxSizer* bSizerSyncMisc;
+ wxPanel* m_panelLogfile;
+ wxStaticBitmap* m_bitmapLogFile;
+ wxCheckBox* m_checkBoxSaveLog;
+ wxButton* m_buttonSelectLogFolder;
wxStaticLine* m_staticline57;
wxStaticText* m_staticText89;
fff::CommandBox* m_comboBoxPostSyncCommand;
@@ -480,6 +486,8 @@ protected:
virtual void OnHelpComparisonSettings( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void onlTimeShiftKeyDown( wxKeyEvent& event ) { event.Skip(); }
virtual void OnHelpTimeShift( wxHyperlinkEvent& event ) { event.Skip(); }
+ virtual void OnToggleIgnoreErrors( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToggleAutoRetry( wxCommandEvent& event ) { event.Skip(); }
virtual void OnHelpPerformance( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnChangeFilterOption( wxCommandEvent& event ) { event.Skip(); }
virtual void OnHelpShowExamples( wxHyperlinkEvent& event ) { event.Skip(); }
@@ -507,16 +515,17 @@ protected:
virtual void OnHelpVersioning( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnChanegVersioningStyle( wxCommandEvent& event ) { event.Skip(); }
virtual void OnToggleVersioningLimit( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnToggleIgnoreErrors( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnToggleAutoRetry( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToggleSaveLogfile( wxCommandEvent& event ) { event.Skip(); }
virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
public:
- wxStaticText* m_staticTextFilterDescr;
- wxBitmapButton* m_bpButtonSelectAltFolder;
wxStaticBitmap* m_bitmapRetryErrors;
+ wxStaticText* m_staticTextFilterDescr;
+ wxBitmapButton* m_bpButtonSelectVersioningAltFolder;
+ wxBitmapButton* m_bpButtonSelectAltLogFolder;
+ fff::FolderHistoryBox* m_logFolderPath;
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 );
@@ -841,12 +850,6 @@ protected:
wxStaticText* m_staticText137;
wxStaticLine* m_staticline262;
wxStaticLine* m_staticline25;
- wxStaticBitmap* m_bitmapLogFile;
- wxCheckBox* m_checkBoxSaveLog;
- wxCheckBox* m_checkBoxLogfilesLimit;
- wxSpinCtrl* m_spinCtrlLogfileLimit;
- wxPanel* m_panelLogfile;
- wxButton* m_buttonSelectLogFolder;
wxHyperlinkCtrl* m_hyperlink17;
wxStaticLine* m_staticline13;
wxBoxSizer* bSizerStdButtons;
@@ -859,8 +862,6 @@ protected:
virtual void OnToggleIgnoreErrors( wxCommandEvent& event ) { event.Skip(); }
virtual void OnErrorDialogShow( wxCommandEvent& event ) { event.Skip(); }
virtual void OnErrorDialogCancel( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnToggleGenerateLogfile( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnToggleLogfilesLimit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnHelpScheduleBatch( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnSaveBatchJob( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
@@ -869,8 +870,6 @@ protected:
public:
wxCheckBox* m_checkBoxAutoClose;
wxChoice* m_choicePostSyncAction;
- fff::FolderHistoryBox* m_logFolderPath;
- wxBitmapButton* m_bpButtonSelectAltLogFolder;
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();
@@ -979,6 +978,7 @@ protected:
zen::BitmapTextButton* m_buttonResetDialogs;
wxStaticLine* m_staticline191;
wxStaticBitmap* m_bitmapLogFile;
+ wxStaticText* m_staticText163;
wxHyperlinkCtrl* m_hyperlinkLogFolder;
wxCheckBox* m_checkBoxLogFilesMaxAge;
wxSpinCtrl* m_spinCtrlLogFilesMaxAge;
diff --git a/FreeFileSync/Source/ui/gui_status_handler.cpp b/FreeFileSync/Source/ui/gui_status_handler.cpp
index 5abf3931..53391ea3 100755
--- a/FreeFileSync/Source/ui/gui_status_handler.cpp
+++ b/FreeFileSync/Source/ui/gui_status_handler.cpp
@@ -25,7 +25,7 @@ StatusHandlerTemporaryPanel::StatusHandlerTemporaryPanel(MainDialog& dlg,
const std::chrono::system_clock::time_point& startTime,
bool ignoreErrors,
size_t automaticRetryCount,
- size_t automaticRetryDelay) :
+ std::chrono::seconds automaticRetryDelay) :
mainDlg_(dlg),
automaticRetryCount_(automaticRetryCount),
automaticRetryDelay_(automaticRetryDelay),
@@ -314,7 +314,7 @@ StatusHandlerFloatingDialog::StatusHandlerFloatingDialog(wxFrame* parentDlg,
const std::chrono::system_clock::time_point& startTime,
bool ignoreErrors,
size_t automaticRetryCount,
- size_t automaticRetryDelay,
+ std::chrono::seconds automaticRetryDelay,
const std::wstring& jobName,
const Zstring& soundFileSyncComplete,
const Zstring& postSyncCommand,
@@ -338,7 +338,7 @@ StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
}
-StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportFinalStatus(int logfilesMaxAgeDays, const std::set<Zstring, LessFilePath>& logFilePathsToKeep)
+StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportFinalStatus(const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep)
{
const auto totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime_);
@@ -402,12 +402,12 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportFinalStat
errorLog_.logMsg(replaceCpy(_("Executing command %x"), L"%x", fmtPath(commandLine)), MSG_TYPE_INFO);
//----------------- always save log under %appdata%\FreeFileSync\Logs ------------------------
- Zstring logFilePath;
+ AbstractPath logFilePath = getNullPath();
try
{
//do NOT use tryReportingError()! saving log files should not be cancellable!
auto notifyStatusNoThrow = [&](const std::wstring& msg) { try { reportStatus(msg); /*throw X*/ } catch (...) {} };
- logFilePath = saveLogFile(summary, errorLog_, startTime_, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatusNoThrow /*throw (X)*/); //throw FileError
+ logFilePath = saveLogFile(summary, errorLog_, startTime_, altLogFolderPathPhrase, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatusNoThrow /*throw (X)*/); //throw FileError
}
catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
@@ -416,7 +416,7 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportFinalStat
try
{
//----------------------------------------------------------------------
- ::wxSetEnv(L"logfile_path", utfTo<wxString>(logFilePath));
+ ::wxSetEnv(L"logfile_path", AFS::getDisplayPath(logFilePath));
//----------------------------------------------------------------------
//use ExecutionType::ASYNC until there is reason not to: https://freefilesync.org/forum/viewtopic.php?t=31
shellExecute(expandMacros(commandLine), ExecutionType::ASYNC); //throw FileError
@@ -440,7 +440,7 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportFinalStat
if (progressDlg_->getWindowIfVisible())
try
{
- delayAndCountDown(operationName, 5 /*delayInSec*/, notifyStatusThrowOnCancel); //throw X
+ delayAndCountDown(operationName, std::chrono::seconds(5), notifyStatusThrowOnCancel); //throw X
}
catch (...) { return false; }
diff --git a/FreeFileSync/Source/ui/gui_status_handler.h b/FreeFileSync/Source/ui/gui_status_handler.h
index 73942f0d..768d4d2e 100755
--- a/FreeFileSync/Source/ui/gui_status_handler.h
+++ b/FreeFileSync/Source/ui/gui_status_handler.h
@@ -22,7 +22,7 @@ namespace fff
class StatusHandlerTemporaryPanel : private wxEvtHandler, public StatusHandler
{
public:
- StatusHandlerTemporaryPanel(MainDialog& dlg, const std::chrono::system_clock::time_point& startTime, bool ignoreErrors, size_t automaticRetryCount, size_t automaticRetryDelay);
+ StatusHandlerTemporaryPanel(MainDialog& dlg, const std::chrono::system_clock::time_point& startTime, bool ignoreErrors, size_t automaticRetryCount, std::chrono::seconds automaticRetryDelay);
~StatusHandlerTemporaryPanel();
void initNewPhase (int itemsTotal, int64_t bytesTotal, Phase phaseID) override; //
@@ -47,7 +47,7 @@ private:
MainDialog& mainDlg_;
zen::ErrorLog errorLog_;
const size_t automaticRetryCount_;
- const size_t automaticRetryDelay_;
+ const std::chrono::seconds automaticRetryDelay_;
const std::chrono::system_clock::time_point startTime_;
};
@@ -60,7 +60,7 @@ public:
const std::chrono::system_clock::time_point& startTime,
bool ignoreErrors,
size_t automaticRetryCount,
- size_t automaticRetryDelay,
+ std::chrono::seconds automaticRetryDelay,
const std::wstring& jobName,
const Zstring& soundFileSyncComplete,
const Zstring& postSyncCommand,
@@ -82,9 +82,9 @@ public:
ProcessSummary summary;
std::shared_ptr<const zen::ErrorLog> errorLog;
bool exitAfterSync;
- Zstring logFilePath;
+ AbstractPath logFilePath;
};
- Result reportFinalStatus(int logfilesMaxAgeDays, const std::set<Zstring, LessFilePath>& logFilePathsToKeep); //noexcept!!
+ Result reportFinalStatus(const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep); //noexcept!!
private:
void onProgressDialogTerminate();
@@ -92,7 +92,7 @@ private:
SyncProgressDialog* progressDlg_; //managed to have shorter lifetime than this handler!
zen::ErrorLog errorLog_;
const size_t automaticRetryCount_;
- const size_t automaticRetryDelay_;
+ const std::chrono::seconds automaticRetryDelay_;
const std::wstring jobName_;
const std::chrono::system_clock::time_point startTime_;
const Zstring postSyncCommand_;
diff --git a/FreeFileSync/Source/ui/log_panel.cpp b/FreeFileSync/Source/ui/log_panel.cpp
index 545bc594..7f84a9ed 100755
--- a/FreeFileSync/Source/ui/log_panel.cpp
+++ b/FreeFileSync/Source/ui/log_panel.cpp
@@ -65,7 +65,7 @@ public:
bool firstLine = false; //if LogEntry::message spans multiple rows
};
- Opt<LogEntryView> getEntry(size_t row) const
+ std::optional<LogEntryView> getEntry(size_t row) const
{
if (row < viewRef_.size())
{
@@ -78,7 +78,7 @@ public:
output.firstLine = line.rowNumber_ == 0; //this is virtually always correct, unless first line of the original message is empty!
return output;
}
- return NoValue();
+ return {};
}
void updateView(int includedTypes) //MSG_TYPE_INFO | MSG_TYPE_WARNING, ect. see error_log.h
@@ -160,7 +160,7 @@ public:
std::wstring getValue(size_t row, ColumnType colType) const override
{
- if (Opt<MessageView::LogEntryView> entry = msgView_.getEntry(row))
+ if (std::optional<MessageView::LogEntryView> entry = msgView_.getEntry(row))
switch (static_cast<ColumnTypeMsg>(colType))
{
case ColumnTypeMsg::TIME:
@@ -198,7 +198,7 @@ public:
wxDCPenChanger dummy2(dc, getColorGridLine());
const bool drawBottomLine = [&] //don't separate multi-line messages
{
- if (Opt<MessageView::LogEntryView> nextEntry = msgView_.getEntry(row + 1))
+ if (std::optional<MessageView::LogEntryView> nextEntry = msgView_.getEntry(row + 1))
return nextEntry->firstLine;
return true;
}();
@@ -211,7 +211,7 @@ public:
}
//--------------------------------------------------------
- if (Opt<MessageView::LogEntryView> entry = msgView_.getEntry(row))
+ if (std::optional<MessageView::LogEntryView> entry = msgView_.getEntry(row))
switch (static_cast<ColumnTypeMsg>(colType))
{
case ColumnTypeMsg::TIME:
diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp
index 5a78c05e..5d608955 100755
--- a/FreeFileSync/Source/ui/main_dlg.cpp
+++ b/FreeFileSync/Source/ui/main_dlg.cpp
@@ -23,8 +23,8 @@
#include <wx+/no_flicker.h>
#include <wx+/rtl.h>
#include <wx+/font_size.h>
-#include <wx+/focus.h>
#include <wx+/popup_dlg.h>
+#include <wx+/focus.h>
#include <wx+/image_resources.h>
#include "cfg_grid.h"
#include "version_check.h"
@@ -287,12 +287,12 @@ void MainDialog::create(const Zstring& globalConfigFilePath)
GetFirstResult<std::false_type> firstUnavailableFile;
for (const Zstring& filePath : cfgFilePaths)
- firstUnavailableFile.addJob([filePath]() -> Opt<std::false_type>
+ firstUnavailableFile.addJob([filePath]() -> std::optional<std::false_type>
{
assert(!filePath.empty());
if (!fileAvailable(filePath))
return std::false_type();
- return NoValue();
+ return {};
});
//potentially slow network access: give all checks 500ms to finish
@@ -401,7 +401,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
m_bpButtonAddPair ->SetBitmapLabel(getResourceImage(L"item_add"));
m_bpButtonHideSearch ->SetBitmapLabel(getResourceImage(L"close_panel"));
- m_bpButtonShowLog ->SetBitmapLabel(getResourceImage(L"log_file_small"));
+ m_bpButtonShowLog ->SetBitmapLabel(getResourceImage(L"log_file"));
m_textCtrlSearchTxt->SetMinSize(wxSize(fastFromDIP(220), -1));
@@ -763,12 +763,12 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
//check existence of all directories in parallel!
GetFirstResult<std::false_type> firstMissingDir;
for (const AbstractPath& folderPath : folderPathsToCheck)
- firstMissingDir.addJob([folderPath]() -> Opt<std::false_type>
+ firstMissingDir.addJob([folderPath]() -> std::optional<std::false_type>
{
try
{
if (AFS::getItemType(folderPath) != AFS::ItemType::FILE) //throw FileError
- return NoValue();
+ return {};
}
catch (FileError&) {}
return std::false_type();
@@ -791,7 +791,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
MainDialog::~MainDialog()
{
- Opt<FileError> firstError;
+ std::optional<FileError> firstError;
try //save "GlobalSettings.xml"
{
writeConfig(getGlobalCfgBeforeExit(), globalConfigFilePath_); //throw FileError
@@ -1095,17 +1095,15 @@ void MainDialog::copySelectionToClipboard(const std::vector<const Grid*>& gridRe
//perf: wxString doesn't model exponential growth and is unsuitable for large data sets
Zstringw clipboardString;
- auto addSelection = [&](const Grid& grid)
- {
- if (auto prov = grid.getDataProvider())
+ for (const Grid* grid : gridRefs)
+ if (auto prov = grid->getDataProvider())
{
- std::vector<Grid::ColAttributes> colAttr = grid.getColumnConfig();
+ std::vector<Grid::ColAttributes> colAttr = grid->getColumnConfig();
erase_if(colAttr, [](const Grid::ColAttributes& ca) { return !ca.visible; });
if (!colAttr.empty())
- for (size_t row : grid.getSelectedRows())
+ for (size_t row : grid->getSelectedRows())
{
- std::for_each(colAttr.begin(), colAttr.end() - 1,
- [&](const Grid::ColAttributes& ca)
+ std::for_each(colAttr.begin(), colAttr.end() - 1, [&](const Grid::ColAttributes& ca)
{
clipboardString += copyStringTo<Zstringw>(prov->getValue(row, ca.type));
clipboardString += L'\t';
@@ -1114,12 +1112,7 @@ void MainDialog::copySelectionToClipboard(const std::vector<const Grid*>& gridRe
clipboardString += L'\n';
}
}
- };
- for (const Grid* gr : gridRefs)
- addSelection(*gr);
-
- //finally write to clipboard
if (wxClipboard::Get()->Open())
{
ZEN_ON_SCOPE_EXIT(wxClipboard::Get()->Close());
@@ -1160,18 +1153,12 @@ std::vector<FileSystemObject*> MainDialog::getTreeSelection() const
if (auto root = dynamic_cast<const TreeView::RootNode*>(node.get()))
{
//selecting root means "select everything", *ignoring* current view filter!
- BaseFolderPair& baseDir = root->baseFolder;
-
- std::vector<FileSystemObject*> dirsFilesAndLinks;
-
- for (FileSystemObject& fsObj : baseDir.refSubFolders()) //no need to explicitly add child elements!
- dirsFilesAndLinks.push_back(&fsObj);
- for (FileSystemObject& fsObj : baseDir.refSubFiles())
- dirsFilesAndLinks.push_back(&fsObj);
- for (FileSystemObject& fsObj : baseDir.refSubLinks())
- dirsFilesAndLinks.push_back(&fsObj);
-
- append(output, dirsFilesAndLinks);
+ for (FileSystemObject& fsObj : root->baseFolder.refSubFolders()) //no need to explicitly add child elements!
+ output.push_back(&fsObj);
+ for (FileSystemObject& fsObj : root->baseFolder.refSubFiles())
+ output.push_back(&fsObj);
+ for (FileSystemObject& fsObj : root->baseFolder.refSubLinks())
+ output.push_back(&fsObj);
}
else if (auto dir = dynamic_cast<const TreeView::DirNode*>(node.get()))
output.push_back(&(dir->folder));
@@ -1200,7 +1187,7 @@ void MainDialog::copyToAlternateFolder(const std::vector<FileSystemObject*>& sel
rowsLeftTmp, rowsRightTmp,
globalCfg_.gui.mainDlg.copyToCfg.lastUsedPath,
globalCfg_.gui.mainDlg.copyToCfg.folderHistory,
- globalCfg_.gui.mainDlg.copyToCfg.historySizeMax,
+ globalCfg_.gui.mainDlg.folderHistItemsMax,
globalCfg_.gui.mainDlg.copyToCfg.keepRelPaths,
globalCfg_.gui.mainDlg.copyToCfg.overwriteIfExists) != ReturnSmallDlg::BUTTON_OKAY)
return;
@@ -3370,6 +3357,7 @@ void MainDialog::showConfigDialog(SyncConfigPanel panelToShow, int localPairInde
globalPairCfg.miscCfg.ignoreErrors = currentCfg_.mainCfg.ignoreErrors;
globalPairCfg.miscCfg.automaticRetryCount = currentCfg_.mainCfg.automaticRetryCount;
globalPairCfg.miscCfg.automaticRetryDelay = currentCfg_.mainCfg.automaticRetryDelay;
+ globalPairCfg.miscCfg.altLogFolderPathPhrase = currentCfg_.mainCfg.altLogFolderPathPhrase;
globalPairCfg.miscCfg.postSyncCommand = currentCfg_.mainCfg.postSyncCommand;
globalPairCfg.miscCfg.postSyncCondition = currentCfg_.mainCfg.postSyncCondition;
globalPairCfg.miscCfg.commandHistory = globalCfg_.gui.commandHistory;
@@ -3412,6 +3400,7 @@ void MainDialog::showConfigDialog(SyncConfigPanel panelToShow, int localPairInde
currentCfg_.mainCfg.ignoreErrors = globalPairCfg.miscCfg.ignoreErrors;
currentCfg_.mainCfg.automaticRetryCount = globalPairCfg.miscCfg.automaticRetryCount;
currentCfg_.mainCfg.automaticRetryDelay = globalPairCfg.miscCfg.automaticRetryDelay;
+ currentCfg_.mainCfg.altLogFolderPathPhrase = globalPairCfg.miscCfg.altLogFolderPathPhrase;
currentCfg_.mainCfg.postSyncCommand = globalPairCfg.miscCfg.postSyncCommand;
currentCfg_.mainCfg.postSyncCondition = globalPairCfg.miscCfg.postSyncCondition;
globalCfg_.gui.commandHistory = globalPairCfg.miscCfg.commandHistory;
@@ -3451,6 +3440,7 @@ void MainDialog::showConfigDialog(SyncConfigPanel panelToShow, int localPairInde
globalPairCfg.miscCfg.ignoreErrors != globalPairCfgOld.miscCfg.ignoreErrors ||
globalPairCfg.miscCfg.automaticRetryCount != globalPairCfgOld.miscCfg.automaticRetryCount ||
globalPairCfg.miscCfg.automaticRetryDelay != globalPairCfgOld.miscCfg.automaticRetryDelay ||
+ globalPairCfg.miscCfg.altLogFolderPathPhrase != globalPairCfgOld.miscCfg.altLogFolderPathPhrase ||
globalPairCfg.miscCfg.postSyncCommand != globalPairCfgOld.miscCfg.postSyncCommand ||
globalPairCfg.miscCfg.postSyncCondition != globalPairCfgOld.miscCfg.postSyncCondition;
/**/ //globalPairCfg.miscCfg.commandHistory != globalPairCfgOld.miscCfg.commandHistory;
@@ -3744,7 +3734,8 @@ void MainDialog::OnCompare(wxCommandEvent& event)
folderHistoryLeft_ ->addItem(utfTo<Zstring>(m_folderPathLeft ->GetValue()));
folderHistoryRight_->addItem(utfTo<Zstring>(m_folderPathRight->GetValue()));
- if (fp.getFocus() == m_buttonCompare)
+ assert(m_buttonCompare->GetId() != wxID_ANY);
+ if (fp.getFocusId() == m_buttonCompare->GetId())
fp.setFocus(m_buttonSync);
//prepare status information
@@ -3754,7 +3745,7 @@ void MainDialog::OnCompare(wxCommandEvent& event)
//update last sync date for selected cfg files https://freefilesync.org/forum/viewtopic.php?t=4991
if (r.summary.finalStatus == SyncResult::FINISHED_WITH_SUCCESS)
- updateConfigLastRunStats(std::chrono::system_clock::to_time_t(startTime), r.summary.finalStatus, Zstring() /*logFilePath*/);
+ updateConfigLastRunStats(std::chrono::system_clock::to_time_t(startTime), r.summary.finalStatus, getNullPath() /*logFilePath*/);
}
}
@@ -3880,8 +3871,8 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
}
const std::map<AbstractPath, size_t>& deviceParallelOps = guiCfg.mainCfg.deviceParallelOps;
-
- std::set<Zstring, LessFilePath> logFilePathsToKeep;
+
+ std::set<AbstractPath> logFilePathsToKeep;
for (const ConfigFileItem& item : cfggrid::getDataView(*m_gridCfgHistory).get())
logFilePathsToKeep.insert(item.logFilePath);
@@ -3923,11 +3914,11 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
for (auto it = begin(folderCmp_); it != end(folderCmp_); ++it)
{
if (it->isAvailable<LEFT_SIDE>()) //do NOT check directory existence again!
- if (Opt<Zstring> nativeFolderPath = AFS::getNativeItemPath(it->getAbstractPath<LEFT_SIDE>())) //restrict directory locking to native paths until further
+ if (std::optional<Zstring> nativeFolderPath = AFS::getNativeItemPath(it->getAbstractPath<LEFT_SIDE>())) //restrict directory locking to native paths until further
availableDirPaths.insert(*nativeFolderPath);
if (it->isAvailable<RIGHT_SIDE>())
- if (Opt<Zstring> nativeFolderPath = AFS::getNativeItemPath(it->getAbstractPath<RIGHT_SIDE>()))
+ if (std::optional<Zstring> nativeFolderPath = AFS::getNativeItemPath(it->getAbstractPath<RIGHT_SIDE>()))
availableDirPaths.insert(*nativeFolderPath);
}
dirLocks = std::make_unique<LockHolder>(availableDirPaths, globalCfg_.warnDlgs.warnDirectoryLockFailed, statusHandler); //throw AbortProcess
@@ -3949,7 +3940,7 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
}
catch (AbortProcess&) {}
- StatusHandlerFloatingDialog::Result r = statusHandler.reportFinalStatus(globalCfg_.logfilesMaxAgeDays, logFilePathsToKeep); //noexcept
+ StatusHandlerFloatingDialog::Result r = statusHandler.reportFinalStatus(guiCfg.mainCfg.altLogFolderPathPhrase, globalCfg_.logfilesMaxAgeDays, logFilePathsToKeep); //noexcept
//---------------------------------------------------------------------------
setLastOperationLog(r.summary, r.errorLog);
@@ -3970,7 +3961,7 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
}
-void MainDialog::updateConfigLastRunStats(time_t lastRunTime, SyncResult result, const Zstring& logFilePath)
+void MainDialog::updateConfigLastRunStats(time_t lastRunTime, SyncResult result, const AbstractPath& logFilePath)
{
cfggrid::getDataView(*m_gridCfgHistory).setLastRunStats(activeConfigFiles_, { lastRunTime, result, logFilePath });
@@ -4040,7 +4031,7 @@ void MainDialog::setLastOperationLog(const ProcessSummary& summary, const std::s
logPanel_->setLog(errorLog);
m_panelLog->Layout();
- setImage(*m_bpButtonShowLog, layOver(getResourceImage(L"log_file_small"), statusOverlayImage, wxALIGN_BOTTOM | wxALIGN_RIGHT));
+ setImage(*m_bpButtonShowLog, layOver(getResourceImage(L"log_file"), statusOverlayImage, wxALIGN_BOTTOM | wxALIGN_RIGHT));
m_bpButtonShowLog->Show(static_cast<bool>(errorLog));
}
@@ -4243,7 +4234,7 @@ void MainDialog::updateGridViewData()
if (m_bpButtonViewTypeSyncAction->isActive())
{
- const FileView::StatusSyncPreview result = filegrid::getDataView(*m_gridMainC).updateSyncPreview(m_bpButtonShowExcluded ->isActive(),
+ const FileView::StatusSyncPreview result = filegrid::getDataView(*m_gridMainC).updateSyncPreview(m_bpButtonShowExcluded->isActive(),
m_bpButtonShowCreateLeft ->isActive(),
m_bpButtonShowCreateRight->isActive(),
m_bpButtonShowDeleteLeft ->isActive(),
@@ -4281,7 +4272,7 @@ void MainDialog::updateGridViewData()
}
else
{
- const FileView::StatusCmpResult result = filegrid::getDataView(*m_gridMainC).updateCmpResult(m_bpButtonShowExcluded ->isActive(),
+ const FileView::StatusCmpResult result = filegrid::getDataView(*m_gridMainC).updateCmpResult(m_bpButtonShowExcluded->isActive(),
m_bpButtonShowLeftOnly ->isActive(),
m_bpButtonShowRightOnly ->isActive(),
m_bpButtonShowLeftNewer ->isActive(),
@@ -4441,10 +4432,11 @@ void MainDialog::showFindPanel() //CTRL + F or F3 with empty search phrase
m_textCtrlSearchTxt->SelectAll();
- wxWindow* focus = wxWindow::FindFocus(); //restore when closing panel!
- if (!isComponentOf(focus, m_panelSearch))
- focusWindowAfterSearch_ = focus == &m_gridMainR->getMainWin() ? focus : &m_gridMainL->getMainWin();
- //don't save pointer to arbitrary window: it might not exist anymore when hideFindPanel() uses it!!! (e.g. some folder pair panel)
+ if (wxWindow* focus = wxWindow::FindFocus()) //restore when closing panel!
+ if (!isComponentOf(focus, m_panelSearch))
+ focusIdAfterSearch_ = focus->GetId();
+ //don't save wxWindow* to arbitrary window: it might not exist anymore when hideFindPanel() uses it!!! (e.g. some folder pair panel)
+
m_textCtrlSearchTxt->SetFocus();
}
@@ -4454,11 +4446,9 @@ void MainDialog::hideFindPanel()
auiMgr_.GetPane(m_panelSearch).Hide();
auiMgr_.Update();
- if (focusWindowAfterSearch_)
- {
- focusWindowAfterSearch_->SetFocus();
- focusWindowAfterSearch_ = nullptr;
- }
+ if (wxWindow* oldFocusWin = wxWindow::FindWindowById(focusIdAfterSearch_))
+ oldFocusWin->SetFocus();
+ focusIdAfterSearch_ = wxID_ANY;
}
@@ -4475,7 +4465,7 @@ void MainDialog::startFindNext(bool searchAscending) //F3 or ENTER in m_textCtrl
Grid* grid2 = m_gridMainR;
wxWindow* focus = wxWindow::FindFocus();
- if ((isComponentOf(focus, m_panelSearch) ? focusWindowAfterSearch_ : focus) == &m_gridMainR->getMainWin())
+ if ((isComponentOf(focus, m_panelSearch) ? focusIdAfterSearch_ : focus->GetId()) == m_gridMainR->getMainWin().GetId())
std::swap(grid1, grid2); //select side to start search at grid cursor position
wxBeginBusyCursor(wxHOURGLASS_CURSOR);
@@ -4490,7 +4480,7 @@ void MainDialog::startFindNext(bool searchAscending) //F3 or ENTER in m_textCtrl
filegrid::setScrollMaster(*grid);
grid->setGridCursor(result.second, GridEventPolicy::ALLOW);
- focusWindowAfterSearch_ = &grid->getMainWin();
+ focusIdAfterSearch_ = grid->getMainWin().GetId();
if (!isComponentOf(wxWindow::FindFocus(), m_panelSearch))
grid->getMainWin().SetFocus();
@@ -4724,9 +4714,10 @@ void MainDialog::recalcMaxFolderPairsVisible()
m_panelDirectoryPairs->ClientToWindowSize(m_panelTopCenter->GetSize()).y); //
const int addPairHeight = !additionalFolderPairs_.empty() ? additionalFolderPairs_[0]->GetSize().y :
m_bpButtonAddPair->GetSize().y; //an educated guess
- assert(addPairHeight > 0);
- if (addPairCountLast_ && addPairHeight > 0)
+ //assert(firstPairHeight > 0 && addPairHeight > 0); -> wxWindows::GetSize() returns 0 if main window is minimized during sync! Test with "When finished: Exit"
+
+ if (addPairCountLast_ && firstPairHeight > 0 && addPairHeight > 0)
{
const double addPairCountCurrent = (m_panelDirectoryPairs->GetSize().y - firstPairHeight) / (1.0 * addPairHeight); //include m_panelDirectoryPairs window borders!
diff --git a/FreeFileSync/Source/ui/main_dlg.h b/FreeFileSync/Source/ui/main_dlg.h
index a91a100c..70a5fdb7 100755
--- a/FreeFileSync/Source/ui/main_dlg.h
+++ b/FreeFileSync/Source/ui/main_dlg.h
@@ -226,7 +226,7 @@ private:
void showConfigDialog(SyncConfigPanel panelToShow, int localPairIndexToShow);
- void updateConfigLastRunStats(time_t lastRunTime, SyncResult result, const Zstring& logFilePath);
+ void updateConfigLastRunStats(time_t lastRunTime, SyncResult result, const AbstractPath& logFilePath);
void setLastOperationLog(const ProcessSummary& summary, const std::shared_ptr<const zen::ErrorLog>& errorLog);
void showLogPanel(bool show);
@@ -312,7 +312,7 @@ private:
std::unique_ptr<FolderPairFirst> firstFolderPair_; //always bound!!!
std::vector<FolderPairPanel*> additionalFolderPairs_; //additional pairs to the first pair
- zen::Opt<double> addPairCountLast_;
+ std::optional<double> addPairCountLast_;
//-------------------------------------
//***********************************************
@@ -343,7 +343,7 @@ private:
std::unique_ptr<FilterConfig> filterCfgOnClipboard_; //copy/paste of filter config
- wxWindow* focusWindowAfterSearch_ = nullptr; //used to restore focus after search panel is closed
+ wxWindowID focusIdAfterSearch_ = wxID_ANY; //used to restore focus after search panel is closed
bool localKeyEventsEnabled_ = true;
bool allowMainDialogClose_ = true; //e.g. do NOT allow close while sync is running => crash!!!
diff --git a/FreeFileSync/Source/ui/progress_indicator.cpp b/FreeFileSync/Source/ui/progress_indicator.cpp
index 7f9850b7..6737996c 100755
--- a/FreeFileSync/Source/ui/progress_indicator.cpp
+++ b/FreeFileSync/Source/ui/progress_indicator.cpp
@@ -9,28 +9,20 @@
#include <wx/imaglist.h>
#include <wx/wupdlock.h>
#include <wx/sound.h>
-//#include <wx/dcclient.h>
-//#include <wx/dataobj.h> //wxTextDataObject
#include <wx/app.h>
#include <zen/basic_math.h>
#include <zen/format_unit.h>
#include <zen/scope_guard.h>
-//#include <wx+/grid.h>
#include <wx+/toggle_button.h>
#include <wx+/image_tools.h>
#include <wx+/graph.h>
-//#include <wx+/context_menu.h>
#include <wx+/no_flicker.h>
#include <wx+/font_size.h>
#include <wx+/std_button_layout.h>
-//#include <wx+/popup_dlg.h>
-//#include <wx+/image_resources.h>
#include <zen/file_access.h>
#include <zen/thread.h>
#include <zen/perf.h>
-//#include <wx+/rtl.h>
#include <wx+/choice_enum.h>
-//#include <wx+/focus.h>
#include "gui_generated.h"
#include "../base/ffs_paths.h"
#include "../base/perf_check.h"
@@ -384,14 +376,14 @@ void CompareProgressDialog::Impl::updateProgressGui()
perf_.addSample(timeElapsed, itemsCurrent, bytesCurrent);
//current speed -> Win 7 copy uses 1 sec update interval instead
- Opt<std::wstring> bps = perf_.getBytesPerSecond();
- Opt<std::wstring> ips = perf_.getItemsPerSecond();
+ std::optional<std::wstring> bps = perf_.getBytesPerSecond();
+ std::optional<std::wstring> ips = perf_.getItemsPerSecond();
m_panelProgressGraph->setAttributes(m_panelProgressGraph->getAttributes().setCornerText(bps ? *bps : L"", Graph2D::CORNER_TOP_LEFT));
m_panelProgressGraph->setAttributes(m_panelProgressGraph->getAttributes().setCornerText(ips ? *ips : L"", Graph2D::CORNER_BOTTOM_LEFT));
//remaining time: display with relative error of 10% - based on samples taken every 0.5 sec only
//-> call more often than once per second to correctly show last few seconds countdown, but don't call too often to avoid occasional jitter
- Opt<double> remTimeSec = perf_.getRemainingTimeSec(bytesTotal - bytesCurrent);
+ std::optional<double> remTimeSec = perf_.getRemainingTimeSec(bytesTotal - bytesCurrent);
setText(*m_staticTextTimeRemaining, remTimeSec ? formatRemainingTime(*remTimeSec) : L"-", &layoutChanged);
}
@@ -480,7 +472,7 @@ private:
std::chrono::duration<double>(upperEnd).count() };
}
- Opt<CurvePoint> getLessEq(double x) const override //x: seconds since begin
+ std::optional<CurvePoint> getLessEq(double x) const override //x: seconds since begin
{
const auto timeX = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double>(x)); //round down
@@ -493,13 +485,13 @@ private:
//find first key > x, then go one step back: => samples must be a std::map, NOT std::multimap!!!
auto it = samples_.upper_bound(timeX);
if (it == samples_.begin())
- return NoValue();
+ return {};
//=> samples not empty in this context
--it;
return CurvePoint(std::chrono::duration<double>(it->first).count(), it->second);
}
- Opt<CurvePoint> getGreaterEq(double x) const override
+ std::optional<CurvePoint> getGreaterEq(double x) const override
{
const std::chrono::nanoseconds timeX(static_cast<std::chrono::nanoseconds::rep>(std::ceil(x * (1000 * 1000 * 1000)))); //round up!
@@ -511,7 +503,7 @@ private:
auto it = samples_.lower_bound(timeX);
if (it == samples_.end())
- return NoValue();
+ return {};
return CurvePoint(std::chrono::duration<double>(it->first).count(), it->second);
}
@@ -1134,8 +1126,8 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
perf_.addSample(timeElapsed, itemsCurrent, bytesCurrent);
//current speed -> Win 7 copy uses 1 sec update interval instead
- Opt<std::wstring> bps = perf_.getBytesPerSecond();
- Opt<std::wstring> ips = perf_.getItemsPerSecond();
+ std::optional<std::wstring> bps = perf_.getBytesPerSecond();
+ std::optional<std::wstring> ips = perf_.getItemsPerSecond();
pnl_.m_panelGraphBytes->setAttributes(pnl_.m_panelGraphBytes->getAttributes().setCornerText(bps ? *bps : L"", Graph2D::CORNER_TOP_LEFT));
pnl_.m_panelGraphItems->setAttributes(pnl_.m_panelGraphItems->getAttributes().setCornerText(ips ? *ips : L"", Graph2D::CORNER_TOP_LEFT));
@@ -1149,7 +1141,7 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
{
//remaining time: display with relative error of 10% - based on samples taken every 0.5 sec only
//-> call more often than once per second to correctly show last few seconds countdown, but don't call too often to avoid occasional jitter
- Opt<double> remTimeSec = perf_.getRemainingTimeSec(bytesTotal - bytesCurrent);
+ std::optional<double> remTimeSec = perf_.getRemainingTimeSec(bytesTotal - bytesCurrent);
setText(*pnl_.m_staticTextTimeRemaining, remTimeSec ? formatRemainingTime(*remTimeSec) : L"-", &layoutChanged);
//update estimated total time marker with precision of "10% remaining time" only to avoid needless jumping around:
diff --git a/FreeFileSync/Source/ui/small_dlgs.cpp b/FreeFileSync/Source/ui/small_dlgs.cpp
index 630429c0..08eefc02 100755
--- a/FreeFileSync/Source/ui/small_dlgs.cpp
+++ b/FreeFileSync/Source/ui/small_dlgs.cpp
@@ -584,7 +584,7 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
//setMainInstructionFont(*m_staticTextHeader);
m_gridCustomCommand->SetTabBehaviour(wxGrid::Tab_Leave);
- m_bitmapLogFile->SetBitmap(getResourceImage(L"log_file_small"));
+ m_bitmapLogFile->SetBitmap(getResourceImage(L"log_file_sicon"));
m_spinCtrlLogFilesMaxAge->SetMinSize(wxSize(fastFromDIP(70), -1)); //Hack: set size (why does wxWindow::Size() not work?)
m_hyperlinkLogFolder->SetLabel(utfTo<wxString>(getDefaultLogFolderPath()));
setRelativeFontSize(*m_hyperlinkLogFolder, 1.2);
@@ -686,6 +686,10 @@ void OptionsDlg::OnDefault(wxCommandEvent& event)
m_checkBoxCopyPermissions->SetValue(defaultCfg_.copyFilePermissions);
setExtApp(defaultCfg_.gui.externalApps);
+
+ m_checkBoxLogFilesMaxAge->SetValue(defaultCfg_.logfilesMaxAgeDays > 0);
+ m_spinCtrlLogFilesMaxAge->SetValue(defaultCfg_.logfilesMaxAgeDays > 0 ? defaultCfg_.logfilesMaxAgeDays : 14);
+
updateGui();
}
diff --git a/FreeFileSync/Source/ui/sync_cfg.cpp b/FreeFileSync/Source/ui/sync_cfg.cpp
index 84750453..f5bb6399 100755
--- a/FreeFileSync/Source/ui/sync_cfg.cpp
+++ b/FreeFileSync/Source/ui/sync_cfg.cpp
@@ -22,6 +22,7 @@
#include "../base/file_hierarchy.h"
#include "../base/help_provider.h"
#include "../base/norm_filter.h"
+#include "../base/generate_logfile.h"
#include "../fs/concrete.h"
@@ -70,6 +71,9 @@ private:
void OnHelpPerformance (wxHyperlinkEvent& event) override { displayHelpEntry(L"performance", this); }
void OnToggleLocalCompSettings(wxCommandEvent& event) override { updateCompGui(); updateSyncGui(); /*affects sync settings, too!*/ }
+ void OnToggleIgnoreErrors (wxCommandEvent& event) override { updateMiscGui(); }
+ void OnToggleAutoRetry (wxCommandEvent& event) override { updateMiscGui(); }
+
void OnCompByTimeSize (wxCommandEvent& event) override { localCmpVar_ = CompareVariant::TIME_SIZE; updateCompGui(); updateSyncGui(); } //
void OnCompByContent (wxCommandEvent& event) override { localCmpVar_ = CompareVariant::CONTENT; updateCompGui(); updateSyncGui(); } //affects sync settings, too!
void OnCompBySize (wxCommandEvent& event) override { localCmpVar_ = CompareVariant::SIZE; updateCompGui(); updateSyncGui(); } //
@@ -79,13 +83,16 @@ private:
void OnChangeCompOption (wxCommandEvent& event) override { updateCompGui(); }
void onlTimeShiftKeyDown (wxKeyEvent& event) override;
- Opt<CompConfig> getCompConfig() const;
+ std::optional<CompConfig> getCompConfig() const;
void setCompConfig(const CompConfig* compCfg);
void updateCompGui();
CompareVariant localCmpVar_ = CompareVariant::TIME_SIZE;
+ std::set<AbstractPath> devicePathsForEdit_; //helper data for deviceParallelOps
+ std::map<AbstractPath, size_t> deviceParallelOps_; //
+
//------------- filter panel --------------------------
void OnHelpShowExamples(wxHyperlinkEvent& event) override { displayHelpEntry(L"exclude-items", this); }
void OnChangeFilterOption(wxCommandEvent& event) override { updateFilterGui(); }
@@ -111,6 +118,7 @@ private:
void OnToggleDetectMovedFiles (wxCommandEvent& event) override { directionCfg_.detectMovedFiles = !directionCfg_.detectMovedFiles; updateSyncGui(); } //parameter NOT owned by checkbox!
void OnChanegVersioningStyle (wxCommandEvent& event) override { updateSyncGui(); }
void OnToggleVersioningLimit (wxCommandEvent& event) override { updateSyncGui(); }
+ void OnToggleSaveLogfile (wxCommandEvent& event) override { updateMiscGui(); }
void OnSyncTwoWayDouble(wxMouseEvent& event) override;
void OnSyncMirrorDouble(wxMouseEvent& event) override;
@@ -131,33 +139,32 @@ private:
void OnHelpDetectMovedFiles(wxHyperlinkEvent& event) override { displayHelpEntry(L"synchronization-settings", this); }
void OnHelpVersioning (wxHyperlinkEvent& event) override { displayHelpEntry(L"versioning", this); }
- Opt<SyncConfig> getSyncConfig() const;
+ std::optional<SyncConfig> getSyncConfig() const;
void setSyncConfig(const SyncConfig* syncCfg);
void updateSyncGui();
+ //parameters with ownership NOT within GUI controls!
+ DirectionConfig directionCfg_;
+ DeletionPolicy handleDeletion_ = DeletionPolicy::RECYCLER; //use Recycler, delete permanently or move to user-defined location
+
+ const std::function<size_t(const Zstring& folderPathPhrase)> getDeviceParallelOps_;
+ const std::function<void (const Zstring& folderPathPhrase, size_t parallelOps)> setDeviceParallelOps_;
+
+ FolderSelector versioningFolder_;
+ EnumDescrList<VersioningStyle> enumVersioningStyle_;
+
+ FolderSelector logfileDir_;
+
EnumDescrList<PostSyncCondition> enumPostSyncCondition_;
//-----------------------------------------------------
- void OnToggleIgnoreErrors(wxCommandEvent& event) override { updateMiscGui(); }
- void OnToggleAutoRetry (wxCommandEvent& event) override { updateMiscGui(); }
-
MiscSyncConfig getMiscSyncOptions() const;
void setMiscSyncOptions(const MiscSyncConfig& miscCfg);
void updateMiscGui();
- std::set<AbstractPath> devicePathsForEdit_; //helper data for deviceParallelOps
- std::map<AbstractPath, size_t> deviceParallelOps_; //
-
- //parameters with ownership NOT within GUI controls!
- DirectionConfig directionCfg_;
- DeletionPolicy handleDeletion_ = DeletionPolicy::RECYCLER; //use Recycler, delete permanently or move to user-defined location
-
- EnumDescrList<VersioningStyle> enumVersioningStyle_;
- FolderSelector versioningFolder_;
-
//-----------------------------------------------------
void selectFolderPairConfig(int newPairIndexToShow);
@@ -223,17 +230,16 @@ ConfigDialog::ConfigDialog(wxWindow* parent,
std::vector<LocalPairConfig>& localPairConfig,
size_t commandHistItemsMax) :
ConfigDlgGenerated(parent),
- versioningFolder_(*m_panelVersioning, *m_buttonSelectVersioningFolder, *m_bpButtonSelectAltFolder, *m_versioningFolderPath, nullptr /*staticText*/, nullptr /*dropWindow2*/,
- nullptr /*droppedPathsFilter*/,
- [this](const Zstring& folderPathPhrase) //getDeviceParallelOps()
+
+ getDeviceParallelOps_([this](const Zstring& folderPathPhrase)
{
assert(selectedPairIndexToShow_ == -1 || makeUnsigned(selectedPairIndexToShow_) < localPairCfg_.size());
const auto& deviceParallelOps = selectedPairIndexToShow_ < 0 ? getMiscSyncOptions().deviceParallelOps : globalPairCfg_.miscCfg.deviceParallelOps; //ternary-WTF!
return getDeviceParallelOps(deviceParallelOps, folderPathPhrase);
-},
+}),
-[this](const Zstring& folderPathPhrase, size_t parallelOps) //setDeviceParallelOps()
+setDeviceParallelOps_([this](const Zstring& folderPathPhrase, size_t parallelOps) //setDeviceParallelOps()
{
assert(selectedPairIndexToShow_ == -1 || makeUnsigned(selectedPairIndexToShow_) < localPairCfg_.size());
if (selectedPairIndexToShow_ < 0)
@@ -245,6 +251,13 @@ ConfigDialog::ConfigDialog(wxWindow* parent,
else
setDeviceParallelOps(globalPairCfg_.miscCfg.deviceParallelOps, folderPathPhrase, parallelOps);
}),
+
+versioningFolder_(*m_panelVersioning, *m_buttonSelectVersioningFolder, *m_bpButtonSelectVersioningAltFolder, *m_versioningFolderPath,
+ nullptr /*staticText*/, nullptr /*dropWindow2*/, nullptr /*droppedPathsFilter*/, getDeviceParallelOps_, setDeviceParallelOps_),
+
+logfileDir_(*m_panelLogfile, *m_buttonSelectLogFolder, *m_bpButtonSelectAltLogFolder, *m_logFolderPath,
+ nullptr /*staticText*/, nullptr /*dropWindow2*/, nullptr /*droppedPathsFilter*/, getDeviceParallelOps_, setDeviceParallelOps_),
+
globalPairCfgOut_(globalPairCfg),
localPairCfgOut_(localPairConfig),
globalPairCfg_(globalPairCfg),
@@ -298,6 +311,9 @@ commandHistItemsMax_(commandHistItemsMax)
m_panelPerfHeader ->Enable(perfPanelActive_);
m_staticTextPerfParallelOps->Enable(perfPanelActive_);
+ m_spinCtrlAutoRetryCount->SetMinSize(wxSize(fastFromDIP(60), -1)); //Hack: set size (why does wxWindow::Size() not work?)
+ m_spinCtrlAutoRetryDelay->SetMinSize(wxSize(fastFromDIP(60), -1)); //
+
//------------- filter panel --------------------------
m_textCtrlInclude->SetMinSize(wxSize(fastFromDIP(280), -1));
@@ -360,9 +376,6 @@ commandHistItemsMax_(commandHistItemsMax)
m_spinCtrlVersionCountMin->SetMinSize(wxSize(fastFromDIP(60), -1)); //Hack: set size (why does wxWindow::Size() not work?)
m_spinCtrlVersionCountMax->SetMinSize(wxSize(fastFromDIP(60), -1)); //
- m_spinCtrlAutoRetryCount->SetMinSize(wxSize(fastFromDIP(60), -1)); //Hack: set size (why does wxWindow::Size() not work?)
- m_spinCtrlAutoRetryDelay->SetMinSize(wxSize(fastFromDIP(60), -1)); //
-
enumPostSyncCondition_.
add(PostSyncCondition::COMPLETION, _("On completion:")).
add(PostSyncCondition::ERRORS, _("On errors:")).
@@ -398,8 +411,8 @@ commandHistItemsMax_(commandHistItemsMax)
//temporarily set main config as reference for window height calculations:
globalPairCfg_ = GlobalPairConfig();
globalPairCfg_.syncCfg.directionCfg.var = DirectionConfig::MIRROR; //
- globalPairCfg_.syncCfg.handleDeletion = DeletionPolicy::VERSIONING; //set tentatively for sync dir height calculation below
- globalPairCfg_.syncCfg.versioningFolderPhrase = Zstr("dummy"); //
+ globalPairCfg_.syncCfg.handleDeletion = DeletionPolicy::VERSIONING; //
+ globalPairCfg_.syncCfg.versioningFolderPhrase = Zstr("dummy"); //set tentatively for sync dir height calculation below
globalPairCfg_.syncCfg.versioningStyle = VersioningStyle::TIMESTAMP_FILE; //
globalPairCfg_.syncCfg.versionMaxAgeDays = 30; //
@@ -552,10 +565,10 @@ void ConfigDialog::onlTimeShiftKeyDown(wxKeyEvent& event)
}
-Opt<CompConfig> ConfigDialog::getCompConfig() const
+std::optional<CompConfig> ConfigDialog::getCompConfig() const
{
if (!m_checkBoxUseLocalCmpOptions->GetValue())
- return NoValue();
+ return {};
CompConfig compCfg;
compCfg.compareVar = localCmpVar_;
@@ -931,10 +944,10 @@ void updateSyncDirectionIcons(const DirectionConfig& directionCfg,
}
-Opt<SyncConfig> ConfigDialog::getSyncConfig() const
+std::optional<SyncConfig> ConfigDialog::getSyncConfig() const
{
if (!m_checkBoxUseLocalSyncOptions->GetValue())
- return NoValue();
+ return {};
SyncConfig syncCfg;
syncCfg.directionCfg = directionCfg_;
@@ -1134,12 +1147,13 @@ void ConfigDialog::updateSyncGui()
m_spinCtrlVersionCountMin->Show(showLimitCtrls);
m_spinCtrlVersionCountMax->Show(showLimitCtrls);
+ m_staticTextLimitVersions->Enable(enableLimitCtrls);
m_checkBoxVersionMaxDays ->Enable(enableLimitCtrls);
m_checkBoxVersionCountMin->Enable(enableLimitCtrls && m_checkBoxVersionMaxDays->GetValue());
m_checkBoxVersionCountMax->Enable(enableLimitCtrls);
m_spinCtrlVersionMaxDays ->Enable(enableLimitCtrls && m_checkBoxVersionMaxDays ->GetValue());
- m_spinCtrlVersionCountMin->Enable(enableLimitCtrls && m_checkBoxVersionCountMin->GetValue() && m_checkBoxVersionMaxDays->GetValue());
+ m_spinCtrlVersionCountMin->Enable(enableLimitCtrls && m_checkBoxVersionMaxDays->GetValue() && m_checkBoxVersionCountMin->GetValue());
m_spinCtrlVersionCountMax->Enable(enableLimitCtrls && m_checkBoxVersionCountMax->GetValue());
}
@@ -1168,11 +1182,15 @@ MiscSyncConfig ConfigDialog::getMiscSyncOptions() const
//----------------------------------------------------------------------------
miscCfg.ignoreErrors = m_checkBoxIgnoreErrors ->GetValue();
miscCfg.automaticRetryCount = m_checkBoxAutoRetry ->GetValue() ? m_spinCtrlAutoRetryCount->GetValue() : 0;
- miscCfg.automaticRetryDelay = m_spinCtrlAutoRetryDelay->GetValue();
+ miscCfg.automaticRetryDelay = std::chrono::seconds(m_spinCtrlAutoRetryDelay->GetValue());
+ //----------------------------------------------------------------------------
+ miscCfg.altLogFolderPathPhrase = m_checkBoxSaveLog->GetValue() ? utfTo<Zstring>(logfileDir_.getPath()) : Zstring();
miscCfg.postSyncCommand = m_comboBoxPostSyncCommand->getValue();
miscCfg.postSyncCondition = getEnumVal(enumPostSyncCondition_, *m_choicePostSyncCondition),
miscCfg.commandHistory = m_comboBoxPostSyncCommand->getHistory();
+ //----------------------------------------------------------------------------
+
return miscCfg;
}
@@ -1221,11 +1239,16 @@ void ConfigDialog::setMiscSyncOptions(const MiscSyncConfig& miscCfg)
m_checkBoxIgnoreErrors ->SetValue(miscCfg.ignoreErrors);
m_checkBoxAutoRetry ->SetValue(miscCfg.automaticRetryCount > 0);
m_spinCtrlAutoRetryCount->SetValue(std::max<size_t>(miscCfg.automaticRetryCount, 0));
- m_spinCtrlAutoRetryDelay->SetValue(miscCfg.automaticRetryDelay);
+ m_spinCtrlAutoRetryDelay->SetValue(miscCfg.automaticRetryDelay.count());
+ //----------------------------------------------------------------------------
+ m_checkBoxSaveLog->SetValue(!trimCpy(miscCfg.altLogFolderPathPhrase).empty());
+ logfileDir_.setPath(m_checkBoxSaveLog->GetValue() ? miscCfg.altLogFolderPathPhrase : getDefaultLogFolderPath());
+ //can't use logfileDir_.setBackgroundText(): no text shown when control is disabled!
m_comboBoxPostSyncCommand->setValue(miscCfg.postSyncCommand);
setEnumVal(enumPostSyncCondition_, *m_choicePostSyncCondition, miscCfg.postSyncCondition),
m_comboBoxPostSyncCommand->setHistory(miscCfg.commandHistory, commandHistItemsMax_);
+ //----------------------------------------------------------------------------
updateMiscGui();
}
@@ -1235,13 +1258,19 @@ void ConfigDialog::updateMiscGui()
{
const MiscSyncConfig miscCfg = getMiscSyncOptions();
- //----------------------------------------------------------------------------
m_bitmapIgnoreErrors->SetBitmap(miscCfg.ignoreErrors ? getResourceImage(L"error_ignore_active") : greyScale(getResourceImage(L"error_ignore_inactive")));
m_bitmapRetryErrors ->SetBitmap(miscCfg.automaticRetryCount > 0 ? getResourceImage(L"error_retry") : greyScale(getResourceImage(L"error_retry")));
fgSizerAutoRetry->Show(miscCfg.automaticRetryCount > 0);
- bSizerMiscConfig->Layout();
+ bSizerCompMisc->Layout();
+ //----------------------------------------------------------------------------
+
+ m_bitmapLogFile->SetBitmap(m_checkBoxSaveLog->GetValue() ? getResourceImage(L"log_file_sicon") : greyScale(getResourceImage(L"log_file_sicon")));
+ m_logFolderPath ->Enable(m_checkBoxSaveLog->GetValue()); //
+ m_buttonSelectLogFolder ->Show(m_checkBoxSaveLog->GetValue()); //enabled status is *not* directly dependent from resolved config! (but transitively)
+
+ m_panelSyncSettings->Layout(); //after showing/hiding m_buttonSelectLogFolder
}
@@ -1271,7 +1300,8 @@ void ConfigDialog::selectFolderPairConfig(int newPairIndexToShow)
//misc
bSizerPerformance ->Show(mainConfigSelected); //caveat: recursively shows hidden child items!
m_staticlinePerformance->Show(mainConfigSelected);
- bSizerMiscConfig ->Show(mainConfigSelected);
+ bSizerCompMisc ->Show(mainConfigSelected);
+ bSizerSyncMisc ->Show(mainConfigSelected);
if (mainConfigSelected) m_staticTextPerfDeRequired->Show(!perfPanelActive_); //keep after bSizerPerformance->Show()
if (mainConfigSelected) m_staticlinePerfDeRequired->Show(!perfPanelActive_); //
@@ -1311,8 +1341,8 @@ void ConfigDialog::selectFolderPairConfig(int newPairIndexToShow)
}
else
{
- setCompConfig (localPairCfg_[selectedPairIndexToShow_].localCmpCfg .get());
- setSyncConfig (localPairCfg_[selectedPairIndexToShow_].localSyncCfg.get());
+ setCompConfig (get(localPairCfg_[selectedPairIndexToShow_].localCmpCfg ));
+ setSyncConfig (get(localPairCfg_[selectedPairIndexToShow_].localSyncCfg));
setFilterConfig(localPairCfg_[selectedPairIndexToShow_].localFilter);
}
}
@@ -1322,8 +1352,8 @@ bool ConfigDialog::unselectFolderPairConfig()
{
assert(selectedPairIndexToShow_ == -1 || makeUnsigned(selectedPairIndexToShow_) < localPairCfg_.size());
- Opt<CompConfig> compCfg = getCompConfig();
- Opt<SyncConfig> syncCfg = getSyncConfig();
+ std::optional<CompConfig> compCfg = getCompConfig();
+ std::optional<SyncConfig> syncCfg = getSyncConfig();
FilterConfig filterCfg = getFilterConfig();
//------- parameter validation (BEFORE writing output!) -------
@@ -1334,7 +1364,7 @@ bool ConfigDialog::unselectFolderPairConfig()
if (syncCfg && syncCfg->handleDeletion == DeletionPolicy::VERSIONING)
{
- if (trimCpy(syncCfg->versioningFolderPhrase).empty())
+ if (AFS::isNullPath(createAbstractPath(syncCfg->versioningFolderPhrase)))
{
m_notebook->ChangeSelection(static_cast<size_t>(SyncConfigPanel::SYNC));
showNotificationDialog(this, DialogInfoType::INFO, PopupDialogCfg().setMainInstructions(_("Please enter a target folder for versioning.")));
diff --git a/FreeFileSync/Source/ui/sync_cfg.h b/FreeFileSync/Source/ui/sync_cfg.h
index bf64fcb4..e660c3a0 100755
--- a/FreeFileSync/Source/ui/sync_cfg.h
+++ b/FreeFileSync/Source/ui/sync_cfg.h
@@ -24,9 +24,9 @@ struct ReturnSyncConfig
enum class SyncConfigPanel
{
- COMPARISON = 0, //
- FILTER = 1, //used as zero-based notebook page index!
- SYNC = 2, //
+ COMPARISON = 0, //used as zero-based notebook page index!
+ FILTER,
+ SYNC
};
struct MiscSyncConfig
@@ -34,7 +34,8 @@ struct MiscSyncConfig
std::map<AbstractPath, size_t> deviceParallelOps;
bool ignoreErrors = false;
size_t automaticRetryCount = 0;
- size_t automaticRetryDelay = 0;
+ std::chrono::seconds automaticRetryDelay{0};
+ Zstring altLogFolderPathPhrase;
Zstring postSyncCommand;
PostSyncCondition postSyncCondition = PostSyncCondition::COMPLETION;
std::vector<Zstring> commandHistory;
@@ -42,9 +43,9 @@ struct MiscSyncConfig
struct GlobalPairConfig
{
- CompConfig cmpCfg;
- SyncConfig syncCfg;
- FilterConfig filter;
+ CompConfig cmpCfg;
+ SyncConfig syncCfg;
+ FilterConfig filter;
MiscSyncConfig miscCfg;
};
diff --git a/FreeFileSync/Source/ui/tree_grid.cpp b/FreeFileSync/Source/ui/tree_grid.cpp
index 7383fbc1..268cb6e4 100755
--- a/FreeFileSync/Source/ui/tree_grid.cpp
+++ b/FreeFileSync/Source/ui/tree_grid.cpp
@@ -1193,7 +1193,7 @@ private:
const int widthNodeStatus_;
const wxBitmap rootBmp_;
- Opt<wxBitmap> renderBuf_; //avoid costs of recreating this temporary variable
+ std::optional<wxBitmap> renderBuf_; //avoid costs of recreating this temporary variable
Grid& grid_;
bool showPercentBar_ = true;
diff --git a/FreeFileSync/Source/ui/tree_grid.h b/FreeFileSync/Source/ui/tree_grid.h
index 6bbfb446..027271af 100755
--- a/FreeFileSync/Source/ui/tree_grid.h
+++ b/FreeFileSync/Source/ui/tree_grid.h
@@ -8,7 +8,6 @@
#define TREE_VIEW_H_841703190201835280256673425
#include <functional>
-#include <zen/optional.h>
#include <wx+/grid.h>
#include "tree_grid_attr.h"
#include "../base/file_hierarchy.h"
diff --git a/FreeFileSync/Source/ui/version_check.cpp b/FreeFileSync/Source/ui/version_check.cpp
index 47863f06..7052dc23 100755
--- a/FreeFileSync/Source/ui/version_check.cpp
+++ b/FreeFileSync/Source/ui/version_check.cpp
@@ -245,10 +245,10 @@ std::shared_ptr<UpdateCheckResultPrep> fff::automaticUpdateCheckPrepare()
struct fff::UpdateCheckResult
{
- UpdateCheckResult(const std::string& ver, const Opt<zen::SysError>& err, bool alive) : onlineVersion(ver), error(err), internetIsAlive(alive) {}
+ UpdateCheckResult(const std::string& ver, const std::optional<zen::SysError>& err, bool alive) : onlineVersion(ver), error(err), internetIsAlive(alive) {}
std::string onlineVersion;
- Opt<zen::SysError> error;
+ std::optional<zen::SysError> error;
bool internetIsAlive = false;
};
@@ -258,7 +258,7 @@ std::shared_ptr<UpdateCheckResult> fff::automaticUpdateCheckRunAsync(const Updat
try
{
const std::string onlineVersion = getOnlineVersion(resultPrep->postParameters); //throw SysError
- return std::make_shared<UpdateCheckResult>(onlineVersion, NoValue(), true);
+ return std::make_shared<UpdateCheckResult>(onlineVersion, std::nullopt, true);
}
catch (const zen::SysError& e)
{
diff --git a/FreeFileSync/Source/version/version.h b/FreeFileSync/Source/version/version.h
index 63deee3e..0c47fff0 100755
--- a/FreeFileSync/Source/version/version.h
+++ b/FreeFileSync/Source/version/version.h
@@ -3,7 +3,7 @@
namespace fff
{
-const char ffsVersion[] = "10.3"; //internal linkage!
+const char ffsVersion[] = "10.4"; //internal linkage!
const char FFS_VERSION_SEPARATOR = '.';
}
diff --git a/wx+/choice_enum.h b/wx+/choice_enum.h
index 97c40b68..2c424b9f 100755
--- a/wx+/choice_enum.h
+++ b/wx+/choice_enum.h
@@ -77,7 +77,9 @@ void setEnumVal(const EnumDescrList<Enum>& mapping, wxChoice& ctrl, Enum value)
{
selectedPos = it - mapping.descrList.begin();
- if (!it->second.second.empty())
+ if (it->second.second.empty())
+ ctrl.UnsetToolTip();
+ else
ctrl.SetToolTip(it->second.second);
}
}
diff --git a/wx+/dc.h b/wx+/dc.h
index 23c70d3f..ff2f81bd 100755
--- a/wx+/dc.h
+++ b/wx+/dc.h
@@ -8,7 +8,6 @@
#define DC_H_4987123956832143243214
#include <unordered_map>
-#include <zen/optional.h>
#include <zen/basic_math.h>
#include <wx/dcbuffer.h> //for macro: wxALWAYS_NATIVE_DOUBLE_BUFFER
#include <wx/dcscreen.h>
@@ -104,7 +103,7 @@ private:
//associate "active" clipping area with each DC
static std::unordered_map<wxDC*, wxRect>& refDcToAreaMap() { static std::unordered_map<wxDC*, wxRect> clippingAreas; return clippingAreas; }
- Opt<wxRect> oldRect_;
+ std::optional<wxRect> oldRect_;
wxDC& dc_;
};
@@ -114,13 +113,13 @@ private:
#endif
#if wxALWAYS_NATIVE_DOUBLE_BUFFER
-struct BufferedPaintDC : public wxPaintDC { BufferedPaintDC(wxWindow& wnd, Opt<wxBitmap>& buffer) : wxPaintDC(&wnd) {} };
+struct BufferedPaintDC : public wxPaintDC { BufferedPaintDC(wxWindow& wnd, std::optional<wxBitmap>& buffer) : wxPaintDC(&wnd) {} };
#else
class BufferedPaintDC : public wxMemoryDC
{
public:
- BufferedPaintDC(wxWindow& wnd, Opt<wxBitmap>& buffer) : buffer_(buffer), paintDc_(&wnd)
+ BufferedPaintDC(wxWindow& wnd, std::optional<wxBitmap>& buffer) : buffer_(buffer), paintDc_(&wnd)
{
const wxSize clientSize = wnd.GetClientSize();
if (clientSize.GetWidth() > 0 && clientSize.GetHeight() > 0) //wxBitmap asserts this!! width may be 0; test case "Grid::CornerWin": compare both sides, then change config
@@ -134,7 +133,7 @@ public:
SetLayoutDirection(wxLayout_RightToLeft);
}
else
- buffer = NoValue();
+ buffer = {};
}
~BufferedPaintDC()
@@ -153,7 +152,7 @@ public:
}
private:
- Opt<wxBitmap>& buffer_;
+ std::optional<wxBitmap>& buffer_;
wxPaintDC paintDc_;
};
#endif
diff --git a/wx+/focus.h b/wx+/focus.h
index cd99d010..e2daef79 100755
--- a/wx+/focus.h
+++ b/wx+/focus.h
@@ -44,22 +44,37 @@ Preserving input focus has to be more clever than:
*/
struct FocusPreserver
{
+ FocusPreserver()
+ {
+ if (wxWindow* win = wxWindow::FindFocus())
+ setFocus(win);
+ }
+
~FocusPreserver()
{
//wxTopLevelWindow::IsActive() does NOT call Win32 ::GetActiveWindow()!
//Instead it checks if ::GetFocus() is set somewhere inside the top level
//Note: Both Win32 active and focus windows are *thread-local* values, while foreground window is global! https://blogs.msdn.microsoft.com/oldnewthing/20131016-00/?p=2913
- if (oldFocus_)
- if (wxTopLevelWindow* topWin = getTopLevelWindow(oldFocus_))
- if (topWin->IsActive()) //Linux/macOS: already behaves just like ::GetForegroundWindow() on Windows!
- oldFocus_->SetFocus();
+
+ if (oldFocusId_ != wxID_ANY)
+ if (wxWindow* oldFocusWin = wxWindow::FindWindowById(oldFocusId_))
+ if (wxTopLevelWindow* topWin = getTopLevelWindow(oldFocusWin))
+ if (topWin->IsActive()) //Linux/macOS: already behaves just like ::GetForegroundWindow() on Windows!
+ oldFocusWin->SetFocus();
}
- wxWindow* getFocus() const { return oldFocus_; }
- void setFocus(wxWindow* win) { oldFocus_ = win; }
+ wxWindowID getFocusId() const { return oldFocusId_; }
+
+ void setFocus(wxWindow* win)
+ {
+ oldFocusId_ = win->GetId();
+ assert(oldFocusId_ != wxID_ANY);
+ }
private:
- wxWindow* oldFocus_ = wxWindow::FindFocus();
+ wxWindowID oldFocusId_ = wxID_ANY;
+ //don't store wxWindow* which may be dangling during ~FocusPreserver()!
+ //test: click on delete folder pair and immediately press F5 => focus window (= FP del button) is defer-deleted during sync
};
}
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index b006cda0..38846523 100755
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -387,8 +387,8 @@ std::vector<CurvePoint> SparseCurveData::getPoints(double minX, double maxX, con
for (int i = posFrom; i <= posTo; ++i)
{
const double x = cvrtX.screenToReal(i);
- Opt<CurvePoint> ptLe = getLessEq(x);
- Opt<CurvePoint> ptGe = getGreaterEq(x);
+ std::optional<CurvePoint> ptLe = getLessEq(x);
+ std::optional<CurvePoint> ptGe = getGreaterEq(x);
//both non-existent and invalid return values are mapped to out of expected range: => check on posLe/posGe NOT ptLe/ptGe in the following!
const int posLe = ptLe ? cvrtX.realToScreenRound(ptLe->x) : i + 1;
const int posGe = ptGe ? cvrtX.realToScreenRound(ptGe->x) : i - 1;
diff --git a/wx+/graph.h b/wx+/graph.h
index e0c2c12b..f1ae5d5a 100755
--- a/wx+/graph.h
+++ b/wx+/graph.h
@@ -14,7 +14,6 @@
#include <wx/settings.h>
#include <wx/bitmap.h>
#include <zen/string_tools.h>
-#include <zen/optional.h>
//elegant 2D graph as wxPanel specialization
@@ -63,8 +62,8 @@ struct SparseCurveData : public CurveData
{
SparseCurveData(bool addSteps = false) : addSteps_(addSteps) {} //addSteps: add points to get a staircase effect or connect points via a direct line
- virtual Opt<CurvePoint> getLessEq (double x) const = 0;
- virtual Opt<CurvePoint> getGreaterEq(double x) const = 0;
+ virtual std::optional<CurvePoint> getLessEq (double x) const = 0;
+ virtual std::optional<CurvePoint> getGreaterEq(double x) const = 0;
private:
std::vector<CurvePoint> getPoints(double minX, double maxX, const wxSize& areaSizePx) const override;
@@ -80,21 +79,21 @@ struct ArrayCurveData : public SparseCurveData
private:
std::pair<double, double> getRangeX() const override { const size_t sz = getSize(); return { 0.0, sz == 0 ? 0.0 : sz - 1.0}; }
- Opt<CurvePoint> getLessEq(double x) const override
+ std::optional<CurvePoint> getLessEq(double x) const override
{
const size_t sz = getSize();
const size_t pos = std::min<ptrdiff_t>(std::floor(x), sz - 1); //[!] expect unsigned underflow if empty!
if (pos < sz)
return CurvePoint(pos, getValue(pos));
- return NoValue();
+ return {};
}
- Opt<CurvePoint> getGreaterEq(double x) const override
+ std::optional<CurvePoint> getGreaterEq(double x) const override
{
const size_t pos = std::max<ptrdiff_t>(std::ceil(x), 0); //[!] use std::max with signed type!
if (pos < getSize())
return CurvePoint(pos, getValue(pos));
- return NoValue();
+ return {};
}
};
@@ -246,7 +245,7 @@ public:
MainAttributes& setMinY(double newMinY) { minY = newMinY; return *this; }
MainAttributes& setMaxY(double newMaxY) { maxY = newMaxY; return *this; }
- MainAttributes& setAutoSize() { minX = maxX = minY = maxY = NoValue(); return *this; }
+ MainAttributes& setAutoSize() { minX = maxX = minY = maxY = {}; return *this; }
MainAttributes& setLabelX(PosLabelX posX, int height = -1, std::shared_ptr<LabelFormatter> newLabelFmt = nullptr)
{
@@ -272,18 +271,18 @@ public:
private:
friend class Graph2D;
- Opt<double> minX; //x-range to visualize
- Opt<double> maxX; //
+ std::optional<double> minX; //x-range to visualize
+ std::optional<double> maxX; //
- Opt<double> minY; //y-range to visualize
- Opt<double> maxY; //
+ std::optional<double> minY; //y-range to visualize
+ std::optional<double> maxY; //
PosLabelX labelposX = LABEL_X_BOTTOM;
- Opt<int> xLabelHeight;
+ std::optional<int> xLabelHeight;
std::shared_ptr<LabelFormatter> labelFmtX = std::make_shared<DecimalNumberFormatter>();
PosLabelY labelposY = LABEL_Y_LEFT;
- Opt<int> yLabelWidth;
+ std::optional<int> yLabelWidth;
std::shared_ptr<LabelFormatter> labelFmtY = std::make_shared<DecimalNumberFormatter>();
std::map<PosCorner, wxString> cornerTexts;
@@ -337,7 +336,7 @@ private:
MainAttributes attr_; //global attributes
- Opt<wxBitmap> doubleBuffer_;
+ std::optional<wxBitmap> doubleBuffer_;
using CurveList = std::vector<std::pair<std::shared_ptr<CurveData>, CurveAttributes>>;
CurveList curves_;
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index 52ee6e6b..65311ffa 100755
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -310,23 +310,21 @@ public:
protected:
void setToolTip(const std::wstring& text) //proper fix for wxWindow
{
- wxToolTip* tt = GetToolTip();
-
- const wxString oldText = tt ? tt->GetTip() : wxString();
- if (text != oldText)
+ if (text != GetToolTipText())
{
if (text.empty())
- SetToolTip(nullptr); //wxGTK doesn't allow wxToolTip with empty text!
+ UnsetToolTip(); //wxGTK doesn't allow wxToolTip with empty text!
else
{
- //wxWidgets bug: tooltip multiline property is defined by first tooltip text containing newlines or not (same is true for maximum width)
+ wxToolTip* tt = GetToolTip();
if (!tt)
- SetToolTip(new wxToolTip(L"a b\n\
- a b")); //ugly, but working (on Windows)
- tt = GetToolTip(); //should be bound by now
- assert(tt);
- if (tt)
- tt->SetTip(text);
+ {
+ //wxWidgets bug: tooltip multiline property is defined by first tooltip text containing newlines or not (same is true for maximum width)
+ tt = new wxToolTip(L"a b\n\
+ a b"); //ugly, but working (on Windows)
+ SetToolTip(tt); //pass ownership
+ }
+ tt->SetTip(text);
}
}
}
@@ -391,7 +389,7 @@ private:
}
Grid& parent_;
- Opt<wxBitmap> doubleBuffer_;
+ std::optional<wxBitmap> doubleBuffer_;
};
//----------------------------------------------------------------------------------------------------------------
@@ -689,12 +687,12 @@ private:
activeResizing_.reset();
activeClickOrMove_.reset();
- if (Opt<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
+ if (std::optional<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
{
if (action->wantResize)
{
if (!event.LeftDClick()) //double-clicks never seem to arrive here; why is this checked at all???
- if (Opt<int> colWidth = refParent().getColWidth(action->col))
+ if (std::optional<int> colWidth = refParent().getColWidth(action->col))
activeResizing_ = std::make_unique<ColumnResizing>(*this, action->col, *colWidth, event.GetPosition().x);
}
else //a move or single click
@@ -724,7 +722,7 @@ private:
}
else //notify single label click
{
- if (const Opt<ColumnType> colType = refParent().colToType(activeClickOrMove_->getColumnFrom()))
+ if (const std::optional<ColumnType> colType = refParent().colToType(activeClickOrMove_->getColumnFrom()))
sendEventNow(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_LEFT, event, *colType));
}
activeClickOrMove_.reset();
@@ -745,7 +743,7 @@ private:
void onMouseLeftDouble(wxMouseEvent& event) override
{
- if (Opt<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
+ if (std::optional<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
if (action->wantResize)
{
//auto-size visible range on double-click
@@ -790,7 +788,7 @@ private:
}
else
{
- if (const Opt<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
+ if (const std::optional<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
{
highlightCol_ = action->col;
@@ -801,7 +799,7 @@ private:
}
else
{
- highlightCol_ = NoValue();
+ highlightCol_ = {};
SetCursor(*wxSTANDARD_CURSOR);
}
}
@@ -823,7 +821,7 @@ private:
void onLeaveWindow(wxMouseEvent& event) override
{
- highlightCol_ = NoValue(); //wxEVT_LEAVE_WINDOW does not respect mouse capture! -> however highlight_ is drawn unconditionally during move/resize!
+ highlightCol_ = {}; //wxEVT_LEAVE_WINDOW does not respect mouse capture! -> however highlight_ is drawn unconditionally during move/resize!
Refresh();
event.Skip();
@@ -831,9 +829,9 @@ private:
void onMouseRightDown(wxMouseEvent& event) override
{
- if (const Opt<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
+ if (const std::optional<ColAction> action = refParent().clientPosToColumnAction(event.GetPosition()))
{
- if (const Opt<ColumnType> colType = refParent().colToType(action->col))
+ if (const std::optional<ColumnType> colType = refParent().colToType(action->col))
sendEventNow(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, event, *colType)); //notify right click
else assert(false);
}
@@ -847,7 +845,7 @@ private:
std::unique_ptr<ColumnResizing> activeResizing_;
std::unique_ptr<ColumnMove> activeClickOrMove_;
- Opt<size_t> highlightCol_; //column during mouse-over
+ std::optional<size_t> highlightCol_; //column during mouse-over
};
//----------------------------------------------------------------------------------------------------------------
@@ -1080,8 +1078,8 @@ private:
activeSelection_.reset();
}
- highlight_.row = -1;
- Refresh();
+ highlight_.row = -1;
+ Refresh();
//event.Skip(); -> we DID handle it!
}
@@ -1146,8 +1144,8 @@ private:
size_t getStartRow () const { return rowStart_; }
size_t getCurrentRow () const { return rowCurrent_; }
bool isPositiveSelect() const { return positiveSelect_; } //are we selecting or unselecting?
- bool gridWasCleared () const { return gridWasCleared_; }
-
+ bool gridWasCleared () const { return gridWasCleared_; }
+
const GridClickEvent& getFirstClick() const { return firstClick_; }
void evalMousePos()
@@ -1823,7 +1821,7 @@ wxWindow& Grid::getMainWin () { return *mainWin_; }
const wxWindow& Grid::getMainWin() const { return *mainWin_; }
-Opt<Grid::ColAction> Grid::clientPosToColumnAction(const wxPoint& pos) const
+std::optional<Grid::ColAction> Grid::clientPosToColumnAction(const wxPoint& pos) const
{
const int absPosX = CalcUnscrolledPosition(pos).x;
if (absPosX >= 0)
@@ -1851,7 +1849,7 @@ Opt<Grid::ColAction> Grid::clientPosToColumnAction(const wxPoint& pos) const
}
}
}
- return NoValue();
+ return {};
}
diff --git a/wx+/grid.h b/wx+/grid.h
index b9a04842..732a4fcb 100755
--- a/wx+/grid.h
+++ b/wx+/grid.h
@@ -12,7 +12,6 @@
#include <vector>
#include <wx/scrolwin.h>
#include <zen/basic_math.h>
-#include <zen/optional.h>
//a user-friendly, extensible and high-performance grid control
@@ -52,13 +51,13 @@ struct GridSelectEvent : public wxCommandEvent
{
GridSelectEvent(size_t rowFirst, size_t rowLast, bool positive, const GridClickEvent* mouseClick) :
wxCommandEvent(EVENT_GRID_SELECT_RANGE), rowFirst_(rowFirst), rowLast_(rowLast), positive_(positive),
- mouseClick_(mouseClick ? *mouseClick : Opt<GridClickEvent>()) { assert(rowFirst <= rowLast); }
+ mouseClick_(mouseClick ? *mouseClick : std::optional<GridClickEvent>()) { assert(rowFirst <= rowLast); }
GridSelectEvent* Clone() const override { return new GridSelectEvent(*this); }
const size_t rowFirst_; //selected range: [rowFirst_, rowLast_)
const size_t rowLast_;
const bool positive_; //"false" when clearing selection!
- const Opt<GridClickEvent> mouseClick_; //filled unless selection was performed via keyboard shortcuts
+ const std::optional<GridClickEvent> mouseClick_; //filled unless selection was performed via keyboard shortcuts
};
struct GridLabelClickEvent : public wxMouseEvent
@@ -299,12 +298,12 @@ private:
int getColWidthsSum(int mainWinWidth) const;
std::vector<int> getColStretchedWidths(int clientWidth) const; //final width = (normalized) (stretchedWidth + offset)
- Opt<int> getColWidth(size_t col) const
+ std::optional<int> getColWidth(size_t col) const
{
const auto& widths = getColWidths();
if (col < widths.size())
return widths[col].width;
- return NoValue();
+ return {};
}
void setColumnWidth(int width, size_t col, GridEventPolicy columnResizeEventPolicy, bool notifyAsync = false);
@@ -321,7 +320,7 @@ private:
bool wantResize = false; //"!wantResize" means "move" or "single click"
size_t col = 0;
};
- Opt<ColAction> clientPosToColumnAction(const wxPoint& pos) const;
+ std::optional<ColAction> clientPosToColumnAction(const wxPoint& pos) const;
void moveColumn(size_t colFrom, size_t colTo);
ptrdiff_t clientPosToMoveTargetColumn(const wxPoint& pos) const; //return < 0 on error
@@ -363,18 +362,10 @@ private:
template <class ColAttrReal>
std::vector<ColAttrReal> makeConsistent(const std::vector<ColAttrReal>& attribs, const std::vector<ColAttrReal>& defaults)
{
- using ColTypeReal = decltype(ColAttrReal().type);
- std::vector<ColAttrReal> output;
-
- std::set<ColTypeReal> usedTypes; //remove duplicates
- auto appendUnique = [&](const std::vector<ColAttrReal>& attr)
- {
- std::copy_if(attr.begin(), attr.end(), std::back_inserter(output),
- [&](const ColAttrReal& a) { return usedTypes.insert(a.type).second; });
- };
- appendUnique(attribs);
- appendUnique(defaults); //make sure each type is existing!
-
+ std::vector<ColAttrReal> output = attribs;
+ //make sure each type is existing!
+ output.insert(output.end(), defaults.begin(), defaults.end());
+ removeDuplicates(output, [](const ColAttrReal& lhs, const ColAttrReal& rhs) { return lhs.type < rhs.type; });
return output;
}
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
index bbeeff8b..d0449fe5 100755
--- a/wx+/image_resources.cpp
+++ b/wx+/image_resources.cpp
@@ -106,7 +106,7 @@ class DpiParallelScaler
public:
DpiParallelScaler(int hqScale) : hqScale_(hqScale) { assert(hqScale > 1); }
- ~DpiParallelScaler() { threadGroup_ = zen::NoValue(); } //DpiParallelScaler must out-live threadGroup!!!
+ ~DpiParallelScaler() { threadGroup_ = {}; } //DpiParallelScaler must out-live threadGroup!!!
void add(const wxString& name, const wxImage& img)
{
@@ -141,7 +141,7 @@ private:
Protected<std::vector<std::pair<std::wstring, ImageHolder>>> result_;
using TaskType = FunctionReturnTypeT<decltype(&getScalerTask)>;
- Opt<ThreadGroup<TaskType>> threadGroup_{ ThreadGroup<TaskType>(std::max<int>(std::thread::hardware_concurrency(), 1), "xBRZ Scaler") };
+ std::optional<ThreadGroup<TaskType>> threadGroup_{ ThreadGroup<TaskType>(std::max<int>(std::thread::hardware_concurrency(), 1), "xBRZ Scaler") };
//hardware_concurrency() == 0 if "not computable or well defined"
};
diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp
index 0cb0e328..4748a590 100755
--- a/wx+/image_tools.cpp
+++ b/wx+/image_tools.cpp
@@ -14,38 +14,45 @@ using namespace zen;
namespace
{
-void writeToImage(const wxImage& source, wxImage& target, const wxPoint& pos)
+void writeToImage(wxImage& output, const wxImage& top, const wxPoint& pos)
{
- const int srcWidth = source.GetWidth ();
- const int srcHeight = source.GetHeight();
- const int trgWidth = target.GetWidth ();
+ const int topWidth = top.GetWidth ();
+ const int topHeight = top.GetHeight();
+ const int outWidth = output.GetWidth();
- if (srcWidth > 0 && srcHeight > 0)
- {
- assert(0 <= pos.x && pos.x + srcWidth <= trgWidth ); //draw area must be a
- assert(0 <= pos.y && pos.y + srcHeight <= target.GetHeight()); //subset of target image!
- assert(target.HasAlpha());
+ assert(0 <= pos.x && pos.x + topWidth <= outWidth ); //draw area must be a
+ assert(0 <= pos.y && pos.y + topHeight <= output.GetHeight()); //subset of output image!
+ assert(top.HasAlpha() && output.HasAlpha());
- {
- const unsigned char* sourcePtr = source.GetData();
- unsigned char* targetPtr = target.GetData() + 3 * (pos.x + pos.y * trgWidth);
+ //https://en.wikipedia.org/wiki/Alpha_compositing
+ const unsigned char* topRgb = top.GetData();
+ const unsigned char* topAlpha = top.GetAlpha();
- for (int row = 0; row < srcHeight; ++row)
- ::memcpy(targetPtr + 3 * row * trgWidth, sourcePtr + 3 * row * srcWidth, 3 * srcWidth);
- }
+ for (int y = 0; y < topHeight; ++y)
+ {
+ unsigned char* outRgb = output.GetData () + 3 * (pos.x + (pos.y + y) * outWidth);
+ unsigned char* outAlpha = output.GetAlpha() + pos.x + (pos.y + y) * outWidth;
- //handle alpha channel
+ for (int x = 0; x < topWidth; ++x)
{
- unsigned char* targetPtr = target.GetAlpha() + pos.x + pos.y * trgWidth;
- if (source.HasAlpha())
+ const int w1 = *topAlpha; //alpha-composition interpreted as weighted average
+ const int w2 = *outAlpha * (255 - w1) / 255;
+ const int wSum = w1 + w2;
+
+ auto calcColor = [w1, w2, wSum](unsigned char colTop, unsigned char colBot)
{
- const unsigned char* sourcePtr = source.GetAlpha();
- for (int row = 0; row < srcHeight; ++row)
- ::memcpy(targetPtr + row * trgWidth, sourcePtr + row * srcWidth, srcWidth);
- }
- else
- for (int row = 0; row < srcHeight; ++row)
- ::memset(targetPtr + row * trgWidth, wxIMAGE_ALPHA_OPAQUE, srcWidth);
+ return static_cast<unsigned char>(wSum == 0 ? 0 : (colTop * w1 + colBot * w2) / wSum);
+ };
+ outRgb[0] = calcColor(topRgb[0], outRgb[0]);
+ outRgb[1] = calcColor(topRgb[1], outRgb[1]);
+ outRgb[2] = calcColor(topRgb[2], outRgb[2]);
+
+ *outAlpha = static_cast<unsigned char>(wSum);
+
+ topRgb += 3;
+ outRgb += 3;
+ ++topAlpha;
+ ++outAlpha;
}
}
}
@@ -64,16 +71,12 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay
int width = std::max(img1Width, img2Width);
int height = std::max(img1Height, img2Height);
- switch (dir)
- {
- case ImageStackLayout::HORIZONTAL:
- width = img1Width + gap + img2Width;
- break;
- case ImageStackLayout::VERTICAL:
- height = img1Height + gap + img2Height;
- break;
- }
+ if (dir == ImageStackLayout::HORIZONTAL)
+ width = img1Width + gap + img2Width;
+ else
+ height = img1Height + gap + img2Height;
+
wxImage output(width, height);
output.SetAlpha();
::memset(output.GetAlpha(), wxIMAGE_ALPHA_TRANSPARENT, width * height);
@@ -96,13 +99,13 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay
switch (dir)
{
case ImageStackLayout::HORIZONTAL:
- writeToImage(img1, output, wxPoint(0, calcPos(img1Height, height)));
- writeToImage(img2, output, wxPoint(img1Width + gap, calcPos(img2Height, height)));
+ writeToImage(output, img1, wxPoint(0, calcPos(img1Height, height)));
+ writeToImage(output, img2, wxPoint(img1Width + gap, calcPos(img2Height, height)));
break;
case ImageStackLayout::VERTICAL:
- writeToImage(img1, output, wxPoint(calcPos(img1Width, width), 0));
- writeToImage(img2, output, wxPoint(calcPos(img2Width, width), img1Height + gap));
+ writeToImage(output, img1, wxPoint(calcPos(img1Width, width), 0));
+ writeToImage(output, img2, wxPoint(calcPos(img2Width, width), img1Height + gap));
break;
}
return output;
@@ -111,26 +114,6 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay
namespace
{
-void calcAlphaForBlackWhiteImage(wxImage& image) //assume black text on white background
-{
- assert(image.HasAlpha());
- if (unsigned char* alphaPtr = image.GetAlpha())
- {
- const int pixelCount = image.GetWidth() * image.GetHeight();
- const unsigned char* dataPtr = image.GetData();
- for (int i = 0; i < pixelCount; ++ i)
- {
- const unsigned char r = *dataPtr++;
- const unsigned char g = *dataPtr++;
- const unsigned char b = *dataPtr++;
-
- //black(0,0,0) becomes fully opaque(255), while white(255,255,255) becomes transparent(0)
- alphaPtr[i] = static_cast<unsigned char>((255 - r + 255 - g + 255 - b) / 3); //mixed mode arithmetics!
- }
- }
-}
-
-
std::vector<std::pair<wxString, wxSize>> getTextExtentInfo(const wxString& text, const wxFont& font)
{
wxMemoryDC dc; //the context used for bitmaps
@@ -201,32 +184,39 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const
wxImage output(newBitmap.ConvertToImage());
output.SetAlpha();
- calcAlphaForBlackWhiteImage(output);
-
- //apply actual text color
- unsigned char* dataPtr = output.GetData();
+ unsigned char* rgb = output.GetData();
+ unsigned char* alpha = output.GetAlpha();
const int pixelCount = output.GetWidth() * output.GetHeight();
- for (int i = 0; i < pixelCount; ++ i)
+
+ for (int i = 0; i < pixelCount; ++i)
{
- *dataPtr++ = col.Red();
- *dataPtr++ = col.Green();
- *dataPtr++ = col.Blue();
+ //black(0,0,0) becomes wxIMAGE_ALPHA_OPAQUE(255), while white(255,255,255) becomes wxIMAGE_ALPHA_TRANSPARENT(0)
+ *alpha++ = static_cast<unsigned char>((255 - rgb[0] + 255 - rgb[1] + 255 - rgb[2]) / 3); //mixed mode arithmetics!
+
+ rgb[0] = col.Red (); //
+ rgb[1] = col.Green(); //apply actual text color
+ rgb[2] = col.Blue (); //
+
+ rgb += 3;
}
return output;
}
-wxBitmap zen::layOver(const wxBitmap& background, const wxBitmap& foreground, int alignment)
+wxBitmap zen::layOver(const wxBitmap& back, const wxBitmap& front, int alignment)
{
- if (!foreground.IsOk()) return background;
+ if (!front.IsOk()) return back;
+
+ const int width = std::max(back.GetWidth(), front.GetWidth());
+ const int height = std::max(back.GetHeight(), front.GetHeight());
- assert(foreground.HasAlpha() == background.HasAlpha()); //we don't support mixed-mode brittleness!
+ assert(front.HasAlpha() == back.HasAlpha()); //we don't support mixed-mode brittleness!
const int offsetX = [&]
{
if (alignment & wxALIGN_RIGHT)
- return background.GetWidth() - foreground.GetWidth();
+ return back.GetWidth() - front.GetWidth();
if (alignment & wxALIGN_CENTER_HORIZONTAL)
- return (background.GetWidth() - foreground.GetWidth()) / 2;
+ return (back.GetWidth() - front.GetWidth()) / 2;
static_assert(wxALIGN_LEFT == 0);
return 0;
@@ -235,19 +225,22 @@ wxBitmap zen::layOver(const wxBitmap& background, const wxBitmap& foreground, i
const int offsetY = [&]
{
if (alignment & wxALIGN_BOTTOM)
- return background.GetHeight() - foreground.GetHeight();
+ return back.GetHeight() - front.GetHeight();
if (alignment & wxALIGN_CENTER_VERTICAL)
- return (background.GetHeight() - foreground.GetHeight()) / 2;
+ return (back.GetHeight() - front.GetHeight()) / 2;
static_assert(wxALIGN_TOP == 0);
return 0;
}();
- wxBitmap output(background.ConvertToImage()); //attention: wxBitmap/wxImage use ref-counting without copy on write!
- {
- wxMemoryDC dc(output);
- dc.DrawBitmap(foreground, offsetX, offsetY);
- }
+ //can't use wxMemoryDC and wxDC::DrawBitmap(): no alpha channel support on wxGTK!
+ wxImage output(width, height);
+ output.SetAlpha();
+ ::memset(output.GetAlpha(), wxIMAGE_ALPHA_TRANSPARENT, width * height);
+
+ const wxPoint posBack(std::max(-offsetX, 0), std::max(-offsetY, 0));
+ writeToImage(output, back .ConvertToImage(), posBack);
+ writeToImage(output, front.ConvertToImage(), posBack + wxPoint(offsetX, offsetY));
return output;
}
diff --git a/wx+/image_tools.h b/wx+/image_tools.h
index ca82a031..06d7f0ba 100755
--- a/wx+/image_tools.h
+++ b/wx+/image_tools.h
@@ -34,7 +34,7 @@ wxImage stackImages(const wxImage& img1, const wxImage& img2, ImageStackLayout d
wxImage createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign = ImageStackAlignment::LEFT); //CENTER/LEFT/RIGHT
-wxBitmap layOver(const wxBitmap& background, const wxBitmap& foreground, int alignment = wxALIGN_CENTER);
+wxBitmap layOver(const wxBitmap& back, const wxBitmap& front, int alignment = wxALIGN_CENTER);
wxImage greyScale(const wxImage& img); //greyscale + brightness adaption
wxBitmap greyScale(const wxBitmap& bmp); //
diff --git a/wx+/rtl.h b/wx+/rtl.h
index e479c5a8..26380f9d 100755
--- a/wx+/rtl.h
+++ b/wx+/rtl.h
@@ -7,7 +7,6 @@
#ifndef RTL_H_0183487180058718273432148
#define RTL_H_0183487180058718273432148
-#include <zen/optional.h>
#include <wx/dcmemory.h>
#include <wx/image.h>
#include <wx/app.h>
@@ -16,7 +15,7 @@
namespace zen
{
//functions supporting right-to-left GUI layout
-void drawBitmapRtlMirror (wxDC& dc, const wxBitmap& image, const wxRect& rect, int alignment, Opt<wxBitmap>& buffer);
+void drawBitmapRtlMirror (wxDC& dc, const wxBitmap& image, const wxRect& rect, int alignment, std::optional<wxBitmap>& buffer);
void drawBitmapRtlNoMirror(wxDC& dc, const wxBitmap& image, const wxRect& rect, int alignment);
//wxDC::DrawIcon DOES mirror by default -> implement RTL support when needed
@@ -56,7 +55,7 @@ void drawBitmapAligned(wxDC& dc, const wxBitmap& image, const wxRect& rect, int
inline
-void drawBitmapRtlMirror(wxDC& dc, const wxBitmap& image, const wxRect& rect, int alignment, Opt<wxBitmap>& buffer)
+void drawBitmapRtlMirror(wxDC& dc, const wxBitmap& image, const wxRect& rect, int alignment, std::optional<wxBitmap>& buffer)
{
if (dc.GetLayoutDirection() == wxLayout_RightToLeft)
{
diff --git a/xBRZ/src/xbrz.cpp b/xBRZ/src/xbrz.cpp
index b8065f5d..f37d1a01 100755
--- a/xBRZ/src/xbrz.cpp
+++ b/xBRZ/src/xbrz.cpp
@@ -228,6 +228,8 @@ double distYCbCrBuffered(uint32_t pix1, uint32_t pix2)
}
+
+
enum BlendType
{
BLEND_NONE = 0,
@@ -358,8 +360,6 @@ template <> inline unsigned char rotateBlendInfo<ROT_180>(unsigned char b) { ret
template <> inline unsigned char rotateBlendInfo<ROT_270>(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; }
-
-
/*
input kernel area naming convention:
-------------
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index 9c351e25..a81fdae0 100755
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -30,9 +30,9 @@
using namespace zen;
-Opt<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
+std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
{
- auto doParse = [&](int sepCountVolumeRoot, bool rootWithSep) -> Opt<PathComponents>
+ 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;
@@ -47,7 +47,7 @@ Opt<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
return PathComponents({ rootPath, relPath });
}
- return NoValue();
+ return {};
};
if (startsWith(itemPath, "/"))
@@ -72,17 +72,17 @@ Opt<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
}
//we do NOT support relative paths!
- return NoValue();
+ return {};
}
-Opt<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
+std::optional<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
{
- if (const Opt<PathComponents> comp = parsePathComponents(itemPath))
+ if (const std::optional<PathComponents> comp = parsePathComponents(itemPath))
{
if (comp->relPath.empty())
- return NoValue();
+ return {};
const Zstring parentRelPath = beforeLast(comp->relPath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
if (parentRelPath.empty())
@@ -90,7 +90,7 @@ Opt<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
return appendSeparator(comp->rootPath) + parentRelPath;
}
assert(false);
- return NoValue();
+ return {};
}
@@ -110,7 +110,7 @@ ItemType zen::getItemType(const Zstring& itemPath) //throw FileError
PathStatus zen::getPathStatus(const Zstring& itemPath) //throw FileError
{
- const Opt<Zstring> parentPath = getParentFolderPath(itemPath);
+ const std::optional<Zstring> parentPath = getParentFolderPath(itemPath);
try
{
return { getItemType(itemPath), itemPath, {} }; //throw FileError
@@ -145,12 +145,12 @@ PathStatus zen::getPathStatus(const Zstring& itemPath) //throw FileError
}
-Opt<ItemType> zen::getItemTypeIfExists(const Zstring& itemPath) //throw FileError
+std::optional<ItemType> zen::getItemTypeIfExists(const Zstring& itemPath) //throw FileError
{
const PathStatus ps = getPathStatus(itemPath); //throw FileError
if (ps.relPath.empty())
return ps.existingType;
- return NoValue();
+ return {};
}
@@ -672,7 +672,7 @@ FileCopyResult copyFileOsSpecific(const Zstring& sourceFile, //throw FileError,
//close output file handle before setting file time; also good place to catch errors when closing stream!
fileOut.finalize(); //throw FileError, (X) essentially a close() since buffers were already flushed
- Opt<FileError> errorModTime;
+ std::optional<FileError> errorModTime;
try
{
//we cannot set the target file times (::futimes) while the file descriptor is still open after a write operation:
diff --git a/zen/file_access.h b/zen/file_access.h
index c62ddc98..916f23f5 100755
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -23,9 +23,9 @@ struct PathComponents
Zstring rootPath; //itemPath = rootPath + (FILE_NAME_SEPARATOR?) + relPath
Zstring relPath; //
};
-Opt<PathComponents> parsePathComponents(const Zstring& itemPath); //no value on failure
+std::optional<PathComponents> parsePathComponents(const Zstring& itemPath); //no value on failure
-Opt<Zstring> getParentFolderPath(const Zstring& itemPath);
+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
@@ -42,7 +42,7 @@ enum class ItemType
//(hopefully) fast: does not distinguish between error/not existing
ItemType getItemType (const Zstring& itemPath); //throw FileError
//execute potentially SLOW folder traversal but distinguish error/not existing
-Opt<ItemType> getItemTypeIfExists(const Zstring& itemPath); //throw FileError
+std::optional<ItemType> getItemTypeIfExists(const Zstring& itemPath); //throw FileError
struct PathStatus
{
@@ -97,7 +97,7 @@ struct FileCopyResult
time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC
FileId sourceFileId;
FileId targetFileId;
- Opt<FileError> errorModTime; //failure to set modification time
+ std::optional<FileError> errorModTime; //failure to set modification time
};
FileCopyResult copyNewFile(const Zstring& sourceFile, const Zstring& targetFile, bool copyFilePermissions, //throw FileError, ErrorTargetExisting, ErrorFileLocked
diff --git a/zen/format_unit.h b/zen/format_unit.h
index 23ab33fb..3686f39c 100755
--- a/zen/format_unit.h
+++ b/zen/format_unit.h
@@ -9,7 +9,6 @@
#include <string>
#include <cstdint>
-#include "optional.h"
#include "string_tools.h"
diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h
index 5a0013b3..e9d50b97 100755
--- a/zen/legacy_compiler.h
+++ b/zen/legacy_compiler.h
@@ -7,82 +7,13 @@
#ifndef LEGACY_COMPILER_H_839567308565656789
#define LEGACY_COMPILER_H_839567308565656789
- #include <memory>
- #include <cstddef> //std::byte
-
+ #include <optional>
namespace std
{
//https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
//https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
-#ifndef __cpp_lib_type_trait_variable_templates //GCC 7.1
- template<class T, class U> constexpr bool is_same_v = is_same<T, U>::value;
- template<class T> constexpr bool is_const_v = is_const<T>::value;
- template<class T> constexpr bool is_signed_v = is_signed<T>::value;
- template<class T> constexpr bool is_trivially_destructible_v = is_trivially_destructible<T>::value;
-#endif
-
-#if __GNUC__ < 7 || (__GNUC__ == 7 && __GNUC_MINOR__ < 1) //GCC doesn't define __cpp_lib_raw_memory_algorithms
-template<class T> void destroy_at(T* p) { p->~T(); }
-
-template< class ForwardIt >
-void destroy(ForwardIt first, ForwardIt last)
-{
- for (; first != last; ++first)
- std::destroy_at(std::addressof(*first));
-}
-
-template<class InputIt, class ForwardIt>
-ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt trg_first)
-{
- typedef typename std::iterator_traits<ForwardIt>::value_type Value;
- ForwardIt current = trg_first;
- try
- {
- for (; first != last; ++first, ++current)
- ::new (static_cast<void*>(std::addressof(*current))) Value(std::move(*first));
- return current;
- }
- catch (...)
- {
- for (; trg_first != current; ++trg_first)
- trg_first->~Value();
- throw;
- }
-}
-#endif
-
-#ifndef __cpp_lib_apply //GCC 7.1
-template <class F, class T0, class T1, class T2>
-constexpr decltype(auto) apply(F&& f, std::tuple<T0, T1, T2>& t) { return f(std::get<0>(t), std::get<1>(t), std::get<2>(t)); }
-#endif
-
-#if __GNUC__ < 7 || (__GNUC__ == 7 && __GNUC_MINOR__ < 1) //__cpp_lib_byte not defined before GCC 7.3 but supported earlier
- typedef unsigned char byte;
-#endif
-
-#ifndef __cpp_lib_bool_constant //GCC 6.1
- template<bool B> using bool_constant = integral_constant<bool, B>;
-#endif
-
-//================================================================================
-
-}
-namespace __cxxabiv1
-{
-struct __cxa_eh_globals;
-extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept;
-}
-namespace std
-{
-inline int uncaught_exceptions_legacy_hack() noexcept
-{
- return *(reinterpret_cast<unsigned int*>(static_cast<char*>(static_cast<void*>(__cxxabiv1::__cxa_get_globals())) + sizeof(void*)));
-}
-#ifndef __cpp_lib_uncaught_exceptions //GCC 6.1
-inline int uncaught_exceptions() noexcept { return uncaught_exceptions_legacy_hack(); }
-#endif
}
diff --git a/zen/optional.h b/zen/optional.h
deleted file mode 100755
index e4605c5f..00000000
--- a/zen/optional.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// *****************************************************************************
-// * 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 OPTIONAL_H_2857428578342203589
-#define OPTIONAL_H_2857428578342203589
-
-#include <type_traits>
-
-
-namespace zen
-{
-/*
-Optional return value without heap memory allocation!
- -> interface like a pointer, performance like a value
-
- Usage:
- ------
- Opt<MyEnum> someFunction();
-{
- if (allIsWell)
- return enumVal;
- else
- return NoValue();
-}
-
- Opt<MyEnum> optValue = someFunction();
- if (optValue)
- ... use *optValue ...
-*/
-
-struct NoValue {};
-
-template <class T>
-class Opt
-{
-public:
- Opt() {}
- Opt(NoValue) {}
- Opt(const T& val) : valid_(true) { new (&rawMem_) T(val); } //throw X
- Opt( T&& tmp) : valid_(true) { new (&rawMem_) T(std::move(tmp)); }
-
- Opt(const Opt& other) : valid_(other.valid_)
- {
- if (const T* val = other.get())
- new (&rawMem_) T(*val); //throw X
- }
-
- ~Opt() { if (T* val = get()) val->~T(); }
-
- Opt& operator=(const Opt& other) //strong exception-safety iff T::operator=() is strongly exception-safe
- {
- if (T* val = get())
- {
- if (const T* valOther = other.get())
- *val = *valOther; //throw X
- else
- {
- valid_ = false;
- val->~T();
- }
- }
- else if (const T* valOther = other.get())
- {
- new (&rawMem_) T(*valOther); //throw X
- valid_ = true;
- }
- return *this;
- }
-
- Opt& operator=(NoValue) //support assignment to Opt<const T>
- {
- if (T* val = get())
- {
- valid_ = false;
- val->~T();
- }
- return *this;
- }
-
- explicit operator bool() const { return valid_; } //thank you, C++11!!!
-
- const T* get() const { return valid_ ? reinterpret_cast<const T*>(&rawMem_) : nullptr; }
- T* get() { return valid_ ? reinterpret_cast< T*>(&rawMem_) : nullptr; }
-
- const T& operator*() const { return *get(); }
- /**/ T& operator*() { return *get(); }
-
- const T* operator->() const { return get(); }
- /**/ T* operator->() { return get(); }
-
-private:
- std::aligned_storage_t<sizeof(T), alignof(T)> rawMem_; //don't require T to be default-constructible!
- bool valid_ = false;
-};
-
-
-template <class T> inline
-bool operator==(const Opt<T>& lhs, const Opt<T>& rhs)
-{
- if (static_cast<bool>(lhs) != static_cast<bool>(rhs))
- return false;
- if (!lhs)
- return true;
- return *lhs == *rhs;
-}
-template <class T> inline
-bool operator!=(const Opt<T>& lhs, const Opt<T>& rhs) { return !(lhs == rhs); }
-
-}
-
-#endif //OPTIONAL_H_2857428578342203589
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index 30b37cb2..8b4389a7 100755
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -27,7 +27,7 @@ bool zen::recycleOrDeleteIfExists(const Zstring& itemPath) //throw FileError
if (!::g_file_trash(file, nullptr, &error))
{
- const Opt<ItemType> type = getItemTypeIfExists(itemPath); //throw FileError
+ const std::optional<ItemType> type = getItemTypeIfExists(itemPath); //throw FileError
if (!type)
return false;
diff --git a/zen/ring_buffer.h b/zen/ring_buffer.h
index 6debd84e..232e17da 100755
--- a/zen/ring_buffer.h
+++ b/zen/ring_buffer.h
@@ -10,8 +10,8 @@
#include <cassert>
#include <vector>
#include <stdexcept>
-#include "type_traits.h"
#include "scope_guard.h"
+#include "string_tools.h"
namespace zen
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index a0e5634b..0802fbcb 100755
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -73,7 +73,7 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError
inline
void openWithDefaultApplication(const Zstring& itemPath) //throw FileError
{
- shellExecute("xdg-open \"" + itemPath + "\"", ExecutionType::ASYNC); //
+ shellExecute("xdg-open \"" + itemPath + "\"", ExecutionType::ASYNC); //
}
}
diff --git a/zen/socket.h b/zen/socket.h
index c92071e2..e551a5ba 100755
--- a/zen/socket.h
+++ b/zen/socket.h
@@ -53,7 +53,7 @@ public:
return testSocket;
};
- Opt<SysError> firstError;
+ std::optional<SysError> firstError;
for (const auto* /*::addrinfo*/ si = servinfo; si; si = si->ai_next)
try
{
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 7365392f..be9bf710 100755
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -12,7 +12,7 @@
#include <vector>
#include <memory>
#include <algorithm>
-#include "type_traits.h"
+#include "string_traits.h"
#include "build_info.h"
@@ -42,8 +42,11 @@ void append(std::map<KeyType, ValueType, LessType, Alloc>& m, const C& c);
template <class T, class Alloc>
void removeDuplicates(std::vector<T, Alloc>& v);
+template <class T, class Alloc, class CompLess>
+void removeDuplicates(std::vector<T, Alloc>& v, CompLess less);
+
//binary search returning an iterator
-template <class Iterator, class T, typename CompLess>
+template <class Iterator, class T, class CompLess>
Iterator binary_search(Iterator first, Iterator last, const T& value, CompLess less);
template <class BidirectionalIterator, class T>
@@ -70,6 +73,9 @@ struct StringHash
};
+//why, oh wy is there no std::optional<T>::get()???
+template <class T> inline T* get( std::optional<T>& opt) { return opt ? &*opt : nullptr; }
+template <class T> inline const T* get(const std::optional<T>& opt) { return opt ? &*opt : nullptr; }
@@ -117,15 +123,29 @@ template <class KeyType, class ValueType, class LessType, class Alloc, class C>
void append(std::map<KeyType, ValueType, LessType, Alloc>& m, const C& c) { m.insert(c.begin(), c.end()); }
+template <class T, class Alloc, class CompLess, class CompEqual> inline
+void removeDuplicates(std::vector<T, Alloc>& v, CompLess less, CompEqual eq)
+{
+ std::sort(v.begin(), v.end(), less);
+ v.erase(std::unique(v.begin(), v.end(), eq), v.end());
+}
+
+
+template <class T, class Alloc, class CompLess> inline
+void removeDuplicates(std::vector<T, Alloc>& v, CompLess less)
+{
+ removeDuplicates(v, less, [&](const auto& lhs, const auto& rhs) { return !less(lhs, rhs) && !less(rhs, lhs); });
+}
+
+
template <class T, class Alloc> inline
void removeDuplicates(std::vector<T, Alloc>& v)
{
- std::sort(v.begin(), v.end());
- v.erase(std::unique(v.begin(), v.end()), v.end());
+ removeDuplicates(v, std::less<T>(), std::equal_to<T>());
}
-template <class Iterator, class T, typename CompLess> inline
+template <class Iterator, class T, class CompLess> inline
Iterator binary_search(Iterator first, Iterator last, const T& value, CompLess less)
{
static_assert(std::is_same_v<typename std::iterator_traits<Iterator>::iterator_category, std::random_access_iterator_tag>);
diff --git a/zen/thread.h b/zen/thread.h
index 5828d07a..7f3d216c 100755
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -11,7 +11,6 @@
#include <future>
#include "scope_guard.h"
#include "ring_buffer.h"
-#include "optional.h"
#include "string_tools.h"
@@ -97,13 +96,13 @@ public:
GetFirstResult();
template <class Fun>
- void addJob(Fun&& f); //f must return a zen::Opt<T> containing a value if successful
+ void addJob(Fun&& f); //f must return a std::optional<T> containing a value if successful
template <class Duration>
bool timedWait(const Duration& duration) const; //true: "get()" is ready, false: time elapsed
//return first value or none if all jobs failed; blocks until result is ready!
- Opt<T> get() const; //may be called only once!
+ std::optional<T> get() const; //may be called only once!
private:
class AsyncResult;
@@ -323,7 +322,7 @@ class GetFirstResult<T>::AsyncResult
{
public:
//context: worker threads
- void reportFinished(Opt<T>&& result)
+ void reportFinished(std::optional<T>&& result)
{
{
std::lock_guard<std::mutex> dummy(lockResult_);
@@ -342,7 +341,7 @@ public:
return conditionJobDone_.wait_for(dummy, duration, [&] { return this->jobDone(jobsTotal); });
}
- Opt<T> getResult(size_t jobsTotal)
+ std::optional<T> getResult(size_t jobsTotal)
{
std::unique_lock<std::mutex> dummy(lockResult_);
conditionJobDone_.wait(dummy, [&] { return this->jobDone(jobsTotal); });
@@ -355,7 +354,7 @@ private:
std::mutex lockResult_;
size_t jobsFinished_ = 0; //
- Opt<T> result_; //our condition is: "have result" or "jobsFinished_ == jobsTotal"
+ std::optional<T> result_; //our condition is: "have result" or "jobsFinished_ == jobsTotal"
std::condition_variable conditionJobDone_;
};
@@ -367,7 +366,7 @@ GetFirstResult<T>::GetFirstResult() : asyncResult_(std::make_shared<AsyncResult>
template <class T>
template <class Fun> inline
-void GetFirstResult<T>::addJob(Fun&& f) //f must return a zen::Opt<T> containing a value on success
+void GetFirstResult<T>::addJob(Fun&& f) //f must return a std::optional<T> containing a value on success
{
std::thread t([asyncResult = this->asyncResult_, f = std::forward<Fun>(f)] { asyncResult->reportFinished(f()); });
++jobsTotal_;
@@ -381,7 +380,7 @@ bool GetFirstResult<T>::timedWait(const Duration& duration) const { return async
template <class T> inline
-Opt<T> GetFirstResult<T>::get() const { return asyncResult_->getResult(jobsTotal_); }
+std::optional<T> GetFirstResult<T>::get() const { return asyncResult_->getResult(jobsTotal_); }
//------------------------------------------------------------------------------------------
diff --git a/zen/utf.h b/zen/utf.h
index 48269416..da6aaf97 100755
--- a/zen/utf.h
+++ b/zen/utf.h
@@ -10,7 +10,6 @@
#include <cstdint>
#include <iterator>
#include "string_tools.h" //copyStringTo
-#include "optional.h"
namespace zen
@@ -96,10 +95,10 @@ class Utf16Decoder
public:
Utf16Decoder(const Char16* str, size_t len) : it_(str), last_(str + len) {}
- Opt<CodePoint> getNext()
+ std::optional<CodePoint> getNext()
{
if (it_ == last_)
- return NoValue();
+ return {};
const Char16 ch = *it_++;
CodePoint cp = ch;
@@ -190,10 +189,10 @@ class Utf8Decoder
public:
Utf8Decoder(const Char8* str, size_t len) : it_(str), last_(str + len) {}
- Opt<CodePoint> getNext()
+ std::optional<CodePoint> getNext()
{
if (it_ == last_)
- return NoValue();
+ return std::nullopt; //GCC 8.2 bug: -Wmaybe-uninitialized for "return {};"
const Char8 ch = *it_++;
CodePoint cp = ch;
@@ -268,7 +267,7 @@ class UtfDecoderImpl<CharType, 1> //UTF8-char
{
public:
UtfDecoderImpl(const CharType* str, size_t len) : decoder_(reinterpret_cast<const Char8*>(str), len) {}
- Opt<CodePoint> getNext() { return decoder_.getNext(); }
+ std::optional<CodePoint> getNext() { return decoder_.getNext(); }
private:
Utf8Decoder decoder_;
};
@@ -279,7 +278,7 @@ class UtfDecoderImpl<CharType, 2> //Windows: UTF16-wchar_t
{
public:
UtfDecoderImpl(const CharType* str, size_t len) : decoder_(reinterpret_cast<const Char16*>(str), len) {}
- Opt<CodePoint> getNext() { return decoder_.getNext(); }
+ std::optional<CodePoint> getNext() { return decoder_.getNext(); }
private:
Utf16Decoder decoder_;
};
@@ -290,10 +289,10 @@ class UtfDecoderImpl<CharType, 4> //other OS: UTF32-wchar_t
{
public:
UtfDecoderImpl(const CharType* str, size_t len) : it_(reinterpret_cast<const CodePoint*>(str)), last_(it_ + len) {}
- Opt<CodePoint> getNext()
+ std::optional<CodePoint> getNext()
{
if (it_ == last_)
- return NoValue();
+ return {};
return *it_++;
}
private:
@@ -314,7 +313,7 @@ bool isValidUtf(const UtfString& str)
using namespace impl;
UtfDecoder<GetCharTypeT<UtfString>> decoder(strBegin(str), strLength(str));
- while (Opt<CodePoint> cp = decoder.getNext())
+ while (std::optional<CodePoint> cp = decoder.getNext())
if (*cp == REPLACEMENT_CHAR)
return false;
@@ -344,7 +343,7 @@ UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t u
return output;
UtfDecoder<CharType> decoder(strBegin(str), strLength(str));
- for (size_t uniPos = 0; Opt<CodePoint> cp = decoder.getNext(); ++uniPos) //[!] declaration in condition part of the for-loop
+ for (size_t uniPos = 0; std::optional<CodePoint> cp = decoder.getNext(); ++uniPos) //[!] declaration in condition part of the for-loop
if (uniPosFirst <= uniPos)
{
if (uniPos >= uniPosLast)
@@ -368,7 +367,7 @@ TargetString utfTo(const SourceString& str, std::false_type)
TargetString output;
UtfDecoder<CharSrc> decoder(strBegin(str), strLength(str));
- while (Opt<CodePoint> cp = decoder.getNext())
+ while (std::optional<CodePoint> cp = decoder.getNext())
codePointToUtf<CharTrg>(*cp, [&](CharTrg c) { output += c; });
return output;
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 1fe31eaf..8bf77a0b 100755
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -49,8 +49,8 @@ int compareNoCaseUtf8(const char* lhs, size_t lhsLen, const char* rhs, size_t rh
impl::UtfDecoder<char> decR(rhs, rhsLen);
for (;;)
{
- const Opt<impl::CodePoint> cpL = decL.getNext();
- const Opt<impl::CodePoint> cpR = decR.getNext();
+ const std::optional<impl::CodePoint> cpL = decL.getNext();
+ const std::optional<impl::CodePoint> cpR = decR.getNext();
if (!cpL || !cpR)
return static_cast<int>(!cpR) - static_cast<int>(!cpL);
diff --git a/zen/zstring.h b/zen/zstring.h
index 3938cef1..7fa21335 100755
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -95,7 +95,7 @@ const wchar_t LTR_MARK = L'\u200E'; //UTF-8: E2 80 8E
const wchar_t RTL_MARK = L'\u200F'; //UTF-8: E2 80 8F
const wchar_t ELLIPSIS = L'\u2026'; //"..."
const wchar_t MULT_SIGN = L'\u00D7'; //fancy "x"
-
+//const wchar_t NOBREAK_SPACE = L'\u00A0';
diff --git a/zenXml/zenxml/cvrt_struc.h b/zenXml/zenxml/cvrt_struc.h
index 11795107..85c5d8d0 100755
--- a/zenXml/zenxml/cvrt_struc.h
+++ b/zenXml/zenxml/cvrt_struc.h
@@ -65,21 +65,19 @@ using IsStlContainer = std::bool_constant<
impl_2384343::HasMember_insert <T>::value>;
-namespace impl_2384343
+template <class T>
+struct IsStlPair
{
-ZEN_INIT_DETECT_MEMBER_TYPE(first_type);
-ZEN_INIT_DETECT_MEMBER_TYPE(second_type);
-
-ZEN_INIT_DETECT_MEMBER(first) //we don't know the exact declaration of the member attribute: may be in a base class!
-ZEN_INIT_DETECT_MEMBER(second) //
-}
-
-template <typename T>
-using IsStlPair = std::bool_constant<
- impl_2384343::HasMemberType_first_type <T>::value &&
- impl_2384343::HasMemberType_second_type<T>::value &&
- impl_2384343::HasMember_first <T>::value &&
- impl_2384343::HasMember_second <T>::value>;
+private:
+ using Yes = char[1];
+ using No = char[2];
+
+ template <class T1, class T2>
+ static Yes& isPair(const std::pair<T1, T2>&);
+ static No& isPair(...);
+public:
+ enum { value = sizeof(isPair(std::declval<T>())) == sizeof(Yes) };
+};
//######################################################################################
diff --git a/zenXml/zenxml/cvrt_text.h b/zenXml/zenxml/cvrt_text.h
index 32a961b2..c6dab8c2 100755
--- a/zenXml/zenxml/cvrt_text.h
+++ b/zenXml/zenxml/cvrt_text.h
@@ -7,6 +7,7 @@
#ifndef CVRT_TEXT_H_018727339083427097434
#define CVRT_TEXT_H_018727339083427097434
+#include <chrono>
#include <zen/utf.h>
#include <zen/string_tools.h>
@@ -101,21 +102,37 @@ template <class T> void writeText(const T& value, std::string& output);
//------------------------------ implementation -------------------------------------
+template <class T>
+struct IsChronoDuration
+{
+private:
+ using Yes = char[1];
+ using No = char[2];
+
+ template <class Rep, class Period>
+ static Yes& isDuration(std::chrono::duration<Rep, Period>);
+ static No& isDuration(...);
+public:
+ enum { value = sizeof(isDuration(std::declval<T>())) == sizeof(Yes) };
+};
+
//Conversion from arbitrary types to text (for use with XML elements and attributes)
enum TextType
{
TEXT_TYPE_BOOL,
TEXT_TYPE_NUMBER,
+ TEXT_TYPE_CHRONO,
TEXT_TYPE_STRING,
TEXT_TYPE_OTHER,
};
template <class T>
struct GetTextType : std::integral_constant<TextType,
- std::is_same_v<T, bool> ? TEXT_TYPE_BOOL :
- IsStringLikeV<T> ? TEXT_TYPE_STRING : //string before number to correctly handle char/wchar_t -> this was an issue with Loki only!
- IsArithmetic<T>::value ? TEXT_TYPE_NUMBER : //
+ std::is_same_v<T, bool> ? TEXT_TYPE_BOOL :
+ IsStringLikeV<T> ? TEXT_TYPE_STRING : //string before number to correctly handle char/wchar_t -> this was an issue with Loki only!
+ IsArithmetic<T>::value ? TEXT_TYPE_NUMBER : //
+ IsChronoDuration<T>::value ? TEXT_TYPE_CHRONO :
TEXT_TYPE_OTHER> {};
//######################################################################################
@@ -165,6 +182,20 @@ struct ConvertText<T, TEXT_TYPE_NUMBER>
}
};
+template <class T>
+struct ConvertText<T, TEXT_TYPE_CHRONO>
+{
+ void writeText(const T& value, std::string& output) const
+ {
+ output = numberTo<std::string>(value.count());
+ }
+ bool readText(const std::string& input, T& value) const
+ {
+ value = T(stringTo<typename T::rep>(input));
+ return true;
+ }
+};
+
//partial specialization: handle conversion for all string-like types!
template <class T>
struct ConvertText<T, TEXT_TYPE_STRING>
diff --git a/zenXml/zenxml/dom.h b/zenXml/zenxml/dom.h
index 8793d5bd..d95f5aa1 100755
--- a/zenXml/zenxml/dom.h
+++ b/zenXml/zenxml/dom.h
@@ -237,7 +237,7 @@ public:
std::pair<AttrIter, AttrIter> getAttributes() const { return { attributes_.begin(), attributes_.end() }; }
//swap two elements while keeping references to parent. -> disabled documentation extraction
- void swapSubtree(XmlElement& other)
+ void swapSubtree(XmlElement& other) noexcept
{
name_ .swap(other.name_);
value_ .swap(other.value_);
@@ -283,8 +283,8 @@ public:
///Default constructor setting up an empty XML document with a standard declaration: <?xml version="1.0" encoding="utf-8" ?>
XmlDoc() {}
- XmlDoc(XmlDoc&& tmp) { swap(tmp); }
- XmlDoc& operator=(XmlDoc&& tmp) { swap(tmp); return *this; }
+ XmlDoc(XmlDoc&& tmp) noexcept { swap(tmp); }
+ XmlDoc& operator=(XmlDoc&& tmp) noexcept { swap(tmp); return *this; }
//Setup an empty XML document
/**
@@ -342,7 +342,7 @@ public:
void setStandalone(const String& standalone) { standalone_ = utfTo<std::string>(standalone); }
//Transactionally swap two elements. -> disabled documentation extraction
- void swap(XmlDoc& other)
+ void swap(XmlDoc& other) noexcept
{
version_ .swap(other.version_);
encoding_ .swap(other.encoding_);
bgstack15