summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xChangelog.txt18
-rwxr-xr-xFreeFileSync/Build/Help/html/schedule-a-batch-job.html2
-rwxr-xr-xFreeFileSync/Build/Help/images/setup-batch-job.pngbin12966 -> 19809 bytes
-rwxr-xr-xFreeFileSync/Build/Languages/bulgarian.lng82
-rwxr-xr-xFreeFileSync/Build/Languages/german.lng100
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/application.cpp19
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/application.h3
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/folder_selector2.cpp5
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/folder_selector2.h4
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/gui_generated.cpp16
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/gui_generated.h5
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/main_dlg.cpp99
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/main_dlg.h13
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/monitor.cpp75
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/monitor.h8
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/tray_menu.cpp22
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/tray_menu.h2
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/xml_proc.cpp28
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/xml_proc.h4
-rwxr-xr-xFreeFileSync/Source/algorithm.cpp42
-rwxr-xr-xFreeFileSync/Source/algorithm.h8
-rwxr-xr-xFreeFileSync/Source/application.cpp25
-rwxr-xr-xFreeFileSync/Source/application.h5
-rwxr-xr-xFreeFileSync/Source/comparison.cpp44
-rwxr-xr-xFreeFileSync/Source/comparison.h6
-rwxr-xr-xFreeFileSync/Source/file_hierarchy.cpp17
-rwxr-xr-xFreeFileSync/Source/file_hierarchy.h12
-rwxr-xr-xFreeFileSync/Source/fs/abstract.cpp6
-rwxr-xr-xFreeFileSync/Source/fs/abstract.h54
-rwxr-xr-xFreeFileSync/Source/fs/concrete.cpp4
-rwxr-xr-xFreeFileSync/Source/fs/concrete.h2
-rwxr-xr-xFreeFileSync/Source/fs/native.cpp169
-rwxr-xr-xFreeFileSync/Source/fs/native.h2
-rwxr-xr-xFreeFileSync/Source/fs/native_traverser_impl.h171
-rwxr-xr-xFreeFileSync/Source/lib/binary.cpp9
-rwxr-xr-xFreeFileSync/Source/lib/binary.h4
-rwxr-xr-xFreeFileSync/Source/lib/cmp_filetime.h2
-rwxr-xr-xFreeFileSync/Source/lib/db_file.cpp25
-rwxr-xr-xFreeFileSync/Source/lib/db_file.h14
-rwxr-xr-xFreeFileSync/Source/lib/dir_exist_async.h6
-rwxr-xr-xFreeFileSync/Source/lib/dir_lock.cpp135
-rwxr-xr-xFreeFileSync/Source/lib/dir_lock.h17
-rwxr-xr-xFreeFileSync/Source/lib/error_log.h4
-rwxr-xr-xFreeFileSync/Source/lib/ffs_paths.cpp8
-rwxr-xr-xFreeFileSync/Source/lib/ffs_paths.h3
-rwxr-xr-xFreeFileSync/Source/lib/generate_logfile.h83
-rwxr-xr-xFreeFileSync/Source/lib/hard_filter.cpp5
-rwxr-xr-xFreeFileSync/Source/lib/hard_filter.h3
-rwxr-xr-xFreeFileSync/Source/lib/help_provider.h4
-rwxr-xr-xFreeFileSync/Source/lib/icon_buffer.cpp11
-rwxr-xr-xFreeFileSync/Source/lib/icon_buffer.h8
-rwxr-xr-xFreeFileSync/Source/lib/icon_holder.h4
-rwxr-xr-xFreeFileSync/Source/lib/icon_loader.cpp13
-rwxr-xr-xFreeFileSync/Source/lib/icon_loader.h2
-rwxr-xr-xFreeFileSync/Source/lib/localization.cpp59
-rwxr-xr-xFreeFileSync/Source/lib/localization.h3
-rwxr-xr-xFreeFileSync/Source/lib/lock_holder.h20
-rwxr-xr-xFreeFileSync/Source/lib/norm_filter.h4
-rwxr-xr-xFreeFileSync/Source/lib/parallel_scan.cpp25
-rwxr-xr-xFreeFileSync/Source/lib/parallel_scan.h28
-rwxr-xr-xFreeFileSync/Source/lib/parse_lng.h144
-rwxr-xr-xFreeFileSync/Source/lib/parse_plural.h11
-rwxr-xr-xFreeFileSync/Source/lib/perf_check.cpp136
-rwxr-xr-xFreeFileSync/Source/lib/perf_check.h30
-rwxr-xr-xFreeFileSync/Source/lib/process_xml.cpp720
-rwxr-xr-xFreeFileSync/Source/lib/process_xml.h119
-rwxr-xr-xFreeFileSync/Source/lib/resolve_path.cpp14
-rwxr-xr-xFreeFileSync/Source/lib/resolve_path.h2
-rwxr-xr-xFreeFileSync/Source/lib/return_codes.h2
-rwxr-xr-xFreeFileSync/Source/lib/soft_filter.h22
-rwxr-xr-xFreeFileSync/Source/lib/status_handler.cpp7
-rwxr-xr-xFreeFileSync/Source/lib/status_handler.h77
-rwxr-xr-xFreeFileSync/Source/lib/status_handler_impl.h8
-rwxr-xr-xFreeFileSync/Source/lib/versioning.cpp14
-rwxr-xr-xFreeFileSync/Source/lib/versioning.h14
-rwxr-xr-xFreeFileSync/Source/process_callback.h10
-rwxr-xr-xFreeFileSync/Source/structures.cpp138
-rwxr-xr-xFreeFileSync/Source/structures.h11
-rwxr-xr-xFreeFileSync/Source/synchronization.cpp86
-rwxr-xr-xFreeFileSync/Source/synchronization.h5
-rwxr-xr-xFreeFileSync/Source/ui/app_icon.h3
-rwxr-xr-xFreeFileSync/Source/ui/batch_config.cpp22
-rwxr-xr-xFreeFileSync/Source/ui/batch_config.h5
-rwxr-xr-xFreeFileSync/Source/ui/batch_status_handler.cpp270
-rwxr-xr-xFreeFileSync/Source/ui/batch_status_handler.h30
-rwxr-xr-xFreeFileSync/Source/ui/cfg_grid.cpp32
-rwxr-xr-xFreeFileSync/Source/ui/cfg_grid.h15
-rwxr-xr-xFreeFileSync/Source/ui/command_box.cpp3
-rwxr-xr-xFreeFileSync/Source/ui/command_box.h7
-rwxr-xr-xFreeFileSync/Source/ui/file_grid.cpp15
-rwxr-xr-xFreeFileSync/Source/ui/file_grid.h18
-rwxr-xr-xFreeFileSync/Source/ui/file_grid_attr.h2
-rwxr-xr-xFreeFileSync/Source/ui/file_view.cpp1
-rwxr-xr-xFreeFileSync/Source/ui/file_view.h11
-rwxr-xr-xFreeFileSync/Source/ui/folder_history_box.cpp1
-rwxr-xr-xFreeFileSync/Source/ui/folder_history_box.h8
-rwxr-xr-xFreeFileSync/Source/ui/folder_pair.h58
-rwxr-xr-xFreeFileSync/Source/ui/folder_selector.cpp5
-rwxr-xr-xFreeFileSync/Source/ui/folder_selector.h6
-rwxr-xr-xFreeFileSync/Source/ui/gui_generated.cpp104
-rwxr-xr-xFreeFileSync/Source/ui/gui_generated.h72
-rwxr-xr-xFreeFileSync/Source/ui/gui_status_handler.cpp216
-rwxr-xr-xFreeFileSync/Source/ui/gui_status_handler.h24
-rwxr-xr-xFreeFileSync/Source/ui/main_dlg.cpp354
-rwxr-xr-xFreeFileSync/Source/ui/main_dlg.h94
-rwxr-xr-xFreeFileSync/Source/ui/progress_indicator.cpp347
-rwxr-xr-xFreeFileSync/Source/ui/progress_indicator.h33
-rwxr-xr-xFreeFileSync/Source/ui/search.cpp5
-rwxr-xr-xFreeFileSync/Source/ui/search.h5
-rwxr-xr-xFreeFileSync/Source/ui/small_dlgs.cpp164
-rwxr-xr-xFreeFileSync/Source/ui/small_dlgs.h4
-rwxr-xr-xFreeFileSync/Source/ui/sorting.h24
-rwxr-xr-xFreeFileSync/Source/ui/sync_cfg.cpp4
-rwxr-xr-xFreeFileSync/Source/ui/sync_cfg.h2
-rwxr-xr-xFreeFileSync/Source/ui/taskbar.cpp1
-rwxr-xr-xFreeFileSync/Source/ui/taskbar.h2
-rwxr-xr-xFreeFileSync/Source/ui/tray_icon.cpp23
-rwxr-xr-xFreeFileSync/Source/ui/tray_icon.h13
-rwxr-xr-xFreeFileSync/Source/ui/tree_grid.cpp11
-rwxr-xr-xFreeFileSync/Source/ui/tree_grid.h13
-rwxr-xr-xFreeFileSync/Source/ui/tree_grid_attr.h2
-rwxr-xr-xFreeFileSync/Source/ui/triple_splitter.cpp31
-rwxr-xr-xFreeFileSync/Source/ui/triple_splitter.h24
-rwxr-xr-xFreeFileSync/Source/ui/version_check.cpp32
-rwxr-xr-xFreeFileSync/Source/ui/version_check.h3
-rw-r--r--[-rwxr-xr-x]FreeFileSync/Source/ui/version_check_impl.h4
-rwxr-xr-xFreeFileSync/Source/version/version.h4
-rwxr-xr-xwx+/app_main.h9
-rwxr-xr-xwx+/choice_enum.h3
-rwxr-xr-xwx+/context_menu.h1
-rwxr-xr-xwx+/dc.h1
-rwxr-xr-xwx+/graph.cpp18
-rwxr-xr-xwx+/graph.h2
-rwxr-xr-xwx+/grid.cpp6
-rwxr-xr-xwx+/grid.h2
-rwxr-xr-xwx+/http.cpp6
-rwxr-xr-xwx+/http.h2
-rwxr-xr-xwx+/image_resources.h1
-rwxr-xr-xwx+/no_flicker.h1
-rwxr-xr-xwx+/rtl.h1
-rwxr-xr-xwx+/toggle_button.h17
-rwxr-xr-xzen/basic_math.h18
-rwxr-xr-xzen/build_info.h3
-rwxr-xr-xzen/dir_watcher.cpp22
-rwxr-xr-xzen/dir_watcher.h13
-rwxr-xr-xzen/error_log.h29
-rwxr-xr-xzen/file_access.h1
-rwxr-xr-xzen/file_error.h1
-rwxr-xr-xzen/file_id_def.h2
-rwxr-xr-xzen/file_io.h2
-rwxr-xr-xzen/file_traverser.cpp2
-rwxr-xr-xzen/file_traverser.h6
-rwxr-xr-xzen/fixed_list.h1
-rwxr-xr-xzen/format_unit.cpp7
-rwxr-xr-xzen/format_unit.h4
-rwxr-xr-xzen/globals.h1
-rwxr-xr-xzen/i18n.h7
-rwxr-xr-xzen/optional.h1
-rwxr-xr-xzen/process_priority.h1
-rwxr-xr-xzen/scope_guard.h2
-rwxr-xr-xzen/shell_execute.h8
-rwxr-xr-xzen/shutdown.cpp4
-rwxr-xr-xzen/shutdown.h1
-rwxr-xr-xzen/string_base.h2
-rwxr-xr-xzen/string_tools.h12
-rwxr-xr-xzen/string_traits.h16
-rwxr-xr-xzen/thread.h2
-rwxr-xr-xzen/time.h199
-rwxr-xr-xzen/utf.h13
-rwxr-xr-xzen/xml_io.h2
-rwxr-xr-xzen/zstring.cpp11
-rwxr-xr-xzenXml/zenxml/bind.h55
-rwxr-xr-xzenXml/zenxml/cvrt_struc.h8
-rwxr-xr-xzenXml/zenxml/cvrt_text.h1
-rwxr-xr-xzenXml/zenxml/dom.h111
-rwxr-xr-xzenXml/zenxml/io.h1
-rwxr-xr-xzenXml/zenxml/parser.h22
-rwxr-xr-xzenXml/zenxml/xml.h1
178 files changed, 3205 insertions, 2725 deletions
diff --git a/Changelog.txt b/Changelog.txt
index 60be1b62..b5f6d52c 100755
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,21 @@
+FreeFileSync 9.8 [2018-02-06]
+-----------------------------
+New option to auto-close progress dialog
+Update last sync time if no differences found
+Added 5 seconds countdown before shutdown/sleep
+Preserve XML attribute creation order
+Support HTTPS web accesses without redirect
+Connect network share upon logon type not granted
+Fixed invalid pointer error when reading MTP
+Fixed temporary db file triggering RealTimeSync
+Fixed runtime error during uninstallation
+Continue status updates during sync cancellation
+Log number of items found during comparison
+Warn about outdated nviewH64.dll instead of crashing
+Show default log file path when saving a batch job
+Consider only full days for time since last sync
+
+
FreeFileSync 9.7 [2018-01-12]
-----------------------------
New configuration management panel
diff --git a/FreeFileSync/Build/Help/html/schedule-a-batch-job.html b/FreeFileSync/Build/Help/html/schedule-a-batch-job.html
index 200df6e0..fa9a1e2d 100755
--- a/FreeFileSync/Build/Help/html/schedule-a-batch-job.html
+++ b/FreeFileSync/Build/Help/html/schedule-a-batch-job.html
@@ -18,7 +18,7 @@
<li>By default, FreeFileSync will show a progress dialog during synchronization and will wait while the summary dialog is shown.
If the progress dialog is not needed, enable checkbox <b>Run minimized</b> and
- also set <i>When finished</i> to <b>Exit</b> if you want to skip the summary dialog at the end.
+ also set <b>Auto-Close</b> if you want to skip the summary dialog at the end.
<br><br>
<div class="bluebox">
diff --git a/FreeFileSync/Build/Help/images/setup-batch-job.png b/FreeFileSync/Build/Help/images/setup-batch-job.png
index 76a27a12..1982a66b 100755
--- a/FreeFileSync/Build/Help/images/setup-batch-job.png
+++ b/FreeFileSync/Build/Help/images/setup-batch-job.png
Binary files differ
diff --git a/FreeFileSync/Build/Languages/bulgarian.lng b/FreeFileSync/Build/Languages/bulgarian.lng
index e82f9a12..2f34bbf0 100755
--- a/FreeFileSync/Build/Languages/bulgarian.lng
+++ b/FreeFileSync/Build/Languages/bulgarian.lng
@@ -7,6 +7,9 @@
<plural_definition>n == 1 ? 0 : 1</plural_definition>
</header>
+<source>Cannot set directory locks for the following folders:</source>
+<target></target>
+
<source>Both sides have changed since last synchronization.</source>
<target>Двете страни са променени след последната синхронизация.</target>
@@ -53,17 +56,20 @@
<target>Проверява достъпността на кошчето за папка %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>Кошчето не се поддържа от следните папки. Изтритите или презаписани файлове няма да могат да се възстановяват:</target>
+<target>Кошчето не се поддържа за следните папки. Изтритите или презаписани файлове няма да могат да се възстановяват:</target>
<source>An exception occurred</source>
<target>Възникна изключение</target>
<source>A directory path is expected after %x.</source>
-<target>Очаква път до директорията след %x.</target>
+<target>Очаква се път до директория след %x.</target>
<source>Syntax error</source>
<target>Синтактична грешка</target>
+<source>A left and a right directory path are expected after %x.</source>
+<target>Очаква се път до лява и дясна директория след %x.</target>
+
<source>Cannot find file %x.</source>
<target>Не е намерен файл %x.</target>
@@ -456,9 +462,6 @@ Actual: %y bytes
<source>Error parsing file %x, row %y, column %z.</source>
<target>Грешка при анализ на файл %x, ред %y, колона %z.</target>
-<source>Cannot set directory lock for %x.</source>
-<target>Не може да заключи директорията за %x.</target>
-
<source>
<pluralform>1 thread</pluralform>
<pluralform>%x threads</pluralform>
@@ -797,6 +800,27 @@ The command is triggered if:
<source>Serious Error</source>
<target>Сериозна грешка</target>
+<source>Last session</source>
+<target>Последна сесия</target>
+
+<source>Today</source>
+<target>Днес</target>
+
+<source>
+<pluralform>1 day</pluralform>
+<pluralform>%x days</pluralform>
+</source>
+<target>
+<pluralform>1 ден</pluralform>
+<pluralform>%x дена</pluralform>
+</target>
+
+<source>Name</source>
+<target>Име</target>
+
+<source>Last sync</source>
+<target>Последна синхронизация</target>
+
<source>Folder</source>
<target>Папка</target>
@@ -1324,6 +1348,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Activate offline</source>
<target>Активирайте офлайн</target>
+<source>Highlight configurations that have not been run for more than the following number of days:</source>
+<target>Маркирай конфигурациите, които не са изпълнявани в течение на повече от следния брой дни:</target>
+
<source>Save as a Batch Job</source>
<target>Запази като пакетна задача</target>
@@ -1342,6 +1369,9 @@ This guarantees a consistent state even in case of a serious error.
<source>FreeFileSync Donation Edition</source>
<target>FreeFileSync-Дарителско-Издание</target>
+<source>Highlight Configurations</source>
+<target>Маркирай конфигурациите</target>
+
<source>&Options</source>
<target>&Опции</target>
@@ -1465,9 +1495,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Select time span...</source>
<target>Избор на времеви интервал...</target>
-<source>Last session</source>
-<target>Последна сесия</target>
-
<source>Folder Comparison and Synchronization</source>
<target>Сравняване и синхронизация на папки</target>
@@ -1486,8 +1513,11 @@ This guarantees a consistent state even in case of a serious error.
<source>Do&n't save</source>
<target>&Не запазвай</target>
-<source>Remove entry from list</source>
-<target>Премахни позицията от списъка</target>
+<source>Hide configuration</source>
+<target>Скрий конфигурацията</target>
+
+<source>Highlight...</source>
+<target>Маркирай...</target>
<source>Clear filter</source>
<target>Изчисти филтъра</target>
@@ -1499,16 +1529,16 @@ This guarantees a consistent state even in case of a serious error.
<target>Покажи файловете, съществуващи само отдясно</target>
<source>Show files that are newer on left</source>
-<target>Покажи по-новите файлове отляво</target>
+<target>Покажи файловете от двете страни; файлът отляво е по-нов</target>
<source>Show files that are newer on right</source>
-<target>Покажи по-новите файлове отдясно</target>
+<target>Покажи файловете от двете страни; файлът отдясно е по-нов</target>
<source>Show files that are equal</source>
<target>Покажи еднаквите файлове</target>
<source>Show files that are different</source>
-<target>Покажи различаващите се файлове</target>
+<target>Покажи нееднаквите файлове</target>
<source>Show conflicts</source>
<target>Покажи конфликтите</target>
@@ -1562,7 +1592,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>
@@ -1571,7 +1601,7 @@ This guarantees a consistent state even in case of a serious error.
<target>Инициализация...</target>
<source>Scanning...</source>
-<target>Търсене на файлове...</target>
+<target>Търси файлове...</target>
<source>Comparing content...</source>
<target>Сравнява съдържанието на файлове...</target>
@@ -1699,9 +1729,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Synchronization</source>
<target>Синхронизиране</target>
-<source>Today</source>
-<target>Днес</target>
-
<source>This week</source>
<target>Тази седмица</target>
@@ -1771,9 +1798,6 @@ This guarantees a consistent state even in case of a serious error.
<source>Files</source>
<target>Файлове</target>
-<source>Name</source>
-<target>Име</target>
-
<source>Percentage</source>
<target>Процент</target>
@@ -1885,15 +1909,6 @@ This guarantees a consistent state even in case of a serious error.
<pluralform>%x часа</pluralform>
</target>
-<source>
-<pluralform>1 day</pluralform>
-<pluralform>%x days</pluralform>
-</source>
-<target>
-<pluralform>1 ден</pluralform>
-<pluralform>%x дена</pluralform>
-</target>
-
<source>Cannot set privilege %x.</source>
<target>Не може да зададе привилегията %x.</target>
@@ -1960,6 +1975,9 @@ This guarantees a consistent state even in case of a serious error.
<source>Start menu</source>
<target>В стартовото меню</target>
+<source>Send To</source>
+<target>Изпрати до</target>
+
<source>Registering FreeFileSync file extensions</source>
<target>Регистриране на файлови разширения за FreeFileSync</target>
@@ -1987,6 +2005,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 silent installation mode is only available in the FreeFileSync Donation Edition.</source>
-<target>Режим на мълчаливо инсталиране е възможен само за FreeFileSync-Дарителско-Издание.</target>
+<source>The %x installation option is only available in the FreeFileSync Donation Edition.</source>
+<target>Опцията %x инсталиране е възможна само за FreeFileSync-ДарителскоИздание.</target>
diff --git a/FreeFileSync/Build/Languages/german.lng b/FreeFileSync/Build/Languages/german.lng
index acc4da40..1a0b13f9 100755
--- a/FreeFileSync/Build/Languages/german.lng
+++ b/FreeFileSync/Build/Languages/german.lng
@@ -118,6 +118,18 @@
<source>If this error is ignored the folders will be considered empty. Missing folders are created automatically when needed.</source>
<target>Wird dieser Fehler ignoriert, werden die Ordner als leer angesehen. Fehlende Ordner werden bei Bedarf automatisch erstellt.</target>
+<source>Comparison finished:</source>
+<target>Vergleich abgeschlossen:</target>
+
+<source>
+<pluralform>1 item found</pluralform>
+<pluralform>%x items found</pluralform>
+</source>
+<target>
+<pluralform>1 Element gefunden</pluralform>
+<pluralform>%x Elemente gefunden</pluralform>
+</target>
+
<source>File %x has an invalid date.</source>
<target>Die Datei %x hat ein ungültiges Datum.</target>
@@ -178,9 +190,6 @@
<source>Using non-default global settings:</source>
<target>Nicht dem Standard entsprechende globale Einstellungen:</target>
-<source>Starting comparison</source>
-<target>Starte Vergleich</target>
-
<source>A folder input field is empty.</source>
<target>Ein Ordnereingabefeld ist leer.</target>
@@ -321,15 +330,15 @@ Tatsächlich: %y bytes
<source>Unable to move %x to the recycle bin.</source>
<target>%x kann nicht in den Papierkorb verschoben werden.</target>
+<source>Cannot find %x.</source>
+<target>%x wurde nicht gefunden.</target>
+
<source>Cannot open file %x.</source>
<target>Die Datei %x kann nicht geöffnet werden.</target>
<source>Cannot find device %x.</source>
<target>Das Gerät %x wurde nicht gefunden.</target>
-<source>Cannot find %x.</source>
-<target>%x wurde nicht gefunden.</target>
-
<source>Type of item %x is not supported:</source>
<target>Der Typ des Elements %x wird nicht unterstützt:</target>
@@ -435,6 +444,9 @@ Tatsächlich: %y bytes
<source>Lock owner:</source>
<target>Sperreigentümer:</target>
+<source>Detecting abandoned lock...</source>
+<target>Ermittle aufgegebene Sperre...</target>
+
<source>
<pluralform>1 sec</pluralform>
<pluralform>%x sec</pluralform>
@@ -444,9 +456,6 @@ Tatsächlich: %y bytes
<pluralform>%x Sek.</pluralform>
</target>
-<source>Detecting abandoned lock...</source>
-<target>Ermittle aufgegebene Sperre...</target>
-
<source>Items processed:</source>
<target>Verarbeitete Elemente:</target>
@@ -501,9 +510,6 @@ Tatsächlich: %y bytes
<source>Volume name %x is not part of file path %y.</source>
<target>Laufwerksname %x ist kein Teil des Dateipfades %y.</target>
-<source>Stop requested: Waiting for current operation to finish...</source>
-<target>Unterbrechung wurde eingeleitet: Warte bis der aktuelle Vorgang beendet ist...</target>
-
<source>Unable to create time stamp for versioning:</source>
<target>Der Zeitstempel für die Versionierung kann nicht erstellt werden:</target>
@@ -516,6 +522,9 @@ Tatsächlich: %y bytes
<source>Select a folder</source>
<target>Ordner auswählen</target>
+<source>&New</source>
+<target>&Neu</target>
+
<source>&Open...</source>
<target>Ö&ffnen...</target>
@@ -731,26 +740,23 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>job name</source>
<target>Auftragsname</target>
-<source>Show summary</source>
-<target>Zusammenfassung zeigen</target>
+<source>System: Sleep</source>
+<target>System: Energie sparen</target>
-<source>Sleep</source>
-<target>Energie sparen</target>
+<source>System: Shut down</source>
+<target>System: Herunterfahren</target>
-<source>Shut down</source>
-<target>Herunterfahren</target>
-
-<source>Synchronization stopped</source>
-<target>Synchronisation unterbrochen</target>
+<source>Cleaning up old log files...</source>
+<target>Bereinige alte Protokolldateien...</target>
<source>Stopped</source>
-<target>Unterbrochen</target>
+<target>Gestoppt</target>
-<source>Synchronization completed with errors</source>
-<target>Synchronisation mit Fehlern abgeschlossen</target>
+<source>Completed with errors</source>
+<target>Mit Fehlern abgeschlossen</target>
-<source>Synchronization completed with warnings</source>
-<target>Synchronisation mit Warnungen abgeschlossen</target>
+<source>Completed with warnings</source>
+<target>Mit Warnungen abgeschlossen</target>
<source>Warning</source>
<target>Warnung</target>
@@ -758,15 +764,12 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Nothing to synchronize</source>
<target>Es gibt nichts zu synchronisieren</target>
-<source>Synchronization completed successfully</source>
-<target>Synchronisation erfolgreich abgeschlossen</target>
+<source>Completed</source>
+<target>Fertig</target>
<source>Executing command %x</source>
<target>Führe Befehl aus: %x</target>
-<source>Cleaning up old log files...</source>
-<target>Bereinige alte Protokolldateien...</target>
-
<source>You can switch to FreeFileSync's main window to resolve this issue.</source>
<target>Sie können auf FreeFileSyncs Hauptfenster wechseln, um das Problem zu beheben.</target>
@@ -782,14 +785,8 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Switching to FreeFileSync's main window</source>
<target>Wechsle auf FreeFileSyncs Hauptfenster</target>
-<source>
-<pluralform>Automatic retry in 1 second...</pluralform>
-<pluralform>Automatic retry in %x seconds...</pluralform>
-</source>
-<target>
-<pluralform>Automatische Wiederholung in 1 Sekunde...</pluralform>
-<pluralform>Automatische Wiederholung in %x Sekunden...</pluralform>
-</target>
+<source>Automatic retry</source>
+<target>Automatische Wiederholung</target>
<source>Ignore &all</source>
<target>&Alle ignorieren</target>
@@ -884,9 +881,6 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Please select a folder on a local file system, network or an MTP device.</source>
<target>Bitte wählen Sie einen Ordner auf einem lokalen Dateisystem, Netzwerk oder MTP Gerät.</target>
-<source>&New</source>
-<target>&Neu</target>
-
<source>&Save</source>
<target>&Speichern</target>
@@ -1207,6 +1201,9 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>When finished:</source>
<target>Am Ende:</target>
+<source>Auto-Close</source>
+<target>Automatisch schließen</target>
+
<source>Close</source>
<target>Schließen</target>
@@ -1219,6 +1216,9 @@ Die Befehlszeile wird ausgelöst, wenn:
<source>Create a batch file for unattended synchronization. To start, double-click this file or schedule in a task planner: %x</source>
<target>Erstellt eine Batchdatei für die unbeaufsichtigte Synchronisation. Zum Starten die Datei doppelklicken oder in einen Taskplaner eintragen: %x</target>
+<source>Progress dialog:</source>
+<target>Fortschrittsdialog:</target>
+
<source>Run minimized</source>
<target>Minimiert ausführen</target>
@@ -1229,7 +1229,7 @@ Die Befehlszeile wird ausgelöst, wenn:
<target>&Abbrechen</target>
<source>Stop synchronization at first error</source>
-<target>Synchronisation beim ersten Fehler unterbrechen</target>
+<target>Synchronisation beim ersten Fehler stoppen</target>
<source>Save log:</source>
<target>Protokoll speichern:</target>
@@ -1597,6 +1597,9 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Paused</source>
<target>Angehalten</target>
+<source>Stop requested...</source>
+<target>Wird gestoppt...</target>
+
<source>Initializing...</source>
<target>Initialisiere...</target>
@@ -1606,9 +1609,6 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Comparing content...</source>
<target>Vergleiche Dateiinhalt...</target>
-<source>Completed</source>
-<target>Fertig</target>
-
<source>Info</source>
<target>Info</target>
@@ -1619,7 +1619,7 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<target>&Fortfahren</target>
<source>Progress</source>
-<target>Verlauf</target>
+<target>Fortschritt</target>
<source>Log</source>
<target>Protokoll</target>
@@ -1690,12 +1690,6 @@ Dadurch wird ein konsistenter Datenstand auch bei schweren Fehlern garantiert.
<source>Parameters for opposite side</source>
<target>Parameter für gegenüberliegende Seite</target>
-<source>Show hidden dialogs and warning messages again?</source>
-<target>Sollen versteckte Fenster und Warnmeldungen wieder gezeigt werden?</target>
-
-<source>&Show</source>
-<target>&Zeigen</target>
-
<source>Downloading update...</source>
<target>Lade Aktualisierung...</target>
diff --git a/FreeFileSync/Source/RealTimeSync/application.cpp b/FreeFileSync/Source/RealTimeSync/application.cpp
index e4cfc530..5559fcf9 100755
--- a/FreeFileSync/Source/RealTimeSync/application.cpp
+++ b/FreeFileSync/Source/RealTimeSync/application.cpp
@@ -24,6 +24,7 @@
#include <gtk/gtk.h>
using namespace zen;
+using namespace rts;
IMPLEMENT_APP(Application);
@@ -40,7 +41,7 @@ bool Application::OnInit()
{
//do not call wxApp::OnInit() to avoid using wxWidgets command line parser
- ::gtk_rc_parse((zen::getResourceDirPf() + "styles.gtk_rc").c_str()); //remove inner border from bitmap buttons
+ ::gtk_rc_parse((fff::getResourceDirPf() + "styles.gtk_rc").c_str()); //remove inner border from bitmap buttons
//Windows User Experience Interaction Guidelines: tool tips should have 5s timeout, info tips no timeout => compromise:
wxToolTip::Enable(true); //yawn, a wxWidgets screw-up: wxToolTip::SetAutoPop is no-op if global tooltip window is not yet constructed: wxToolTip::Enable creates it
@@ -48,11 +49,11 @@ bool Application::OnInit()
SetAppName(L"RealTimeSync");
- initResourceImages(getResourceDirPf() + Zstr("Resources.zip"));
+ initResourceImages(fff::getResourceDirPf() + Zstr("Resources.zip"));
try
{
- setLanguage(xmlAccess::getProgramLanguage()); //throw FileError
+ fff::setLanguage(getProgramLanguage()); //throw FileError
}
catch (const FileError& e)
{
@@ -75,8 +76,8 @@ bool Application::OnInit()
int Application::OnExit()
{
- uninitializeHelp();
- releaseWxLocale();
+ fff::uninitializeHelp();
+ fff::releaseWxLocale();
cleanupResourceImages();
return wxApp::OnExit();
}
@@ -90,7 +91,7 @@ void Application::onEnterEventLoop(wxEvent& event)
std::vector<Zstring> commandArgs;
for (int i = 1; i < argc; ++i)
{
- Zstring filePath = getResolvedFilePath(utfTo<Zstring>(argv[i]));
+ Zstring filePath = fff::getResolvedFilePath(utfTo<Zstring>(argv[i]));
if (!fileAvailable(filePath)) //be a little tolerant
{
@@ -123,15 +124,15 @@ int Application::OnRun()
}
catch (const std::bad_alloc& e) //the only kind of exception we don't want crash dumps for
{
- logFatalError(e.what()); //it's not always possible to display a message box, e.g. corrupted stack, however low-level file output works!
+ fff::logFatalError(e.what()); //it's not always possible to display a message box, e.g. corrupted stack, however low-level file output works!
const auto title = copyStringTo<std::wstring>(wxTheApp->GetAppDisplayName()) + SPACED_DASH + _("An exception occurred");
wxSafeShowMessage(title, e.what());
- return FFS_RC_EXCEPTION;
+ return fff::FFS_RC_EXCEPTION;
}
//catch (...) -> let it crash and create mini dump!!!
- return FFS_RC_SUCCESS; //program's return code
+ return fff::FFS_RC_SUCCESS; //program's return code
}
diff --git a/FreeFileSync/Source/RealTimeSync/application.h b/FreeFileSync/Source/RealTimeSync/application.h
index b4228c50..338a15e1 100755
--- a/FreeFileSync/Source/RealTimeSync/application.h
+++ b/FreeFileSync/Source/RealTimeSync/application.h
@@ -10,6 +10,8 @@
#include <wx/app.h>
+namespace rts
+{
class Application : public wxApp
{
public:
@@ -24,5 +26,6 @@ private:
void onEnterEventLoop(wxEvent& event);
//wxLayoutDirection GetLayoutDirection() const override { return wxLayout_LeftToRight; }
};
+}
#endif //APPLICATION_H_18506781708176342677
diff --git a/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp b/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
index fce01000..f83eebb7 100755
--- a/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
+++ b/FreeFileSync/Source/RealTimeSync/folder_selector2.cpp
@@ -16,6 +16,7 @@
using namespace zen;
+using namespace rts;
namespace
@@ -25,7 +26,7 @@ void setFolderPath(const Zstring& dirpath, wxTextCtrl* txtCtrl, wxWindow& toolti
if (txtCtrl)
txtCtrl->ChangeValue(utfTo<wxString>(dirpath));
- const Zstring folderPathFmt = getResolvedFilePath(dirpath); //may block when resolving [<volume name>]
+ 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...
@@ -124,7 +125,7 @@ void FolderSelector2::onSelectDir(wxCommandEvent& event)
//IFileDialog requirements for default path: 1. accepts native paths only!!! 2. path must exist!
Zstring defaultFolderPath;
{
- const Zstring folderPath = getResolvedFilePath(getPath());
+ const Zstring folderPath = fff::getResolvedFilePath(getPath());
if (!folderPath.empty())
{
auto ft = runAsync([folderPath] { return dirAvailable(folderPath); });
diff --git a/FreeFileSync/Source/RealTimeSync/folder_selector2.h b/FreeFileSync/Source/RealTimeSync/folder_selector2.h
index a11567a8..e6af3940 100755
--- a/FreeFileSync/Source/RealTimeSync/folder_selector2.h
+++ b/FreeFileSync/Source/RealTimeSync/folder_selector2.h
@@ -13,7 +13,7 @@
#include <wx/textctrl.h>
#include <wx+/file_drop.h>
-namespace zen
+namespace rts
{
//handle drag and drop, tooltip, label and manual input, coordinating a wxWindow, wxButton, and wxTextCtrl
@@ -32,7 +32,7 @@ public:
private:
void onMouseWheel (wxMouseEvent& event);
- void onFilesDropped (FileDropEvent& event);
+ void onFilesDropped (zen::FileDropEvent& event);
void onEditFolderPath(wxCommandEvent& event);
void onSelectDir (wxCommandEvent& event);
diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
index cc5dbb99..0f62f821 100755
--- a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
+++ b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
@@ -1,8 +1,8 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jun 17 2015)
+// C++ code generated with wxFormBuilder (version Nov 6 2017)
// http://www.wxformbuilder.org/
//
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "wx+/bitmap_button.h"
@@ -18,6 +18,10 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_menubar1 = new wxMenuBar( 0 );
m_menuFile = new wxMenu();
+ wxMenuItem* m_menuItem6;
+ m_menuItem6 = new wxMenuItem( m_menuFile, wxID_NEW, wxString( _("&New") ) + wxT('\t') + wxT("Ctrl+N"), wxEmptyString, wxITEM_NORMAL );
+ m_menuFile->Append( m_menuItem6 );
+
wxMenuItem* m_menuItem13;
m_menuItem13 = new wxMenuItem( m_menuFile, wxID_OPEN, wxString( _("&Open...") ) + wxT('\t') + wxT("CTRL+O"), wxEmptyString, wxITEM_NORMAL );
m_menuFile->Append( m_menuItem13 );
@@ -58,7 +62,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_staticText9 = new wxStaticText( this, wxID_ANY, _("Usage:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText9->Wrap( -1 );
- m_staticText9->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) );
+ m_staticText9->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
bSizer16->Add( m_staticText9, 0, wxALL, 5 );
@@ -144,7 +148,6 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
bSizer19 = new wxBoxSizer( wxHORIZONTAL );
m_txtCtrlDirectoryMain = new wxTextCtrl( m_panelMainFolder, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 300, -1 ), 0 );
- m_txtCtrlDirectoryMain->SetMaxLength( 0 );
bSizer19->Add( m_txtCtrlDirectoryMain, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectFolderMain = new wxButton( m_panelMainFolder, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -205,7 +208,6 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
bSizer141->Add( m_staticText6, 0, wxALL, 5 );
m_textCtrlCommand = new wxTextCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
- m_textCtrlCommand->SetMaxLength( 0 );
m_textCtrlCommand->SetToolTip( _("The command is triggered if:\n- files or subfolders change\n- new folders arrive (e.g. USB stick insert)") );
bSizer141->Add( m_textCtrlCommand, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
@@ -224,7 +226,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_buttonStart = new zen::BitmapTextButton( this, wxID_OK, _("Start"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
m_buttonStart->SetDefault();
- m_buttonStart->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) );
+ m_buttonStart->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
bSizerMain->Add( m_buttonStart, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
@@ -237,6 +239,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDlgGenerated::OnClose ) );
+ this->Connect( m_menuItem6->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigNew ) );
this->Connect( m_menuItem13->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigLoad ) );
this->Connect( m_menuItem14->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigSave ) );
this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuQuit ) );
@@ -264,7 +267,6 @@ FolderGenerated::FolderGenerated( wxWindow* parent, wxWindowID id, const wxPoint
bSizer114->Add( m_bpButtonRemoveFolder, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_txtCtrlDirectory = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
- m_txtCtrlDirectory->SetMaxLength( 0 );
bSizer114->Add( m_txtCtrlDirectory, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectFolder = new wxButton( this, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.h b/FreeFileSync/Source/RealTimeSync/gui_generated.h
index b16f1a97..773d8c5a 100755
--- a/FreeFileSync/Source/RealTimeSync/gui_generated.h
+++ b/FreeFileSync/Source/RealTimeSync/gui_generated.h
@@ -1,8 +1,8 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jun 17 2015)
+// C++ code generated with wxFormBuilder (version Nov 6 2017)
// http://www.wxformbuilder.org/
//
-// PLEASE DO "NOT" EDIT THIS FILE!
+// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __GUI_GENERATED_H__
@@ -77,6 +77,7 @@ protected:
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
+ virtual void OnConfigNew( wxCommandEvent& event ) { event.Skip(); }
virtual void OnConfigLoad( wxCommandEvent& event ) { event.Skip(); }
virtual void OnConfigSave( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuQuit( wxCommandEvent& event ) { event.Skip(); }
diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
index f665c783..c6093389 100755
--- a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
+++ b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
@@ -25,6 +25,7 @@
#include <gtk/gtk.h>
using namespace zen;
+using namespace rts;
namespace
@@ -32,7 +33,7 @@ namespace
}
-class DirectoryPanel : public FolderGenerated
+class rts::DirectoryPanel : public FolderGenerated
{
public:
DirectoryPanel(wxWindow* parent) :
@@ -43,7 +44,7 @@ public:
Zstring getPath() const { return folderSelector_.getPath(); }
private:
- zen::FolderSelector2 folderSelector_;
+ FolderSelector2 folderSelector_;
};
@@ -55,7 +56,7 @@ void MainDialog::create(const Zstring& cfgFile)
MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
: MainDlgGenerated(dlg),
- lastRunConfigPath_(zen::getConfigDirPathPf() + Zstr("LastRun.ffs_real"))
+ lastRunConfigPath_(fff::getConfigDirPathPf() + Zstr("LastRun.ffs_real"))
{
SetIcon(getRtsIcon()); //set application icon
@@ -76,7 +77,7 @@ MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
dirpathFirst = std::make_unique<FolderSelector2>(*m_panelMainFolder, *m_buttonSelectFolderMain, *m_txtCtrlDirectoryMain, m_staticTextFinalPath);
//--------------------------- load config values ------------------------------------
- xmlAccess::XmlRealConfig newConfig;
+ XmlRealConfig newConfig;
Zstring currentConfigFile = cfgFileName;
if (currentConfigFile.empty())
@@ -90,7 +91,7 @@ MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
try
{
std::wstring warningMsg;
- xmlAccess::readRealOrBatchConfig(currentConfigFile, newConfig, warningMsg); //throw FileError
+ readRealOrBatchConfig(currentConfigFile, newConfig, warningMsg); //throw FileError
if (!warningMsg.empty())
showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(warningMsg));
@@ -131,7 +132,7 @@ MainDialog::MainDialog(wxDialog* dlg, const Zstring& cfgFileName)
MainDialog::~MainDialog()
{
//save current configuration
- const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
+ const XmlRealConfig currentCfg = getConfiguration();
try //write config to XML
{
@@ -153,7 +154,7 @@ void MainDialog::onQueryEndSession()
void MainDialog::OnShowHelp(wxCommandEvent& event)
{
- zen::displayHelpEntry(L"realtimesync", this);
+ fff::displayHelpEntry(L"realtimesync", this);
}
@@ -193,9 +194,10 @@ void MainDialog::OnStart(wxCommandEvent& event)
{
Hide();
- xmlAccess::XmlRealConfig currentCfg = getConfiguration();
+ XmlRealConfig currentCfg = getConfiguration();
+ const Zstring activeCfgFilePath = !equalFilePath(activeConfigFile_, lastRunConfigPath_) ? activeConfigFile_ : Zstring();
- switch (rts::startDirectoryMonitor(currentCfg, xmlAccess::extractJobName(utfTo<Zstring>(currentConfigFileName_))))
+ switch (rts::startDirectoryMonitor(currentCfg, fff::extractJobName(activeCfgFilePath)))
{
case rts::EXIT_APP:
Close();
@@ -212,29 +214,29 @@ void MainDialog::OnStart(wxCommandEvent& event)
void MainDialog::OnConfigSave(wxCommandEvent& event)
{
- Zstring defaultFileName = currentConfigFileName_.empty() ? Zstr("Realtime.ffs_real") : currentConfigFileName_;
+ Zstring defaultFilePath = !activeConfigFile_.empty() && !equalFilePath(activeConfigFile_, lastRunConfigPath_) ? activeConfigFile_ : Zstr("Realtime.ffs_real");
//attention: currentConfigFileName may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config!
- if (endsWith(defaultFileName, Zstr(".ffs_batch"), CmpFilePath()))
- defaultFileName = beforeLast(defaultFileName, Zstr("."), IF_MISSING_RETURN_NONE) + Zstr(".ffs_real");
+ if (endsWith(defaultFilePath, Zstr(".ffs_batch"), CmpFilePath()))
+ defaultFilePath = beforeLast(defaultFilePath, Zstr("."), IF_MISSING_RETURN_NONE) + Zstr(".ffs_real");
wxFileDialog filePicker(this,
wxString(),
//OS X really needs dir/file separated like this:
- utfTo<wxString>(beforeLast(defaultFileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
- utfTo<wxString>(afterLast (defaultFileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)), //default file
+ utfTo<wxString>(beforeLast(defaultFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
+ utfTo<wxString>(afterLast (defaultFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)), //default file
wxString(L"RealTimeSync (*.ffs_real)|*.ffs_real") + L"|" +_("All files") + L" (*.*)|*",
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (filePicker.ShowModal() != wxID_OK)
return;
- const Zstring newFileName = utfTo<Zstring>(filePicker.GetPath());
+ const Zstring targetFilePath = utfTo<Zstring>(filePicker.GetPath());
//write config to XML
- const xmlAccess::XmlRealConfig currentCfg = getConfiguration();
+ const XmlRealConfig currentCfg = getConfiguration();
try
{
- writeConfig(currentCfg, newFileName); //throw FileError
- setLastUsedConfig(newFileName);
+ writeConfig(currentCfg, targetFilePath); //throw FileError
+ setLastUsedConfig(targetFilePath);
}
catch (const FileError& e)
{
@@ -245,21 +247,22 @@ void MainDialog::OnConfigSave(wxCommandEvent& event)
void MainDialog::loadConfig(const Zstring& filepath)
{
- xmlAccess::XmlRealConfig newConfig;
+ XmlRealConfig newConfig;
- try
- {
- std::wstring warningMsg;
- xmlAccess::readRealOrBatchConfig(filepath, newConfig, warningMsg); //throw FileError
+ if (!filepath.empty())
+ try
+ {
+ std::wstring warningMsg;
+ readRealOrBatchConfig(filepath, newConfig, warningMsg); //throw FileError
- if (!warningMsg.empty())
- showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(warningMsg));
- }
- catch (const FileError& e)
- {
- showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
- return;
- }
+ if (!warningMsg.empty())
+ showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(warningMsg));
+ }
+ catch (const FileError& e)
+ {
+ showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString()));
+ return;
+ }
setConfiguration(newConfig);
setLastUsedConfig(filepath);
@@ -268,25 +271,31 @@ void MainDialog::loadConfig(const Zstring& filepath)
void MainDialog::setLastUsedConfig(const Zstring& filepath)
{
- //set title
- if (filepath == lastRunConfigPath_)
- {
- SetTitle(wxString(L"RealTimeSync ") + zen::ffsVersion + SPACED_DASH + _("Automated Synchronization"));
- currentConfigFileName_.clear();
- }
+ activeConfigFile_ = filepath;
+
+ const Zstring activeCfgFilePath = !equalFilePath(activeConfigFile_, lastRunConfigPath_) ? activeConfigFile_ : Zstring();
+
+ if (!activeCfgFilePath.empty())
+ SetTitle(utfTo<wxString>(activeCfgFilePath));
else
- {
- SetTitle(utfTo<wxString>(filepath));
- currentConfigFileName_ = filepath;
- }
+ SetTitle(wxString(L"RealTimeSync ") + fff::ffsVersion + SPACED_DASH + _("Automated Synchronization"));
+
+}
+
+
+void MainDialog::OnConfigNew(wxCommandEvent& event)
+{
+ loadConfig({});
}
void MainDialog::OnConfigLoad(wxCommandEvent& event)
{
+ const Zstring activeCfgFilePath = !equalFilePath(activeConfigFile_, lastRunConfigPath_) ? activeConfigFile_ : Zstring();
+
wxFileDialog filePicker(this,
wxString(),
- utfTo<wxString>(beforeLast(currentConfigFileName_, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
+ utfTo<wxString>(beforeLast(activeCfgFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
wxString(), //default file
wxString(L"RealTimeSync (*.ffs_real; *.ffs_batch)|*.ffs_real;*.ffs_batch") + L"|" +_("All files") + L" (*.*)|*",
wxFD_OPEN);
@@ -303,7 +312,7 @@ void MainDialog::onFilesDropped(FileDropEvent& event)
}
-void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg)
+void MainDialog::setConfiguration(const XmlRealConfig& cfg)
{
//clear existing folders
dirpathFirst->setPath(Zstring());
@@ -326,9 +335,9 @@ void MainDialog::setConfiguration(const xmlAccess::XmlRealConfig& cfg)
}
-xmlAccess::XmlRealConfig MainDialog::getConfiguration()
+XmlRealConfig MainDialog::getConfiguration()
{
- xmlAccess::XmlRealConfig output;
+ XmlRealConfig output;
output.directories.push_back(utfTo<Zstring>(dirpathFirst->getPath()));
for (const DirectoryPanel* dne : dirpathsExtra)
diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.h b/FreeFileSync/Source/RealTimeSync/main_dlg.h
index 21decc40..cecf26c8 100755
--- a/FreeFileSync/Source/RealTimeSync/main_dlg.h
+++ b/FreeFileSync/Source/RealTimeSync/main_dlg.h
@@ -17,10 +17,9 @@
#include "folder_selector2.h"
-namespace xmlAccess
+namespace rts
{
struct XmlRealConfig;
-}
class DirectoryPanel;
@@ -45,27 +44,29 @@ private:
void OnRemoveTopFolder(wxCommandEvent& event) override;
void OnKeyPressed (wxKeyEvent& event);
void OnStart (wxCommandEvent& event) override;
+ void OnConfigNew (wxCommandEvent& event) override;
void OnConfigSave (wxCommandEvent& event) override;
void OnConfigLoad (wxCommandEvent& event) override;
void OnMenuQuit (wxCommandEvent& event) override { Close(); }
void onFilesDropped(zen::FileDropEvent& event);
- void setConfiguration(const xmlAccess::XmlRealConfig& cfg);
- xmlAccess::XmlRealConfig getConfiguration();
+ void setConfiguration(const XmlRealConfig& cfg);
+ XmlRealConfig getConfiguration();
void setLastUsedConfig(const Zstring& filepath);
void addFolder(const std::vector<Zstring>& newFolders, bool addFront = false);
void removeAddFolder(size_t pos);
void clearAddFolders();
- std::unique_ptr<zen::FolderSelector2> dirpathFirst;
+ std::unique_ptr<FolderSelector2> dirpathFirst;
std::vector<DirectoryPanel*> dirpathsExtra; //additional pairs to the standard pair
const Zstring lastRunConfigPath_;
- Zstring currentConfigFileName_;
+ Zstring activeConfigFile_;
zen::AsyncGuiQueue guiQueue_; //schedule and run long-running tasks asynchronously, but process results on GUI queue
};
+}
#endif //MAIN_DLG_H_2384790842252445
diff --git a/FreeFileSync/Source/RealTimeSync/monitor.cpp b/FreeFileSync/Source/RealTimeSync/monitor.cpp
index 54f5ae65..8f0f5c18 100755
--- a/FreeFileSync/Source/RealTimeSync/monitor.cpp
+++ b/FreeFileSync/Source/RealTimeSync/monitor.cpp
@@ -10,7 +10,6 @@
#include <zen/file_access.h>
#include <zen/dir_watcher.h>
#include <zen/thread.h>
-//#include <zen/tick_count.h>
#include <zen/basic_math.h>
#include <wx/utils.h>
#include "../lib/resolve_path.h"
@@ -23,7 +22,7 @@ using namespace zen;
namespace
{
-const int FOLDER_EXISTENCE_CHECK_INTERVAL_SEC = 1; //unit: [s]
+const std::chrono::seconds FOLDER_EXISTENCE_CHECK_INTERVAL(1);
std::vector<Zstring> getFormattedDirs(const std::vector<Zstring>& folderPathPhrases) //throw FileError
@@ -42,7 +41,7 @@ std::vector<Zstring> getFormattedDirs(const std::vector<Zstring>& folderPathPhra
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(getResolvedFilePath(phrase));
+ folderPaths.insert(fff::getResolvedFilePath(phrase));
}
return { folderPaths.begin(), folderPaths.end() };
@@ -68,7 +67,7 @@ struct WaitResult
WaitResult waitForChanges(const std::vector<Zstring>& folderPathPhrases, //throw FileError
- const std::function<void(bool readyForSync)>& onRefreshGui)
+ const std::function<void(bool readyForSync)>& requestUiRefresh, std::chrono::milliseconds cbInterval)
{
const std::vector<Zstring> folderPaths = getFormattedDirs(folderPathPhrases); //throw FileError
if (folderPaths.empty()) //pathological case, but we have to check else this function will wait endlessly
@@ -84,8 +83,8 @@ WaitResult waitForChanges(const std::vector<Zstring>& folderPathPhrases, //throw
//a non-existent network path may block, so check existence asynchronously!
auto ftDirAvailable = runAsync([=] { return dirAvailable(folderPath); });
- while (ftDirAvailable.wait_for(std::chrono::milliseconds(rts::UI_UPDATE_INTERVAL_MS / 2)) != std::future_status::ready)
- onRefreshGui(false /*readyForSync*/); //may throw!
+ while (ftDirAvailable.wait_for(cbInterval) != std::future_status::ready)
+ if (requestUiRefresh) requestUiRefresh(false /*readyForSync*/); //throw X
if (!ftDirAvailable.get()) //folder not existing or can't access
return WaitResult(folderPath);
@@ -107,7 +106,7 @@ WaitResult waitForChanges(const std::vector<Zstring>& folderPathPhrases, //throw
{
const auto now = std::chrono::steady_clock::now();
- if (numeric::dist(now, lastCheckTime) > std::chrono::seconds(FOLDER_EXISTENCE_CHECK_INTERVAL_SEC)) //handle potential chrono wrap-around!
+ if (numeric::dist(now, lastCheckTime) > FOLDER_EXISTENCE_CHECK_INTERVAL) //handle potential chrono wrap-around!
{
lastCheckTime = now;
return true;
@@ -127,15 +126,16 @@ WaitResult waitForChanges(const std::vector<Zstring>& folderPathPhrases, //throw
return WaitResult(folderPath);
try
{
- std::vector<DirWatcher::Entry> changedItems = watcher.getChanges([&] { onRefreshGui(false /*readyForSync*/); /*may throw!*/ }); //throw FileError
+ std::vector<DirWatcher::Entry> changedItems = watcher.getChanges([&] { requestUiRefresh(false /*readyForSync*/); /*throw X*/ },
+ cbInterval); //throw FileError
//remove to be ignored changes
erase_if(changedItems, [](const DirWatcher::Entry& e)
{
return
- //endsWith(e.filepath_, Zstr(".ffs_tmp")) ||
- endsWith(e.filepath_, Zstr(".ffs_lock")) || //sync.ffs_lock, sync.Del.ffs_lock
- endsWith(e.filepath_, Zstr(".ffs_db")); //sync.ffs_db, .sync.tmp.ffs_db
+ endsWith(e.filePath, Zstr(".ffs_tmp")) || //sync.8ea2.ffs_tmp
+ endsWith(e.filePath, Zstr(".ffs_lock")) || //sync.ffs_lock, sync.Del.ffs_lock
+ endsWith(e.filePath, Zstr(".ffs_db")); //sync.ffs_db
//no need to ignore temporary recycle bin directory: this must be caused by a file deletion anyway
});
@@ -150,15 +150,15 @@ WaitResult waitForChanges(const std::vector<Zstring>& folderPathPhrases, //throw
}
}
- std::this_thread::sleep_for(std::chrono::milliseconds(rts::UI_UPDATE_INTERVAL_MS / 2));
- onRefreshGui(true /*readyForSync*/); //throw ?: may start sync at this presumably idle time
+ std::this_thread::sleep_for(cbInterval);
+ requestUiRefresh(true /*readyForSync*/); //throw X: may start sync at this presumably idle time
}
}
//wait until all directories become available (again) + logs in network share
void waitForMissingDirs(const std::vector<Zstring>& folderPathPhrases, //throw FileError
- const std::function<void(const Zstring& folderPath)>& onRefreshGui)
+ const std::function<void(const Zstring& folderPath)>& requestUiRefresh, std::chrono::milliseconds cbInterval)
{
for (;;)
{
@@ -171,19 +171,18 @@ void waitForMissingDirs(const std::vector<Zstring>& folderPathPhrases, //throw F
//2. check dir availability
return dirAvailable(folderPath);
});
- while (ftDirAvailable.wait_for(std::chrono::milliseconds(rts::UI_UPDATE_INTERVAL_MS / 2)) != std::future_status::ready)
- onRefreshGui(folderPath); //may throw!
+ while (ftDirAvailable.wait_for(cbInterval) != std::future_status::ready)
+ if (requestUiRefresh) requestUiRefresh(folderPath); //throw X
if (!ftDirAvailable.get())
{
allAvailable = false;
//wait some time...
- const int refreshInterval = rts::UI_UPDATE_INTERVAL_MS / 2;
- static_assert(FOLDER_EXISTENCE_CHECK_INTERVAL_SEC * 1000 % refreshInterval == 0, "");
- for (int i = 0; i < FOLDER_EXISTENCE_CHECK_INTERVAL_SEC * 1000 / refreshInterval; ++i)
+ 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())
{
- onRefreshGui(folderPath); //may throw!
- std::this_thread::sleep_for(std::chrono::milliseconds(refreshInterval));
+ if (requestUiRefresh) requestUiRefresh(folderPath); //throw X
+ std::this_thread::sleep_for(cbInterval);
}
break;
}
@@ -213,7 +212,7 @@ struct ExecCommandNowException {};
}
-void rts::monitorDirectories(const std::vector<Zstring>& folderPathPhrases, unsigned int delay, rts::MonitorCallback& callback)
+void rts::monitorDirectories(const std::vector<Zstring>& folderPathPhrases, size_t delay, MonitorCallback& cb, std::chrono::milliseconds cbInterval)
{
if (folderPathPhrases.empty())
{
@@ -223,12 +222,12 @@ void rts::monitorDirectories(const std::vector<Zstring>& folderPathPhrases, unsi
auto execMonitoring = [&] //throw FileError
{
- callback.setPhase(MonitorCallback::MONITOR_PHASE_WAITING);
- waitForMissingDirs(folderPathPhrases, [&](const Zstring& folderPath) { callback.requestUiRefresh(); }); //throw FileError
- callback.setPhase(MonitorCallback::MONITOR_PHASE_ACTIVE);
+ cb.setPhase(MonitorCallback::MONITOR_PHASE_WAITING);
+ waitForMissingDirs(folderPathPhrases, [&](const Zstring& folderPath) { cb.requestUiRefresh(); }, cbInterval); //throw FileError
+ cb.setPhase(MonitorCallback::MONITOR_PHASE_ACTIVE);
//schedule initial execution (*after* all directories have arrived, which could take some time which we don't want to include)
- time_t nextExecDate = std::time(nullptr) + delay;
+ time_t nextExecTime = std::time(nullptr) + delay;
for (;;) //loop over command invocations
{
@@ -241,33 +240,33 @@ void rts::monitorDirectories(const std::vector<Zstring>& folderPathPhrases, unsi
WaitResult res = waitForChanges(folderPathPhrases, [&](bool readyForSync) //throw FileError, ExecCommandNowException
{
if (readyForSync)
- if (nextExecDate <= std::time(nullptr))
+ if (nextExecTime <= std::time(nullptr))
throw ExecCommandNowException(); //abort wait and start sync
- callback.requestUiRefresh();
- });
+ cb.requestUiRefresh();
+ }, cbInterval);
switch (res.type)
{
case WaitResult::CHANGE_DIR_UNAVAILABLE: //don't execute the command before all directories are available!
- callback.setPhase(MonitorCallback::MONITOR_PHASE_WAITING);
- waitForMissingDirs(folderPathPhrases, [&](const Zstring& folderPath) { callback.requestUiRefresh(); }); //throw FileError
- callback.setPhase(MonitorCallback::MONITOR_PHASE_ACTIVE);
+ cb.setPhase(MonitorCallback::MONITOR_PHASE_WAITING);
+ waitForMissingDirs(folderPathPhrases, [&](const Zstring& folderPath) { cb.requestUiRefresh(); }, cbInterval); //throw FileError
+ cb.setPhase(MonitorCallback::MONITOR_PHASE_ACTIVE);
break;
case WaitResult::CHANGE_DETECTED:
lastChangeDetected = res.changedItem_;
break;
}
- nextExecDate = std::time(nullptr) + delay;
+ nextExecTime = std::time(nullptr) + delay;
}
}
catch (ExecCommandNowException&) {}
- ::wxSetEnv(L"change_path", utfTo<wxString>(lastChangeDetected.filepath_)); //some way to output what file changed to the user
- ::wxSetEnv(L"change_action", toString(lastChangeDetected.action_)); //
+ ::wxSetEnv(L"change_path", utfTo<wxString>(lastChangeDetected.filePath)); //some way to output what file changed to the user
+ ::wxSetEnv(L"change_action", toString(lastChangeDetected.action)); //
//execute command
- callback.executeExternalCommand();
- nextExecDate = std::numeric_limits<time_t>::max();
+ cb.executeExternalCommand();
+ nextExecTime = std::numeric_limits<time_t>::max();
}
};
@@ -278,6 +277,6 @@ void rts::monitorDirectories(const std::vector<Zstring>& folderPathPhrases, unsi
}
catch (const FileError& e)
{
- callback.reportError(e.toString());
+ cb.reportError(e.toString());
}
}
diff --git a/FreeFileSync/Source/RealTimeSync/monitor.h b/FreeFileSync/Source/RealTimeSync/monitor.h
index c8809998..70b6ff84 100755
--- a/FreeFileSync/Source/RealTimeSync/monitor.h
+++ b/FreeFileSync/Source/RealTimeSync/monitor.h
@@ -7,15 +7,13 @@
#ifndef MONITOR_H_345087425834253425
#define MONITOR_H_345087425834253425
+#include <chrono>
#include <functional>
#include <zen/zstring.h>
namespace rts
{
-const int UI_UPDATE_INTERVAL_MS = 100; //unit: [ms]; perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
-
-
struct MonitorCallback
{
virtual ~MonitorCallback() {}
@@ -32,8 +30,8 @@ struct MonitorCallback
};
void monitorDirectories(const std::vector<Zstring>& folderPathPhrases,
//non-formatted dirnames that yet require call to getFormattedDirectoryName(); empty directories must be checked by caller!
- unsigned int delay,
- MonitorCallback& callback);
+ size_t delay,
+ MonitorCallback& cb, std::chrono::milliseconds cbInterval);
}
#endif //MONITOR_H_345087425834253425
diff --git a/FreeFileSync/Source/RealTimeSync/tray_menu.cpp b/FreeFileSync/Source/RealTimeSync/tray_menu.cpp
index ec2185d3..dd697d1f 100755
--- a/FreeFileSync/Source/RealTimeSync/tray_menu.cpp
+++ b/FreeFileSync/Source/RealTimeSync/tray_menu.cpp
@@ -19,13 +19,15 @@
#include "monitor.h"
#include "../lib/resolve_path.h"
-using namespace rts;
using namespace zen;
+using namespace rts;
namespace
{
-const int RETRY_AFTER_ERROR_INTERVAL_SEC = 15; //unit: [s]
+const std::chrono::seconds RETRY_AFTER_ERROR_INTERVAL(15);
+const std::chrono::milliseconds UI_UPDATE_INTERVAL(100); //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
+
std::chrono::steady_clock::time_point lastExec;
@@ -34,7 +36,7 @@ bool updateUiIsAllowed()
{
const auto now = std::chrono::steady_clock::now();
- if (numeric::dist(now, lastExec) > std::chrono::milliseconds(rts::UI_UPDATE_INTERVAL_MS)) //handle potential chrono wrap-around!
+ if (numeric::dist(now, lastExec) > UI_UPDATE_INTERVAL) //handle potential chrono wrap-around!
{
lastExec = now;
return true;
@@ -239,7 +241,7 @@ private:
}
-rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname)
+rts::AbortReason rts::startDirectoryMonitor(const XmlRealConfig& config, const wxString& jobname)
{
std::vector<Zstring> dirNamesNonFmt = config.directories;
erase_if(dirNamesNonFmt, [](const Zstring& str) { return trimCpy(str).empty(); }); //remove empty entries WITHOUT formatting paths yet!
@@ -278,10 +280,10 @@ rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& conf
void executeExternalCommand() override
{
- auto cmdLineExp = expandMacros(cmdLine_);
+ auto cmdLineExp = fff::expandMacros(cmdLine_);
try
{
- shellExecute(cmdLineExp, EXEC_TYPE_SYNC); //throw FileError
+ shellExecute(cmdLineExp, ExecutionType::SYNC); //throw FileError
}
catch (const FileError& e)
{
@@ -301,8 +303,8 @@ rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& conf
trayIcon.clearShowErrorRequested();
//wait for some time, then return to retry
- static_assert(RETRY_AFTER_ERROR_INTERVAL_SEC * 1000 % UI_UPDATE_INTERVAL_MS == 0, "");
- for (int i = 0; i < RETRY_AFTER_ERROR_INTERVAL_SEC * 1000 / UI_UPDATE_INTERVAL_MS; ++i)
+ const auto delayUntil = std::chrono::steady_clock::now() + RETRY_AFTER_ERROR_INTERVAL;
+ for (auto now = std::chrono::steady_clock::now(); now < delayUntil; now = std::chrono::steady_clock::now())
{
trayIcon.doUiRefreshNow(); //throw AbortMonitoring
@@ -316,7 +318,7 @@ rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& conf
case ConfirmationButton::CANCEL:
throw AbortMonitoring(SHOW_GUI);
}
- std::this_thread::sleep_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS));
+ std::this_thread::sleep_for(UI_UPDATE_INTERVAL);
}
}
@@ -326,7 +328,7 @@ rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& conf
try
{
- monitorDirectories(dirNamesNonFmt, config.delay, cb); //cb: throw AbortMonitoring
+ monitorDirectories(dirNamesNonFmt, config.delay, cb, UI_UPDATE_INTERVAL / 2); //cb: throw AbortMonitoring
assert(false);
return SHOW_GUI;
}
diff --git a/FreeFileSync/Source/RealTimeSync/tray_menu.h b/FreeFileSync/Source/RealTimeSync/tray_menu.h
index c0833784..ad2ee456 100755
--- a/FreeFileSync/Source/RealTimeSync/tray_menu.h
+++ b/FreeFileSync/Source/RealTimeSync/tray_menu.h
@@ -18,7 +18,7 @@ enum AbortReason
SHOW_GUI,
EXIT_APP
};
-AbortReason startDirectoryMonitor(const xmlAccess::XmlRealConfig& config, const wxString& jobname); //jobname may be empty
+AbortReason startDirectoryMonitor(const XmlRealConfig& config, const wxString& jobname); //jobname may be empty
}
#endif //TRAY_MENU_H_3967857420987534253245
diff --git a/FreeFileSync/Source/RealTimeSync/xml_proc.cpp b/FreeFileSync/Source/RealTimeSync/xml_proc.cpp
index 8b631d6c..0cf23407 100755
--- a/FreeFileSync/Source/RealTimeSync/xml_proc.cpp
+++ b/FreeFileSync/Source/RealTimeSync/xml_proc.cpp
@@ -11,7 +11,7 @@
#include "../lib/ffs_paths.h"
using namespace zen;
-using namespace xmlAccess;
+using namespace rts;
namespace
@@ -37,7 +37,7 @@ bool isXmlTypeRTS(const XmlDoc& doc) //throw()
}
-void xmlAccess::readConfig(const Zstring& filepath, XmlRealConfig& config, std::wstring& warningMsg) //throw FileError
+void rts::readConfig(const Zstring& filepath, XmlRealConfig& config, std::wstring& warningMsg) //throw FileError
{
XmlDoc doc = loadXmlDocument(filepath); //throw FileError
@@ -69,7 +69,7 @@ void writeConfig(const XmlRealConfig& config, XmlOut& out)
}
-void xmlAccess::writeConfig(const XmlRealConfig& config, const Zstring& filepath) //throw FileError
+void rts::writeConfig(const XmlRealConfig& config, const Zstring& filepath) //throw FileError
{
XmlDoc doc("FreeFileSync");
doc.root().setAttribute("XmlType", "REAL");
@@ -83,7 +83,7 @@ void xmlAccess::writeConfig(const XmlRealConfig& config, const Zstring& filepath
namespace
{
-xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& batchCfg, const Zstring& batchFilePath)
+XmlRealConfig convertBatchToReal(const fff::XmlBatchConfig& batchCfg, const Zstring& batchFilePath)
{
std::set<Zstring, LessFilePath> uniqueFolders;
@@ -92,7 +92,7 @@ xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& bat
uniqueFolders.insert(batchCfg.mainCfg.firstPair.folderPathPhraseRight_);
//additional folders
- for (const FolderPairEnh& fp : batchCfg.mainCfg.additionalPairs)
+ for (const fff::FolderPairEnh& fp : batchCfg.mainCfg.additionalPairs)
{
uniqueFolders.insert(fp.folderPathPhraseLeft_);
uniqueFolders.insert(fp.folderPathPhraseRight_);
@@ -100,23 +100,21 @@ xmlAccess::XmlRealConfig convertBatchToReal(const xmlAccess::XmlBatchConfig& bat
erase_if(uniqueFolders, [](const Zstring& str) { return trimCpy(str).empty(); });
- xmlAccess::XmlRealConfig output;
+ XmlRealConfig output;
output.directories.assign(uniqueFolders.begin(), uniqueFolders.end());
- output.commandline = Zstr("\"") + zen::getFreeFileSyncLauncherPath() + Zstr("\" \"") + batchFilePath + Zstr("\"");
+ output.commandline = Zstr("\"") + fff::getFreeFileSyncLauncherPath() + Zstr("\" \"") + batchFilePath + Zstr("\"");
return output;
}
}
-void xmlAccess::readRealOrBatchConfig(const Zstring& filepath, xmlAccess::XmlRealConfig& config, std::wstring& warningMsg) //throw FileError
+void rts::readRealOrBatchConfig(const Zstring& filepath, XmlRealConfig& config, std::wstring& warningMsg) //throw FileError
{
- using namespace xmlAccess;
-
- if (getXmlType(filepath) != XML_TYPE_BATCH) //throw FileError
+ if (fff::getXmlType(filepath) != fff::XML_TYPE_BATCH) //throw FileError
return readConfig(filepath, config, warningMsg); //throw FileError
//convert batch config to RealTimeSync config
- XmlBatchConfig batchCfg;
+ fff::XmlBatchConfig batchCfg;
readConfig(filepath, batchCfg, warningMsg); //throw FileError
//<- redirect batch config warnings
@@ -124,13 +122,13 @@ void xmlAccess::readRealOrBatchConfig(const Zstring& filepath, xmlAccess::XmlRea
}
-wxLanguage xmlAccess::getProgramLanguage()
+wxLanguage rts::getProgramLanguage()
{
- xmlAccess::XmlGlobalSettings settings;
+ fff::XmlGlobalSettings settings;
std::wstring warningMsg;
try
{
- xmlAccess::readConfig(getGlobalConfigFile(), settings, warningMsg); //throw FileError
+ fff::readConfig(fff::getGlobalConfigFile(), settings, warningMsg); //throw FileError
}
catch (const FileError&) {} //use default language if error occurred
diff --git a/FreeFileSync/Source/RealTimeSync/xml_proc.h b/FreeFileSync/Source/RealTimeSync/xml_proc.h
index 3969ba23..afbd010c 100755
--- a/FreeFileSync/Source/RealTimeSync/xml_proc.h
+++ b/FreeFileSync/Source/RealTimeSync/xml_proc.h
@@ -12,7 +12,7 @@
#include <zen/zstring.h>
#include <wx/language.h>
-namespace xmlAccess
+namespace rts
{
struct XmlRealConfig
{
@@ -26,7 +26,7 @@ void writeConfig(const XmlRealConfig& config, const Zstring& filepath); //throw
//reuse (some of) FreeFileSync's xml files
-void readRealOrBatchConfig(const Zstring& filepath, xmlAccess::XmlRealConfig& config, std::wstring& warningMsg); //throw FileError
+void readRealOrBatchConfig(const Zstring& filepath, XmlRealConfig& config, std::wstring& warningMsg); //throw FileError
wxLanguage getProgramLanguage();
}
diff --git a/FreeFileSync/Source/algorithm.cpp b/FreeFileSync/Source/algorithm.cpp
index 861ca36d..2316cd27 100755
--- a/FreeFileSync/Source/algorithm.cpp
+++ b/FreeFileSync/Source/algorithm.cpp
@@ -21,10 +21,10 @@
using namespace zen;
-//using namespace std::rel_ops;
+using namespace fff;
-void zen::swapGrids(const MainConfiguration& config, FolderComparison& folderCmp) //throw FileError
+void fff::swapGrids(const MainConfiguration& config, FolderComparison& folderCmp) //throw FileError
{
std::for_each(begin(folderCmp), end(folderCmp), [](BaseFolderPair& baseFolder) { baseFolder.flip(); });
@@ -182,7 +182,7 @@ bool allItemsCategoryEqual(const ContainerObject& hierObj)
}
}
-bool zen::allElementsEqual(const FolderComparison& folderCmp)
+bool fff::allElementsEqual(const FolderComparison& folderCmp)
{
return std::all_of(begin(folderCmp), end(folderCmp), [](const BaseFolderPair& baseFolder) { return allItemsCategoryEqual(baseFolder); });
}
@@ -655,7 +655,7 @@ private:
//---------------------------------------------------------------------------------------------------------------
-std::vector<DirectionConfig> zen::extractDirectionCfg(const MainConfiguration& mainCfg)
+std::vector<DirectionConfig> fff::extractDirectionCfg(const MainConfiguration& mainCfg)
{
//merge first and additional pairs
std::vector<FolderPairEnh> allPairs;
@@ -672,7 +672,7 @@ std::vector<DirectionConfig> zen::extractDirectionCfg(const MainConfiguration& m
}
-void zen::redetermineSyncDirection(const DirectionConfig& dirCfg, //throw FileError
+void fff::redetermineSyncDirection(const DirectionConfig& dirCfg, //throw FileError
BaseFolderPair& baseFolder,
const std::function<void(const std::wstring& msg)>& notifyStatus)
{
@@ -718,7 +718,7 @@ void zen::redetermineSyncDirection(const DirectionConfig& dirCfg, //throw FileEr
}
-void zen::redetermineSyncDirection(const MainConfiguration& mainCfg, //throw FileError
+void fff::redetermineSyncDirection(const MainConfiguration& mainCfg, //throw FileError
FolderComparison& folderCmp,
const std::function<void(const std::wstring& msg)>& notifyStatus)
{
@@ -779,7 +779,7 @@ struct SetNewDirection
};
-void zen::setSyncDirectionRec(SyncDirection newDirection, FileSystemObject& fsObj)
+void fff::setSyncDirectionRec(SyncDirection newDirection, FileSystemObject& fsObj)
{
//process subdirectories also!
visitFSObject(fsObj, [&](const FolderPair& folder)
@@ -818,7 +818,7 @@ void inOrExcludeAllRows(ContainerObject& hierObj)
}
-void zen::setActiveStatus(bool newStatus, FolderComparison& folderCmp)
+void fff::setActiveStatus(bool newStatus, FolderComparison& folderCmp)
{
if (newStatus)
std::for_each(begin(folderCmp), end(folderCmp), [](BaseFolderPair& baseFolder) { inOrExcludeAllRows<true>(baseFolder); }); //include all rows
@@ -827,7 +827,7 @@ void zen::setActiveStatus(bool newStatus, FolderComparison& folderCmp)
}
-void zen::setActiveStatus(bool newStatus, FileSystemObject& fsObj)
+void fff::setActiveStatus(bool newStatus, FileSystemObject& fsObj)
{
fsObj.setActive(newStatus);
@@ -929,7 +929,7 @@ public:
private:
ApplySoftFilter(ContainerObject& hierObj, const SoftFilter& timeSizeFilter) : timeSizeFilter_(timeSizeFilter) { recurse(hierObj); }
- void recurse(zen::ContainerObject& hierObj) const
+ void recurse(fff::ContainerObject& hierObj) const
{
for (FilePair& file : hierObj.refSubFiles())
processFile(file);
@@ -1013,20 +1013,20 @@ private:
}
-void zen::addHardFiltering(BaseFolderPair& baseFolder, const Zstring& excludeFilter)
+void fff::addHardFiltering(BaseFolderPair& baseFolder, const Zstring& excludeFilter)
{
ApplyHardFilter<STRATEGY_AND>::execute(baseFolder, NameFilter(FilterConfig().includeFilter, excludeFilter));
}
-void zen::addSoftFiltering(BaseFolderPair& baseFolder, const SoftFilter& timeSizeFilter)
+void fff::addSoftFiltering(BaseFolderPair& baseFolder, const SoftFilter& timeSizeFilter)
{
if (!timeSizeFilter.isNull()) //since we use STRATEGY_AND, we may skip a "null" filter
ApplySoftFilter<STRATEGY_AND>::execute(baseFolder, timeSizeFilter);
}
-void zen::applyFiltering(FolderComparison& folderCmp, const MainConfiguration& mainCfg)
+void fff::applyFiltering(FolderComparison& folderCmp, const MainConfiguration& mainCfg)
{
if (folderCmp.empty())
return;
@@ -1117,13 +1117,13 @@ private:
};
-void zen::applyTimeSpanFilter(FolderComparison& folderCmp, time_t timeFrom, time_t timeTo)
+void fff::applyTimeSpanFilter(FolderComparison& folderCmp, time_t timeFrom, time_t timeTo)
{
std::for_each(begin(folderCmp), end(folderCmp), [&](BaseFolderPair& baseFolder) { FilterByTimeSpan::execute(baseFolder, timeFrom, timeTo); });
}
-Opt<PathDependency> zen::getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
+Opt<PathDependency> fff::getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
const AbstractPath& basePathR, const HardFilter& filterR)
{
if (!AFS::isNullPath(basePathL) && !AFS::isNullPath(basePathR))
@@ -1163,7 +1163,7 @@ Opt<PathDependency> zen::getPathDependency(const AbstractPath& basePathL, const
//############################################################################################################
-std::pair<std::wstring, int> zen::getSelectedItemsAsString(const std::vector<const FileSystemObject*>& selectionLeft,
+std::pair<std::wstring, int> fff::getSelectedItemsAsString(const std::vector<const FileSystemObject*>& selectionLeft,
const std::vector<const FileSystemObject*>& selectionRight)
{
//don't use wxString! its rather dumb linear allocation strategy brings perf down to a crawl!
@@ -1184,7 +1184,7 @@ std::pair<std::wstring, int> zen::getSelectedItemsAsString(const std::vector<con
++totalDelCount;
}
- return std::make_pair(fileList, totalDelCount);
+ return { fileList, totalDelCount };
}
@@ -1330,12 +1330,12 @@ void copyToAlternateFolderFrom(const std::vector<const FileSystemObject*>& rowsT
}
-void zen::copyToAlternateFolder(const std::vector<const FileSystemObject*>& rowsToCopyOnLeft,
+void fff::copyToAlternateFolder(const std::vector<const FileSystemObject*>& rowsToCopyOnLeft,
const std::vector<const FileSystemObject*>& rowsToCopyOnRight,
const Zstring& targetFolderPathPhrase,
bool keepRelPaths,
bool overwriteIfExists,
- xmlAccess::OptionalDialogs& warnings,
+ WarningDialogs& warnings,
ProcessCallback& callback)
{
std::vector<const FileSystemObject*> itemSelectionLeft = rowsToCopyOnLeft;
@@ -1494,7 +1494,7 @@ void categorize(const std::vector<FileSystemObject*>& rows,
}
-void zen::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDeleteOnLeft, //refresh GUI grid after deletion to remove invalid rows
+void fff::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDeleteOnLeft, //refresh GUI grid after deletion to remove invalid rows
const std::vector<FileSystemObject*>& rowsToDeleteOnRight, //all pointers need to be bound!
FolderComparison& folderCmp, //attention: rows will be physically deleted!
const std::vector<DirectionConfig>& directCfgs,
@@ -1594,7 +1594,7 @@ void zen::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDelete
//############################################################################################################
-bool zen::operator<(const FileDescriptor& lhs, const FileDescriptor& rhs)
+bool fff::operator<(const FileDescriptor& lhs, const FileDescriptor& rhs)
{
if (lhs.attr.modTime != rhs.attr.modTime)
return lhs.attr.modTime < rhs.attr.modTime;
diff --git a/FreeFileSync/Source/algorithm.h b/FreeFileSync/Source/algorithm.h
index 98067b4e..719d0f9b 100755
--- a/FreeFileSync/Source/algorithm.h
+++ b/FreeFileSync/Source/algorithm.h
@@ -14,7 +14,7 @@
#include "process_callback.h"
-namespace zen
+namespace fff
{
void swapGrids(const MainConfiguration& config, FolderComparison& folderCmp); //throw FileError
@@ -48,8 +48,8 @@ struct PathDependency
AbstractPath basePathChild;
Zstring relPath; //filled if child path is sub folder of parent path; empty if child path == parent path
};
-Opt<PathDependency> getPathDependency(const AbstractPath& basePathL, const HardFilter& filterL,
- const AbstractPath& basePathR, const HardFilter& filterR);
+zen::Opt<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!
@@ -61,7 +61,7 @@ void copyToAlternateFolder(const std::vector<const FileSystemObject*>& rowsToCop
const Zstring& targetFolderPathPhrase,
bool keepRelPaths,
bool overwriteIfExists,
- xmlAccess::OptionalDialogs& warnings,
+ WarningDialogs& warnings,
ProcessCallback& callback);
//manual deletion of files on main grid
diff --git a/FreeFileSync/Source/application.cpp b/FreeFileSync/Source/application.cpp
index d38573ef..0c6a4382 100755
--- a/FreeFileSync/Source/application.cpp
+++ b/FreeFileSync/Source/application.cpp
@@ -26,7 +26,7 @@
#include <gtk/gtk.h>
using namespace zen;
-using namespace xmlAccess;
+using namespace fff;
IMPLEMENT_APP(Application)
@@ -67,7 +67,7 @@ bool Application::OnInit()
try
{
//tentatively set program language to OS default until GlobalSettings.xml is read later
- setLanguage(xmlAccess::XmlGlobalSettings().programLanguage); //throw FileError
+ setLanguage(XmlGlobalSettings().programLanguage); //throw FileError
}
catch (const FileError&) { assert(false); }
@@ -356,7 +356,7 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
//distinguish sync scenarios:
//---------------------------
- const Zstring globalConfigFilePath = !globalConfigFile.empty() ? globalConfigFile : xmlAccess::getGlobalConfigFile();
+ const Zstring globalConfigFilePath = !globalConfigFile.empty() ? globalConfigFile : getGlobalConfigFile();
if (configFiles.empty())
{
@@ -462,7 +462,7 @@ void runGuiMode(const Zstring& globalConfigFilePath) { MainDialog::create(global
void runGuiMode(const Zstring& globalConfigFilePath,
- const xmlAccess::XmlGuiConfig& guiCfg,
+ const XmlGuiConfig& guiCfg,
const std::vector<Zstring>& cfgFilePaths,
bool startComparison)
{
@@ -543,13 +543,14 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
try //begin of synchronization process (all in one try-catch block)
{
- const std::chrono::system_clock::time_point batchStartTime = std::chrono::system_clock::now();
+ const std::chrono::system_clock::time_point syncStartTime = std::chrono::system_clock::now();
//class handling status updates and error messages
BatchStatusHandler statusHandler(!batchCfg.batchExCfg.runMinimized, //throw AbortProcess, BatchRequestSwitchToMainDialog
+ batchCfg.batchExCfg.autoCloseSummary,
extractJobName(cfgFilePath),
globalCfg.soundFileSyncFinished,
- batchStartTime,
+ syncStartTime,
batchCfg.batchExCfg.logFolderPathPhrase,
batchCfg.batchExCfg.logfilesCountLimit,
globalCfg.lastSyncsLogFileSizeMax,
@@ -570,7 +571,7 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
std::unique_ptr<LockHolder> dirLocks;
//COMPARE DIRECTORIES
- FolderComparison cmpResult = compare(globalCfg.optDialogs,
+ FolderComparison cmpResult = compare(globalCfg.warnDlgs,
globalCfg.fileTimeTolerance,
showPopupAllowed, //allowUserInteraction
globalCfg.runWithBackgroundPriority,
@@ -585,7 +586,7 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
if (syncProcessCfg.size() != cmpResult.size())
throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
- synchronize(batchStartTime,
+ synchronize(syncStartTime,
globalCfg.verifyFileCopy,
globalCfg.copyLockedFiles,
globalCfg.copyFilePermissions,
@@ -594,11 +595,11 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
globalCfg.folderAccessTimeout,
syncProcessCfg,
cmpResult,
- globalCfg.optDialogs,
+ globalCfg.warnDlgs,
statusHandler); //throw ?
//not cancelled? => update last sync date for the selected cfg file
- for (xmlAccess::ConfigFileItem& cfi : globalCfg.gui.mainDlg.cfgFileHistory)
+ for (ConfigFileItem& cfi : globalCfg.gui.mainDlg.cfgFileHistory)
if (equalFilePath(cfi.filePath, cfgFilePath))
{
cfi.lastSyncTime = std::time(nullptr);
@@ -609,12 +610,12 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
catch (BatchRequestSwitchToMainDialog&)
{
//open new toplevel window *after* progress dialog is gone => run on main event loop
- return MainDialog::create(globalConfigFilePath, &globalCfg, xmlAccess::convertBatchToGui(batchCfg), { cfgFilePath }, true /*startComparison*/);
+ return MainDialog::create(globalConfigFilePath, &globalCfg, convertBatchToGui(batchCfg), { cfgFilePath }, true /*startComparison*/);
}
try //save global settings to XML: e.g. ignored warnings
{
- xmlAccess::writeConfig(globalCfg, globalConfigFilePath); //FileError
+ writeConfig(globalCfg, globalConfigFilePath); //FileError
}
catch (const FileError& e)
{
diff --git a/FreeFileSync/Source/application.h b/FreeFileSync/Source/application.h
index 5803bee6..1b930074 100755
--- a/FreeFileSync/Source/application.h
+++ b/FreeFileSync/Source/application.h
@@ -13,6 +13,8 @@
#include "lib/return_codes.h"
+namespace fff //avoid name clash with "int ffs()" for fuck's sake! (maxOS, Linux issue only: <string> internally includes <strings.h>, WTF!)
+{
class Application : public wxApp
{
private:
@@ -26,7 +28,8 @@ private:
void onQueryEndSession(wxEvent& event);
void launch(const std::vector<Zstring>& commandArgs);
- zen::FfsReturnCode returnCode_ = zen::FFS_RC_SUCCESS;
+ FfsReturnCode returnCode_ = FFS_RC_SUCCESS;
};
+}
#endif //APPLICATION_H_081568741942010985702395
diff --git a/FreeFileSync/Source/comparison.cpp b/FreeFileSync/Source/comparison.cpp
index ac89cb6c..ca7c6d03 100755
--- a/FreeFileSync/Source/comparison.cpp
+++ b/FreeFileSync/Source/comparison.cpp
@@ -16,9 +16,10 @@
#include "fs/concrete.h"
using namespace zen;
+using namespace fff;
-std::vector<FolderPairCfg> zen::extractCompareCfg(const MainConfiguration& mainCfg)
+std::vector<FolderPairCfg> fff::extractCompareCfg(const MainConfiguration& mainCfg)
{
//merge first and additional pairs
std::vector<FolderPairEnh> allPairs = { mainCfg.firstPair };
@@ -152,7 +153,6 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& keysToRead, int
itemsReported_ = itemsTotal;
callback_.reportStatus(statusMsg); //may throw
- //callback_.requestUiRefresh(); //already called by reportStatus()
}
HandleError reportError(const std::wstring& msg, size_t retryNumber) override
@@ -170,6 +170,8 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& keysToRead, int
return ON_ERROR_CONTINUE;
}
+ int getItemsTotal() const { return itemsReported_; }
+
private:
ProcessCallback& callback_;
int itemsReported_ = 0;
@@ -178,7 +180,9 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& keysToRead, int
fillBuffer(keysToRead, //in
directoryBuffer_, //out
cb,
- UI_UPDATE_INTERVAL_MS / 2); //every ~50 ms
+ UI_UPDATE_INTERVAL / 2); //every ~50 ms
+
+ callback.reportInfo(_("Comparison finished:") + L" " + _P("1 item found", "%x items found", cb.getItemsTotal()));
}
@@ -714,11 +718,11 @@ std::shared_ptr<BaseFolderPair> ComparisonBuffer::performComparison(const Resolv
std::vector<SymlinkPair*>& undefinedSymlinks) const
{
callback_.reportStatus(_("Generating file list..."));
- callback_.forceUiRefresh();
+ callback_.forceUiRefresh(); //throw X
auto getDirValue = [&](const AbstractPath& folderPath) -> const DirectoryValue*
{
- auto it = directoryBuffer_.find(DirectoryKey(folderPath, fpCfg.filter.nameFilter, fpCfg.handleSymlinks));
+ auto it = directoryBuffer_.find({ folderPath, fpCfg.filter.nameFilter, fpCfg.handleSymlinks });
return it != directoryBuffer_.end() ? &it->second : nullptr;
};
@@ -775,9 +779,9 @@ std::shared_ptr<BaseFolderPair> ComparisonBuffer::performComparison(const Resolv
}
-void zen::logNonDefaultSettings(const xmlAccess::XmlGlobalSettings& activeSettings, ProcessCallback& callback)
+void fff::logNonDefaultSettings(const XmlGlobalSettings& activeSettings, ProcessCallback& callback)
{
- const xmlAccess::XmlGlobalSettings defaultSettings;
+ const XmlGlobalSettings defaultSettings;
std::wstring changedSettingsMsg;
if (activeSettings.failSafeFileCopy != defaultSettings.failSafeFileCopy)
@@ -809,7 +813,7 @@ void zen::logNonDefaultSettings(const xmlAccess::XmlGlobalSettings& activeSettin
}
-FolderComparison zen::compare(xmlAccess::OptionalDialogs& warnings,
+FolderComparison fff::compare(WarningDialogs& warnings,
int fileTimeTolerance,
bool allowUserInteraction,
bool runWithBackgroundPriority,
@@ -823,8 +827,8 @@ FolderComparison zen::compare(xmlAccess::OptionalDialogs& warnings,
//indicator at the very beginning of the log to make sense of "total time"
//init process: keep at beginning so that all gui elements are initialized properly
- callback.initNewPhase(-1, 0, ProcessCallback::PHASE_SCANNING); //may throw; it's not known how many files will be scanned => -1 objects
- //callback.reportInfo(_("Starting comparison")); -> still useful?
+ callback.initNewPhase(-1, 0, ProcessCallback::PHASE_SCANNING); //may throw; it's unknown how many files will be scanned => -1 objects
+ //callback.reportInfo(Comparison started")); -> still useful?
//-------------------------------------------------------------------------------
@@ -923,9 +927,9 @@ FolderComparison zen::compare(xmlAccess::OptionalDialogs& warnings,
for (const auto& w : workLoad)
{
if (basefolderExisting(w.first.folderPathLeft)) //only traverse *currently existing* folders: at this point user is aware that non-ex + empty string are seen as empty folder!
- dirsToRead.emplace(w.first.folderPathLeft, w.second.filter.nameFilter, w.second.handleSymlinks);
+ dirsToRead.insert({ w.first.folderPathLeft, w.second.filter.nameFilter, w.second.handleSymlinks });
if (basefolderExisting(w.first.folderPathRight))
- dirsToRead.emplace(w.first.folderPathRight, w.second.filter.nameFilter, w.second.handleSymlinks);
+ dirsToRead.insert({ w.first.folderPathRight, w.second.filter.nameFilter, w.second.handleSymlinks });
}
FolderComparison output;
@@ -940,15 +944,9 @@ FolderComparison zen::compare(xmlAccess::OptionalDialogs& warnings,
//process binary comparison as one junk
std::vector<std::pair<ResolvedFolderPair, FolderPairCfg>> workLoadByContent;
for (const auto& w : workLoad)
- switch (w.second.compareVar)
- {
- case CompareVariant::TIME_SIZE:
- case CompareVariant::SIZE:
- break;
- case CompareVariant::CONTENT:
- workLoadByContent.push_back(w);
- break;
- }
+ if (w.second.compareVar == CompareVariant::CONTENT)
+ workLoadByContent.push_back(w);
+
std::list<std::shared_ptr<BaseFolderPair>> outputByContent = cmpBuff.compareByContent(workLoadByContent);
//write output in expected order
@@ -980,11 +978,11 @@ FolderComparison zen::compare(xmlAccess::OptionalDialogs& warnings,
const FolderPairCfg& fpCfg = cfgList[it - output.begin()];
callback.reportStatus(_("Calculating sync directions..."));
- callback.forceUiRefresh();
+ callback.forceUiRefresh(); //throw X
tryReportingError([&]
{
- zen::redetermineSyncDirection(fpCfg.directionCfg, *it, //throw FileError
+ redetermineSyncDirection(fpCfg.directionCfg, *it, //throw FileError
[&](const std::wstring& msg) { callback.reportStatus(msg); }); //throw X
}, callback); //throw X?
diff --git a/FreeFileSync/Source/comparison.h b/FreeFileSync/Source/comparison.h
index 03afa415..5bc5cd9d 100755
--- a/FreeFileSync/Source/comparison.h
+++ b/FreeFileSync/Source/comparison.h
@@ -14,7 +14,7 @@
#include "lib/lock_holder.h"
-namespace zen
+namespace fff
{
struct FolderPairCfg
{
@@ -48,10 +48,10 @@ struct FolderPairCfg
std::vector<FolderPairCfg> extractCompareCfg(const MainConfiguration& mainCfg); //fill FolderPairCfg and resolve folder pairs
//inform about (important) non-default global settings related to comparison and synchronization
-void logNonDefaultSettings(const xmlAccess::XmlGlobalSettings& currentSettings, ProcessCallback& callback);
+void logNonDefaultSettings(const XmlGlobalSettings& currentSettings, ProcessCallback& callback);
//FFS core routine:
-FolderComparison compare(xmlAccess::OptionalDialogs& warnings,
+FolderComparison compare(WarningDialogs& warnings,
int fileTimeTolerance,
bool allowUserInteraction,
bool runWithBackgroundPriority,
diff --git a/FreeFileSync/Source/file_hierarchy.cpp b/FreeFileSync/Source/file_hierarchy.cpp
index dfe1bffb..bc6db6d6 100755
--- a/FreeFileSync/Source/file_hierarchy.cpp
+++ b/FreeFileSync/Source/file_hierarchy.cpp
@@ -10,6 +10,7 @@
#include <zen/file_error.h>
using namespace zen;
+using namespace fff;
@@ -281,7 +282,7 @@ SyncOperation FilePair::getSyncOperation() const
}
-std::wstring zen::getCategoryDescription(CompareFilesResult cmpRes)
+std::wstring fff::getCategoryDescription(CompareFilesResult cmpRes)
{
switch (cmpRes)
{
@@ -314,7 +315,7 @@ const wchar_t arrowRight[] = L"->";
}
-std::wstring zen::getCategoryDescription(const FileSystemObject& fsObj)
+std::wstring fff::getCategoryDescription(const FileSystemObject& fsObj)
{
const std::wstring footer = L"\n[" + utfTo<std::wstring>(fsObj. getPairItemName()) + L"]";
@@ -336,14 +337,14 @@ std::wstring zen::getCategoryDescription(const FileSystemObject& fsObj)
[&](const FilePair& file)
{
descr += std::wstring(L"\n") +
- arrowLeft + L" " + zen::formatUtcToLocalTime(file.getLastWriteTime< LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + zen::formatUtcToLocalTime(file.getLastWriteTime<RIGHT_SIDE>());
+ arrowLeft + L" " + formatUtcToLocalTime(file.getLastWriteTime< LEFT_SIDE>()) + L"\n" +
+ arrowRight + L" " + formatUtcToLocalTime(file.getLastWriteTime<RIGHT_SIDE>());
},
[&](const SymlinkPair& symlink)
{
descr += std::wstring(L"\n") +
- arrowLeft + L" " + zen::formatUtcToLocalTime(symlink.getLastWriteTime< LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + zen::formatUtcToLocalTime(symlink.getLastWriteTime<RIGHT_SIDE>());
+ arrowLeft + L" " + formatUtcToLocalTime(symlink.getLastWriteTime< LEFT_SIDE>()) + L"\n" +
+ arrowRight + L" " + formatUtcToLocalTime(symlink.getLastWriteTime<RIGHT_SIDE>());
});
return descr + footer;
}
@@ -357,7 +358,7 @@ std::wstring zen::getCategoryDescription(const FileSystemObject& fsObj)
}
-std::wstring zen::getSyncOpDescription(SyncOperation op)
+std::wstring fff::getSyncOpDescription(SyncOperation op)
{
switch (op)
{
@@ -395,7 +396,7 @@ std::wstring zen::getSyncOpDescription(SyncOperation op)
}
-std::wstring zen::getSyncOpDescription(const FileSystemObject& fsObj)
+std::wstring fff::getSyncOpDescription(const FileSystemObject& fsObj)
{
const std::wstring footer = L"\n[" + utfTo<std::wstring>(fsObj. getPairItemName()) + L"]";
diff --git a/FreeFileSync/Source/file_hierarchy.h b/FreeFileSync/Source/file_hierarchy.h
index 5b0ae6c7..d6a7c6fc 100755
--- a/FreeFileSync/Source/file_hierarchy.h
+++ b/FreeFileSync/Source/file_hierarchy.h
@@ -22,7 +22,7 @@
#include "fs/abstract.h"
-namespace zen
+namespace fff
{
using AFS = AbstractFileSystem;
@@ -199,9 +199,9 @@ class ContainerObject : public virtual PathInformation
friend class FileSystemObject;
public:
- using FileList = FixedList<FilePair>; //MergeSides::execute() requires a structure that doesn't invalidate pointers after push_back()
- using SymlinkList = FixedList<SymlinkPair>; //
- using FolderList = FixedList<FolderPair>;
+ using FileList = zen::FixedList<FilePair>; //MergeSides::execute() requires a structure that doesn't invalidate pointers after push_back()
+ using SymlinkList = zen::FixedList<SymlinkPair>; //
+ using FolderList = zen::FixedList<FolderPair>;
FolderPair& addSubFolder(const Zstring& itemNameL,
const FolderAttributes& left, //file exists on both sides
@@ -545,9 +545,9 @@ private:
void flip () override;
void removeObjectL() override;
void removeObjectR() override;
- void notifySyncCfgChanged() override { syncOpBuffered_ = NoValue(); FileSystemObject::notifySyncCfgChanged(); ContainerObject::notifySyncCfgChanged(); }
+ void notifySyncCfgChanged() override { syncOpBuffered_ = zen::NoValue(); FileSystemObject::notifySyncCfgChanged(); ContainerObject::notifySyncCfgChanged(); }
- mutable Opt<SyncOperation> syncOpBuffered_; //determining sync-op for directory may be expensive as it depends on child-objects => buffer
+ mutable zen::Opt<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/fs/abstract.cpp b/FreeFileSync/Source/fs/abstract.cpp
index 4c100bdd..6442008d 100755
--- a/FreeFileSync/Source/fs/abstract.cpp
+++ b/FreeFileSync/Source/fs/abstract.cpp
@@ -10,12 +10,14 @@
#include <zen/crc.h>
using namespace zen;
+using namespace fff;
using AFS = AbstractFileSystem;
+
const Zchar* AFS::TEMP_FILE_ENDING = Zstr(".ffs_tmp");
-bool zen::isValidRelPath(const Zstring& relPath)
+bool fff::isValidRelPath(const Zstring& relPath)
{
const bool check1 = !contains(relPath, '\\');
const bool check2 = !startsWith(relPath, FILE_NAME_SEPARATOR) && !endsWith(relPath, FILE_NAME_SEPARATOR);
@@ -88,7 +90,7 @@ AFS::FileCopyResult AFS::copyFileAsStream(const AfsPath& afsPathSource, const St
bufferedStreamCopy(*streamIn, *streamOut); //throw FileError, ErrorFileLocked, X
- const FileId targetFileId = streamOut->finalize(); //throw FileError, X
+ const AFS::FileId targetFileId = streamOut->finalize(); //throw FileError, X
//check if "expected == actual number of bytes written"
//-> extra check: bytes reported via notifyUnbufferedIO() should match actual number of bytes written
diff --git a/FreeFileSync/Source/fs/abstract.h b/FreeFileSync/Source/fs/abstract.h
index c612dfd9..4899f32a 100755
--- a/FreeFileSync/Source/fs/abstract.h
+++ b/FreeFileSync/Source/fs/abstract.h
@@ -15,7 +15,7 @@
#include "../lib/icon_holder.h"
-namespace zen
+namespace fff
{
struct AbstractFileSystem;
@@ -65,9 +65,9 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
static Zstring getItemName(const AbstractPath& ap) { assert(getParentFolderPath(ap)); return getItemName(ap.afsPath); }
- static Opt<Zstring> getNativeItemPath(const AbstractPath& ap) { return ap.afs->getNativeItemPath(ap.afsPath); }
+ static zen::Opt<Zstring> getNativeItemPath(const AbstractPath& ap) { return ap.afs->getNativeItemPath(ap.afsPath); }
- static Opt<AbstractPath> getParentFolderPath(const AbstractPath& ap);
+ static zen::Opt<AbstractPath> getParentFolderPath(const AbstractPath& ap);
struct PathComponents
{
@@ -91,7 +91,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 Opt<ItemType> getItemTypeIfExists(const AbstractPath& ap); //throw FileError
+ static zen::Opt<ItemType> getItemTypeIfExists(const AbstractPath& ap); //throw FileError
static PathStatus getPathStatus(const AbstractPath& ap); //throw FileError
//----------------------------------------------------------------------------------------------------------------
@@ -125,7 +125,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
static void connectNetworkFolder(const AbstractPath& ap, bool allowUserInteraction) { return ap.afs->connectNetworkFolder(ap.afsPath, allowUserInteraction); } //throw FileError
//----------------------------------------------------------------------------------------------------------------
- using FileId = Zbase<char>;
+ using FileId = zen::Zbase<char>;
struct StreamAttributes
{
@@ -142,7 +142,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 Opt<StreamAttributes> getAttributesBuffered() = 0; //throw FileError
+ virtual zen::Opt<StreamAttributes> getAttributesBuffered() = 0; //throw FileError
};
struct OutputStreamImpl
@@ -164,18 +164,18 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
std::unique_ptr<OutputStreamImpl> outStream_; //bound!
const AbstractPath filePath_;
bool finalizeSucceeded_ = false;
- Opt<uint64_t> bytesExpected_;
+ zen::Opt<uint64_t> bytesExpected_;
uint64_t bytesWrittenTotal_ = 0;
};
//return value always bound:
- static std::unique_ptr<InputStream> getInputStream(const AbstractPath& ap, const IOCallback& notifyUnbufferedIO) //throw FileError, ErrorFileLocked, X
+ static std::unique_ptr<InputStream> getInputStream(const AbstractPath& ap, const zen::IOCallback& notifyUnbufferedIO) //throw FileError, ErrorFileLocked, X
{ return ap.afs->getInputStream(ap.afsPath, notifyUnbufferedIO); }
//target existing: undefined behavior! (fail/overwrite/auto-rename)
static std::unique_ptr<OutputStream> getOutputStream(const AbstractPath& ap, //throw FileError
const uint64_t* streamSize, //optional
- const IOCallback& notifyUnbufferedIO) //
+ const zen::IOCallback& notifyUnbufferedIO) //
{ return std::make_unique<OutputStream>(ap.afs->getOutputStream(ap.afsPath, streamSize, notifyUnbufferedIO), ap, streamSize); }
//----------------------------------------------------------------------------------------------------------------
@@ -244,7 +244,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;
- Opt<FileError> errorModTime; //failure to set modification time
+ zen::Opt<zen::FileError> errorModTime; //failure to set modification time
};
//symlink handling: follow
@@ -258,7 +258,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
//if transactionalCopy == true, full read access on source had been proven at this point, so it's safe to delete it.
const std::function<void()>& onDeleteTargetFile,
//accummulated delta != file size! consider ADS, sparse, compressed files
- const IOCallback& notifyUnbufferedIO);
+ const zen::IOCallback& notifyUnbufferedIO);
//target existing: undefined behavior! (fail/overwrite)
//symlink handling: follow link!
@@ -295,8 +295,8 @@ protected: //grant derived classes access to AbstractPath:
static const AbstractFileSystem& getAfs (const AbstractPath& ap) { return *ap.afs; }
static AfsPath getAfsPath(const AbstractPath& ap) { return ap.afsPath; }
- static Zstring getItemName(const AfsPath& afsPath) { return afterLast(afsPath.value, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL); }
- static Opt<AfsPath> getParentAfsPath(const AfsPath& 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);
struct PathStatusImpl
{
@@ -308,10 +308,10 @@ protected: //grant derived classes access to AbstractPath:
//target existing: undefined behavior! (fail/overwrite/auto-rename)
FileCopyResult copyFileAsStream(const AfsPath& afsPathSource, const StreamAttributes& attrSource, //throw FileError, ErrorFileLocked
- const AbstractPath& apTarget, const IOCallback& notifyUnbufferedIO) const; //may be nullptr; throw X!
+ const AbstractPath& apTarget, const zen::IOCallback& notifyUnbufferedIO) const; //may be nullptr; throw X!
private:
- virtual Opt<Zstring> getNativeItemPath(const AfsPath& afsPath) const { return NoValue(); };
+ virtual zen::Opt<Zstring> getNativeItemPath(const AfsPath& afsPath) const { return zen::NoValue(); };
virtual Zstring getInitPathPhrase(const AfsPath& afsPath) const = 0;
@@ -339,12 +339,12 @@ private:
virtual AbstractPath getSymlinkResolvedPath(const AfsPath& afsPath) const = 0; //throw FileError
virtual std::string getSymlinkBinaryContent(const AfsPath& afsPath) const = 0; //throw FileError
//----------------------------------------------------------------------------------------------------------------
- virtual std::unique_ptr<InputStream> getInputStream (const AfsPath& afsPath, const IOCallback& notifyUnbufferedIO) const = 0; //throw FileError, ErrorFileLocked, X
+ virtual std::unique_ptr<InputStream> getInputStream (const AfsPath& afsPath, const zen::IOCallback& notifyUnbufferedIO) const = 0; //throw FileError, ErrorFileLocked, X
//target existing: undefined behavior! (fail/overwrite/auto-rename)
virtual std::unique_ptr<OutputStreamImpl> getOutputStream(const AfsPath& afsPath, //throw FileError
const uint64_t* streamSize, //optional
- const IOCallback& notifyUnbufferedIO) const = 0; //
+ const zen::IOCallback& notifyUnbufferedIO) const = 0; //
//----------------------------------------------------------------------------------------------------------------
virtual void traverseFolder(const AfsPath& afsPath, TraverserCallback& sink /*throw X*/) const = 0; //throw X
//----------------------------------------------------------------------------------------------------------------
@@ -358,7 +358,7 @@ private:
virtual FileCopyResult copyFileForSameAfsType(const AfsPath& afsPathSource, const StreamAttributes& attrSource, //throw FileError, ErrorFileLocked
const AbstractPath& apTarget, bool copyFilePermissions,
//accummulated delta != file size! consider ADS, sparse, compressed files
- const IOCallback& notifyUnbufferedIO) const = 0; //may be nullptr; throw X!
+ const zen::IOCallback& notifyUnbufferedIO) const = 0; //may be nullptr; throw X!
//target existing: undefined behavior! (fail/overwrite)
@@ -391,7 +391,7 @@ bool tryReportingDirError(Command cmd, AbstractFileSystem::TraverserCallback& ca
cmd(); //throw FileError
return true;
}
- catch (const FileError& e)
+ catch (const zen::FileError& e)
{
switch (callback.reportDirError(e.toString(), retryNumber)) //throw X
{
@@ -413,7 +413,7 @@ bool tryReportingItemError(Command cmd, AbstractFileSystem::TraverserCallback& c
cmd(); //throw FileError
return true;
}
- catch (const FileError& e)
+ catch (const zen::FileError& e)
{
switch (callback.reportItemError(e.toString(), retryNumber, itemName)) //throw X
{
@@ -436,6 +436,8 @@ bool tryReportingItemError(Command cmd, AbstractFileSystem::TraverserCallback& c
inline
AbstractPath AbstractFileSystem::appendRelPath(const AbstractPath& ap, const Zstring& relPath)
{
+ using namespace zen;
+
assert(isValidRelPath(relPath));
return AbstractPath(ap.afs, AfsPath(appendPaths(ap.afsPath.value, relPath, FILE_NAME_SEPARATOR)));
}
@@ -444,6 +446,8 @@ AbstractPath AbstractFileSystem::appendRelPath(const AbstractPath& ap, const Zst
inline
Zstring AbstractFileSystem::appendPaths(const Zstring& basePath, const Zstring& relPath, Zchar pathSep)
{
+ using namespace zen;
+
assert(!startsWith(relPath, pathSep) && !endsWith(relPath, pathSep));
if (relPath.empty())
return basePath;
@@ -482,6 +486,8 @@ AbstractFileSystem::OutputStream::OutputStream(std::unique_ptr<OutputStreamImpl>
inline
AbstractFileSystem::OutputStream::~OutputStream()
{
+ using namespace zen;
+
//we delete the file on errors: => file should not have existed prior to creating OutputStream instance!!
outStream_.reset(); //close file handle *before* remove!
@@ -502,6 +508,8 @@ void AbstractFileSystem::OutputStream::write(const void* data, size_t len) //thr
inline
AbstractFileSystem::FileId AbstractFileSystem::OutputStream::finalize() //throw FileError, X
{
+ using namespace zen;
+
//important check: catches corrupt SFTP download with libssh2!
if (bytesExpected_ && *bytesExpected_ != bytesWrittenTotal_)
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getDisplayPath(filePath_))), //instead we should report the source file, but don't have it here...
@@ -530,6 +538,8 @@ bool AbstractFileSystem::supportPermissionCopy(const AbstractPath& apSource, con
inline
void AbstractFileSystem::renameItem(const AbstractPath& apSource, const AbstractPath& apTarget) //throw FileError, ErrorDifferentVolume
{
+ using namespace zen;
+
if (typeid(*apSource.afs) == typeid(*apTarget.afs))
return apSource.afs->renameItemForSameAfsType(apSource.afsPath, apTarget); //throw FileError, ErrorDifferentVolume
@@ -543,6 +553,8 @@ void AbstractFileSystem::renameItem(const AbstractPath& apSource, const Abstract
inline
void AbstractFileSystem::copyNewFolder(const AbstractPath& apSource, const AbstractPath& apTarget, bool copyFilePermissions) //throw FileError
{
+ using namespace zen;
+
if (typeid(*apSource.afs) == typeid(*apTarget.afs))
return apSource.afs->copyNewFolderForSameAfsType(apSource.afsPath, apTarget, copyFilePermissions); //throw FileError
@@ -559,6 +571,8 @@ void AbstractFileSystem::copyNewFolder(const AbstractPath& apSource, const Abstr
inline
void AbstractFileSystem::copySymlink(const AbstractPath& apSource, const AbstractPath& apTarget, bool copyFilePermissions) //throw FileError
{
+ using namespace zen;
+
if (typeid(*apSource.afs) == typeid(*apTarget.afs))
return apSource.afs->copySymlinkForSameAfsType(apSource.afsPath, apTarget, copyFilePermissions); //throw FileError
diff --git a/FreeFileSync/Source/fs/concrete.cpp b/FreeFileSync/Source/fs/concrete.cpp
index 056daace..ebf0778b 100755
--- a/FreeFileSync/Source/fs/concrete.cpp
+++ b/FreeFileSync/Source/fs/concrete.cpp
@@ -7,10 +7,10 @@
#include "concrete.h"
#include "native.h"
-using namespace zen;
+using namespace fff;
-AbstractPath zen::createAbstractPath(const Zstring& itemPathPhrase) //noexcept
+AbstractPath fff::createAbstractPath(const Zstring& itemPathPhrase) //noexcept
{
//greedy: try native evaluation first
if (acceptsItemPathPhraseNative(itemPathPhrase)) //noexcept
diff --git a/FreeFileSync/Source/fs/concrete.h b/FreeFileSync/Source/fs/concrete.h
index 3e3a933d..82c04c5b 100755
--- a/FreeFileSync/Source/fs/concrete.h
+++ b/FreeFileSync/Source/fs/concrete.h
@@ -9,7 +9,7 @@
#include "abstract.h"
-namespace zen
+namespace fff
{
AbstractPath createAbstractPath(const Zstring& itemPathPhrase); //noexcept
}
diff --git a/FreeFileSync/Source/fs/native.cpp b/FreeFileSync/Source/fs/native.cpp
index 8a9e461d..98a7becc 100755
--- a/FreeFileSync/Source/fs/native.cpp
+++ b/FreeFileSync/Source/fs/native.cpp
@@ -15,11 +15,16 @@
#include <zen/crc.h>
#include "../lib/resolve_path.h"
#include "../lib/icon_loader.h"
-#include "native_traverser_impl.h"
+
+ #include <cstddef> //offsetof
+ #include <sys/stat.h>
+ #include <dirent.h>
#include <fcntl.h> //fallocate, fcntl
using namespace zen;
+using namespace fff;
+using AFS = AbstractFileSystem;
namespace
@@ -30,6 +35,158 @@ void initComForThread() //throw FileError
{
}
+//====================================================================================================
+//====================================================================================================
+
+inline
+AFS::FileId convertToAbstractFileId(const zen::FileId& fid)
+{
+ if (fid == zen::FileId())
+ return AFS::FileId();
+
+ AFS::FileId out(reinterpret_cast<const char*>(&fid.volumeId), sizeof(fid.volumeId));
+ out. append(reinterpret_cast<const char*>(&fid.fileIndex), sizeof(fid.fileIndex));
+ return out;
+}
+
+
+class DirTraverser
+{
+public:
+ static void execute(const Zstring& baseDirPath, AFS::TraverserCallback& sink)
+ {
+ DirTraverser(baseDirPath, sink); //throw X
+ }
+
+private:
+ DirTraverser(const Zstring& baseDirPath, AFS::TraverserCallback& sink)
+ {
+ /* quote: "Since POSIX.1 does not specify the size of the d_name field, and other nonstandard fields may precede
+ that field within the dirent structure, portable applications that use readdir_r() should allocate
+ the buffer whose address is passed in entry as follows:
+ len = offsetof(struct dirent, d_name) + pathconf(dirPath, _PC_NAME_MAX) + 1
+ entryp = malloc(len); */
+ const size_t nameMax = std::max<long>(::pathconf(baseDirPath.c_str(), _PC_NAME_MAX), 10000); //::pathconf may return long(-1)
+ buffer_.resize(offsetof(struct ::dirent, d_name) + nameMax + 1);
+
+ traverse(baseDirPath, sink); //throw X
+ }
+
+ DirTraverser (const DirTraverser&) = delete;
+ DirTraverser& operator=(const DirTraverser&) = delete;
+
+ void traverse(const Zstring& dirPath, AFS::TraverserCallback& sink) //throw X
+ {
+ tryReportingDirError([&] //throw X
+ {
+ traverseWithException(dirPath, sink); //throw FileError, X
+ }, sink);
+ }
+
+ void traverseWithException(const Zstring& dirPath, AFS::TraverserCallback& sink) //throw FileError, X
+ {
+ //no need to check for endless recursion:
+ //1. Linux has a fixed limit on the number of symbolic links in a path
+ //2. fails with "too many open files" or "path too long" before reaching stack overflow
+
+ DIR* folder = ::opendir(dirPath.c_str()); //directory must NOT end with path separator, except "/"
+ if (!folder)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), L"opendir");
+ ZEN_ON_SCOPE_EXIT(::closedir(folder)); //never close nullptr handles! -> crash
+
+ for (;;)
+ {
+ struct ::dirent* dirEntry = nullptr;
+ if (::readdir_r(folder, reinterpret_cast< ::dirent*>(&buffer_[0]), &dirEntry) != 0)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r");
+ //don't retry but restart dir traversal on error! https://blogs.msdn.microsoft.com/oldnewthing/20140612-00/?p=753/
+
+ if (!dirEntry) //no more items
+ return;
+
+ const char* itemNameRaw = dirEntry->d_name; //evaluate dirEntry *before* going into recursion => we use a single "buffer"!
+
+ //skip "." and ".."
+ if (itemNameRaw[0] == '.' &&
+ (itemNameRaw[1] == 0 || (itemNameRaw[1] == '.' && itemNameRaw[2] == 0)))
+ continue;
+ const Zstring& itemName = itemNameRaw;
+ if (itemName.empty()) //checks result of normalizeUtfForPosix, too!
+ throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name.");
+
+ const Zstring& itemPath = appendSeparator(dirPath) + itemName;
+
+ struct ::stat statData = {};
+ if (!tryReportingItemError([&] //throw X
+ {
+ if (::lstat(itemPath.c_str(), &statData) != 0) //lstat() does not resolve symlinks
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"lstat");
+ }, sink, itemName))
+ continue; //ignore error: skip file
+
+ if (S_ISLNK(statData.st_mode)) //on Linux there is no distinction between file and directory symlinks!
+ {
+ const AFS::TraverserCallback::SymlinkInfo linkInfo = { itemName, statData.st_mtime };
+
+ switch (sink.onSymlink(linkInfo)) //throw X
+ {
+ case AFS::TraverserCallback::LINK_FOLLOW:
+ {
+ //try to resolve symlink (and report error on failure!!!)
+ struct ::stat statDataTrg = {};
+
+ const bool validLink = tryReportingItemError([&] //throw X
+ {
+ if (::stat(itemPath.c_str(), &statDataTrg) != 0)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(itemPath)), L"stat");
+ }, sink, itemName);
+
+ if (validLink)
+ {
+ if (S_ISDIR(statDataTrg.st_mode)) //a directory
+ {
+ if (std::unique_ptr<AFS::TraverserCallback> trav = sink.onFolder({ itemName, &linkInfo })) //throw X
+ traverse(itemPath, *trav); //throw X
+ }
+ else //a file or named pipe, ect.
+ {
+ AFS::TraverserCallback::FileInfo fi = { itemName, makeUnsigned(statDataTrg.st_size), statDataTrg.st_mtime, convertToAbstractFileId(extractFileId(statDataTrg)), &linkInfo };
+ sink.onFile(fi); //throw X
+ }
+ }
+ // else //broken symlink -> ignore: it's client's responsibility to handle error!
+ }
+ break;
+
+ case AFS::TraverserCallback::LINK_SKIP:
+ break;
+ }
+ }
+ else if (S_ISDIR(statData.st_mode)) //a directory
+ {
+ if (std::unique_ptr<AFS::TraverserCallback> trav = sink.onFolder({ itemName, nullptr })) //throw X
+ traverse(itemPath, *trav); //throw X
+ }
+ else //a file or named pipe, ect.
+ {
+ AFS::TraverserCallback::FileInfo fi = { itemName, makeUnsigned(statData.st_size), statData.st_mtime, convertToAbstractFileId(extractFileId(statData)), nullptr /*symlinkInfo*/ };
+ sink.onFile(fi); //throw X
+ }
+ /*
+ It may be a good idea to not check "S_ISREG(statData.st_mode)" explicitly and to not issue an error message on other types to support these scenarios:
+ - RTS setup watch (essentially wants to read directories only)
+ - removeDirectory (wants to delete everything; pipes can be deleted just like files via "unlink")
+
+ However an "open" on a pipe will block (https://sourceforge.net/p/freefilesync/bugs/221/), so the copy routines need to be smarter!!
+ */
+ }
+ }
+
+ std::vector<char> buffer_;
+};
+
+//====================================================================================================
+//====================================================================================================
class RecycleSessionNative : public AbstractFileSystem::RecycleSession
{
@@ -314,7 +471,7 @@ private:
try
{
initComForThread(); //throw FileError
- return zen::getFileIcon(getNativePath(afsPath), pixelSize);
+ return fff::getFileIcon(getNativePath(afsPath), pixelSize);
}
catch (FileError&) { assert(false); return ImageHolder(); }
}
@@ -324,7 +481,7 @@ private:
try
{
initComForThread(); //throw FileError
- return zen::getThumbnailImage(getNativePath(afsPath), pixelSize);
+ return fff::getThumbnailImage(getNativePath(afsPath), pixelSize);
}
catch (FileError&) { assert(false); return ImageHolder(); }
}
@@ -387,7 +544,7 @@ void RecycleSessionNative::tryCleanup(const std::function<void (const std::wstri
//coordinate changes with getResolvedFilePath()!
-bool zen::acceptsItemPathPhraseNative(const Zstring& itemPathPhrase) //noexcept
+bool fff::acceptsItemPathPhraseNative(const Zstring& itemPathPhrase) //noexcept
{
Zstring path = itemPathPhrase;
path = expandMacros(path); //expand before trimming!
@@ -403,7 +560,7 @@ bool zen::acceptsItemPathPhraseNative(const Zstring& itemPathPhrase) //noexcept
}
-AbstractPath zen::createItemPathNative(const Zstring& itemPathPhrase) //noexcept
+AbstractPath fff::createItemPathNative(const Zstring& itemPathPhrase) //noexcept
{
//TODO: get volume by name hangs for idle HDD! => run createItemPathNative during getFolderStatusNonBlocking() but getResolvedFilePath currently not thread-safe!
const Zstring itemPath = getResolvedFilePath(itemPathPhrase);
@@ -411,7 +568,7 @@ AbstractPath zen::createItemPathNative(const Zstring& itemPathPhrase) //noexcept
}
-AbstractPath zen::createItemPathNativeNoFormatting(const Zstring& nativePath) //noexcept
+AbstractPath fff::createItemPathNativeNoFormatting(const Zstring& nativePath) //noexcept
{
if (const Opt<PathComponents> comp = parsePathComponents(nativePath))
return AbstractPath(std::make_shared<NativeFileSystem>(comp->rootPath), AfsPath(comp->relPath));
diff --git a/FreeFileSync/Source/fs/native.h b/FreeFileSync/Source/fs/native.h
index b8957a51..d7d8c1bb 100755
--- a/FreeFileSync/Source/fs/native.h
+++ b/FreeFileSync/Source/fs/native.h
@@ -9,7 +9,7 @@
#include "abstract.h"
-namespace zen
+namespace fff
{
bool acceptsItemPathPhraseNative (const Zstring& itemPathPhrase); //noexcept
AbstractPath createItemPathNative(const Zstring& itemPathPhrase); //noexcept
diff --git a/FreeFileSync/Source/fs/native_traverser_impl.h b/FreeFileSync/Source/fs/native_traverser_impl.h
deleted file mode 100755
index cc4d8a52..00000000
--- a/FreeFileSync/Source/fs/native_traverser_impl.h
+++ /dev/null
@@ -1,171 +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 *
-// *****************************************************************************
-
-#include <zen/sys_error.h>
-#include <zen/symlink_target.h>
-#include <zen/file_access.h>
-
-
- #include <cstddef> //offsetof
- #include <sys/stat.h>
- #include <dirent.h>
-
-
-//implementation header for native.cpp, not for reuse!!!
-
-namespace
-{
-using namespace zen;
-using AFS = AbstractFileSystem;
-
-
-inline
-AFS::FileId convertToAbstractFileId(const zen::FileId& fid)
-{
- if (fid == zen::FileId())
- return AFS::FileId();
-
- AFS::FileId out(reinterpret_cast<const char*>(&fid.volumeId), sizeof(fid.volumeId));
- out. append(reinterpret_cast<const char*>(&fid.fileIndex), sizeof(fid.fileIndex));
- return out;
-}
-
-
-class DirTraverser
-{
-public:
- static void execute(const Zstring& baseDirPath, AFS::TraverserCallback& sink)
- {
- DirTraverser(baseDirPath, sink); //throw X
- }
-
-private:
- DirTraverser(const Zstring& baseDirPath, AFS::TraverserCallback& sink)
- {
- /* quote: "Since POSIX.1 does not specify the size of the d_name field, and other nonstandard fields may precede
- that field within the dirent structure, portable applications that use readdir_r() should allocate
- the buffer whose address is passed in entry as follows:
- len = offsetof(struct dirent, d_name) + pathconf(dirPath, _PC_NAME_MAX) + 1
- entryp = malloc(len); */
- const size_t nameMax = std::max<long>(::pathconf(baseDirPath.c_str(), _PC_NAME_MAX), 10000); //::pathconf may return long(-1)
- buffer_.resize(offsetof(struct ::dirent, d_name) + nameMax + 1);
-
- traverse(baseDirPath, sink); //throw X
- }
-
- DirTraverser (const DirTraverser&) = delete;
- DirTraverser& operator=(const DirTraverser&) = delete;
-
- void traverse(const Zstring& dirPath, AFS::TraverserCallback& sink) //throw X
- {
- tryReportingDirError([&] //throw X
- {
- traverseWithException(dirPath, sink); //throw FileError, X
- }, sink);
- }
-
- void traverseWithException(const Zstring& dirPath, AFS::TraverserCallback& sink) //throw FileError, X
- {
- //no need to check for endless recursion:
- //1. Linux has a fixed limit on the number of symbolic links in a path
- //2. fails with "too many open files" or "path too long" before reaching stack overflow
-
- DIR* folder = ::opendir(dirPath.c_str()); //directory must NOT end with path separator, except "/"
- if (!folder)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), L"opendir");
- ZEN_ON_SCOPE_EXIT(::closedir(folder)); //never close nullptr handles! -> crash
-
- for (;;)
- {
- struct ::dirent* dirEntry = nullptr;
- if (::readdir_r(folder, reinterpret_cast< ::dirent*>(&buffer_[0]), &dirEntry) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r");
- //don't retry but restart dir traversal on error! https://blogs.msdn.microsoft.com/oldnewthing/20140612-00/?p=753/
-
- if (!dirEntry) //no more items
- return;
-
- const char* itemNameRaw = dirEntry->d_name; //evaluate dirEntry *before* going into recursion => we use a single "buffer"!
-
- //skip "." and ".."
- if (itemNameRaw[0] == '.' &&
- (itemNameRaw[1] == 0 || (itemNameRaw[1] == '.' && itemNameRaw[2] == 0)))
- continue;
- const Zstring& itemName = itemNameRaw;
- if (itemName.empty()) //checks result of osx::normalizeUtfForPosix, too!
- throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name.");
-
- const Zstring& itemPath = appendSeparator(dirPath) + itemName;
-
- struct ::stat statData = {};
- if (!tryReportingItemError([&] //throw X
- {
- if (::lstat(itemPath.c_str(), &statData) != 0) //lstat() does not resolve symlinks
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"lstat");
- }, sink, itemName))
- continue; //ignore error: skip file
-
- if (S_ISLNK(statData.st_mode)) //on Linux there is no distinction between file and directory symlinks!
- {
- const AFS::TraverserCallback::SymlinkInfo linkInfo = { itemName, statData.st_mtime };
-
- switch (sink.onSymlink(linkInfo)) //throw X
- {
- case AFS::TraverserCallback::LINK_FOLLOW:
- {
- //try to resolve symlink (and report error on failure!!!)
- struct ::stat statDataTrg = {};
-
- const bool validLink = tryReportingItemError([&] //throw X
- {
- if (::stat(itemPath.c_str(), &statDataTrg) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(itemPath)), L"stat");
- }, sink, itemName);
-
- if (validLink)
- {
- if (S_ISDIR(statDataTrg.st_mode)) //a directory
- {
- if (std::unique_ptr<AFS::TraverserCallback> trav = sink.onFolder({ itemName, &linkInfo })) //throw X
- traverse(itemPath, *trav); //throw X
- }
- else //a file or named pipe, ect.
- {
- AFS::TraverserCallback::FileInfo fi = { itemName, makeUnsigned(statDataTrg.st_size), statDataTrg.st_mtime, convertToAbstractFileId(extractFileId(statDataTrg)), &linkInfo };
- sink.onFile(fi); //throw X
- }
- }
- // else //broken symlink -> ignore: it's client's responsibility to handle error!
- }
- break;
-
- case AFS::TraverserCallback::LINK_SKIP:
- break;
- }
- }
- else if (S_ISDIR(statData.st_mode)) //a directory
- {
- if (std::unique_ptr<AFS::TraverserCallback> trav = sink.onFolder({ itemName, nullptr })) //throw X
- traverse(itemPath, *trav); //throw X
- }
- else //a file or named pipe, ect.
- {
- AFS::TraverserCallback::FileInfo fi = { itemName, makeUnsigned(statData.st_size), statData.st_mtime, convertToAbstractFileId(extractFileId(statData)), nullptr /*symlinkInfo*/ };
- sink.onFile(fi); //throw X
- }
- /*
- It may be a good idea to not check "S_ISREG(statData.st_mode)" explicitly and to not issue an error message on other types to support these scenarios:
- - RTS setup watch (essentially wants to read directories only)
- - removeDirectory (wants to delete everything; pipes can be deleted just like files via "unlink")
-
- However an "open" on a pipe will block (https://sourceforge.net/p/freefilesync/bugs/221/), so the copy routines need to be smarter!!
- */
- }
- }
-
- std::vector<char> buffer_;
-};
-}
diff --git a/FreeFileSync/Source/lib/binary.cpp b/FreeFileSync/Source/lib/binary.cpp
index d7f7bf63..e4ac6fc3 100755
--- a/FreeFileSync/Source/lib/binary.cpp
+++ b/FreeFileSync/Source/lib/binary.cpp
@@ -9,6 +9,7 @@
#include <chrono>
using namespace zen;
+using namespace fff;
using AFS = AbstractFileSystem;
namespace
@@ -62,9 +63,9 @@ struct StreamReader
}
size_t proposedBlockSize = 0;
- const auto loopTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(stopTime - startTime).count();
+ const auto loopTime = stopTime - startTime;
- if (loopTimeMs >= 100)
+ if (loopTime >= std::chrono::milliseconds(100))
lastDelayViolation_ = stopTime;
//avoid "flipping back": e.g. DVD-ROMs read 32MB at once, so first read may be > 500 ms, but second one will be 0ms!
@@ -73,7 +74,7 @@ struct StreamReader
lastDelayViolation_ = stopTime;
proposedBlockSize = dynamicBlockSize_ * 2;
}
- if (loopTimeMs > 500)
+ if (loopTime > std::chrono::milliseconds(500))
proposedBlockSize = dynamicBlockSize_ / 2;
if (defaultBlockSize_ <= proposedBlockSize && proposedBlockSize <= BLOCK_SIZE_MAX)
@@ -92,7 +93,7 @@ private:
}
-bool zen::filesHaveSameContent(const AbstractPath& filePath1, const AbstractPath& filePath2, const IOCallback& notifyUnbufferedIO) //throw FileError
+bool fff::filesHaveSameContent(const AbstractPath& filePath1, const AbstractPath& filePath2, const IOCallback& notifyUnbufferedIO) //throw FileError
{
int64_t totalUnbufferedIO = 0;
diff --git a/FreeFileSync/Source/lib/binary.h b/FreeFileSync/Source/lib/binary.h
index 914fedea..bba321da 100755
--- a/FreeFileSync/Source/lib/binary.h
+++ b/FreeFileSync/Source/lib/binary.h
@@ -10,11 +10,11 @@
#include "../fs/abstract.h"
-namespace zen
+namespace fff
{
bool filesHaveSameContent(const AbstractPath& filePath1, //throw FileError
const AbstractPath& filePath2,
- const IOCallback& notifyUnbufferedIO); //may be nullptr
+ const zen::IOCallback& notifyUnbufferedIO); //may be nullptr
}
#endif //BINARY_H_3941281398513241134
diff --git a/FreeFileSync/Source/lib/cmp_filetime.h b/FreeFileSync/Source/lib/cmp_filetime.h
index e3c490df..ce3a04e9 100755
--- a/FreeFileSync/Source/lib/cmp_filetime.h
+++ b/FreeFileSync/Source/lib/cmp_filetime.h
@@ -11,7 +11,7 @@
#include <algorithm>
-namespace zen
+namespace fff
{
inline
bool sameFileTime(int64_t lhs, int64_t rhs, int tolerance, const std::vector<unsigned int>& ignoreTimeShiftMinutes)
diff --git a/FreeFileSync/Source/lib/db_file.cpp b/FreeFileSync/Source/lib/db_file.cpp
index c4cfd837..6b13014d 100755
--- a/FreeFileSync/Source/lib/db_file.cpp
+++ b/FreeFileSync/Source/lib/db_file.cpp
@@ -11,6 +11,7 @@
using namespace zen;
+using namespace fff;
namespace
@@ -23,7 +24,7 @@ const int DB_FORMAT_STREAM = 3; //
struct SessionData
{
- bool isLeadStream;
+ bool isLeadStream = false;
ByteArray rawStream;
};
bool operator==(const SessionData& lhs, const SessionData& rhs) { return lhs.isLeadStream == rhs.isLeadStream && lhs.rawStream == rhs.rawStream; }
@@ -42,7 +43,6 @@ AbstractPath getDatabaseFilePath(const BaseFolderPair& baseFolder, bool tempfile
//precomposed/decomposed UTF? are UTC file times really compatible? what about endianess!?
//however 32 and 64-bit FreeFileSync are designed to produce binary-identical db files!
//Give db files different names.
- //make sure they end with ".ffs_db". These files will be excluded from comparison
const Zstring dbName = Zstr(".sync"); //files beginning with dots are hidden e.g. in Nautilus
Zstring dbFileName;
if (tempfile) //generate (hopefully) unique file name to avoid clashing with some remnant ffs_tmp file
@@ -790,13 +790,13 @@ std::pair<DbStreams::const_iterator,
throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" +
_("The database files do not yet contain information about the last synchronization."));
- return std::make_pair(itCommonL, itCommonR);
+ return { itCommonL, itCommonR };
}
}
//#######################################################################################################################################
-std::shared_ptr<InSyncFolder> zen::loadLastSynchronousState(const BaseFolderPair& baseFolder, //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
+std::shared_ptr<InSyncFolder> fff::loadLastSynchronousState(const BaseFolderPair& baseFolder, //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
const std::function<void(const std::wstring& statusMsg)>& notifyStatus)
{
const AbstractPath dbPathLeft = getDatabaseFilePath< LEFT_SIDE>(baseFolder);
@@ -836,7 +836,7 @@ std::shared_ptr<InSyncFolder> zen::loadLastSynchronousState(const BaseFolderPair
}
-void zen::saveLastSynchronousState(const BaseFolderPair& baseFolder, const std::function<void(const std::wstring& statusMsg)>& notifyStatus) //throw FileError
+void fff::saveLastSynchronousState(const BaseFolderPair& baseFolder, const std::function<void(const std::wstring& statusMsg)>& notifyStatus) //throw FileError
{
//transactional behaviour! write to tmp files first
const AbstractPath dbPathLeft = getDatabaseFilePath< LEFT_SIDE>(baseFolder);
@@ -861,19 +861,16 @@ void zen::saveLastSynchronousState(const BaseFolderPair& baseFolder, const std::
catch (FileError&) {}
//if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- std::shared_ptr<InSyncFolder> lastSyncState = std::make_shared<InSyncFolder>(InSyncFolder::DIR_STATUS_IN_SYNC);
+ auto lastSyncState = std::make_shared<InSyncFolder>(InSyncFolder::DIR_STATUS_IN_SYNC);
auto itStreamOldL = streamsLeft .cend();
auto itStreamOldR = streamsRight.cend();
try
{
//find associated session: there can be at most one session within intersection of left and right ids
- std::pair<DbStreams::const_iterator,
- DbStreams::const_iterator> session = getCommonSession(streamsLeft, streamsRight, //throw FileError, FileErrorDatabaseNotExisting
- AFS::getDisplayPath(dbPathLeft),
- AFS::getDisplayPath(dbPathRight));
+ std::tie(itStreamOldL, itStreamOldR) = getCommonSession(streamsLeft, streamsRight, //throw FileError, FileErrorDatabaseNotExisting
+ AFS::getDisplayPath(dbPathLeft),
+ AFS::getDisplayPath(dbPathRight));
- itStreamOldL = session.first;
- itStreamOldR = session.second;
const bool leadStreamLeft = itStreamOldL->second.isLeadStream;
//load last synchrounous state
@@ -925,8 +922,8 @@ void zen::saveLastSynchronousState(const BaseFolderPair& baseFolder, const std::
//operation finished: rename temp files -> this should work (almost) transactionally:
//if there were no write access, creation of temp files would have failed
- AFS::removeFileIfExists(dbPathLeft); //throw FileError
- AFS::renameItem(dbPathLeftTmp, dbPathLeft); //throw FileError, (ErrorDifferentVolume)
+ AFS::removeFileIfExists(dbPathLeft); //throw FileError
+ AFS::renameItem(dbPathLeftTmp, dbPathLeft); //throw FileError, (ErrorDifferentVolume)
guardTmpL.dismiss();
AFS::removeFileIfExists(dbPathRight); //
diff --git a/FreeFileSync/Source/lib/db_file.h b/FreeFileSync/Source/lib/db_file.h
index 99bcfb79..df61d892 100755
--- a/FreeFileSync/Source/lib/db_file.h
+++ b/FreeFileSync/Source/lib/db_file.h
@@ -11,7 +11,7 @@
#include "../file_hierarchy.h"
-namespace zen
+namespace fff
{
const Zchar SYNC_DB_FILE_ENDING[] = Zstr(".ffs_db"); //don't use Zstring as global constant: avoid static initialization order problem in global namespace!
@@ -21,7 +21,7 @@ struct InSyncDescrFile //subset of FileAttributes
modTime(modTimeIn),
fileId(idIn) {}
- time_t modTime;
+ time_t modTime = 0;
AFS::FileId fileId; // == file id: optional! (however, always set on Linux, and *generally* available on Windows)
};
@@ -29,7 +29,7 @@ struct InSyncDescrLink
{
explicit InSyncDescrLink(time_t modTimeIn) : modTime(modTimeIn) {}
- time_t modTime;
+ time_t modTime = 0;
};
@@ -39,8 +39,8 @@ struct InSyncFile
InSyncFile(const InSyncDescrFile& l, const InSyncDescrFile& r, CompareVariant cv, uint64_t fileSizeIn) : left(l), right(r), cmpVar(cv), fileSize(fileSizeIn) {}
InSyncDescrFile left; //support flip()!
InSyncDescrFile right; //
- CompareVariant cmpVar; //the one active while finding "file in sync"
- uint64_t fileSize; //file size must be identical on both sides!
+ CompareVariant cmpVar = CompareVariant::TIME_SIZE; //the one active while finding "file in sync"
+ uint64_t fileSize = 0; //file size must be identical on both sides!
};
struct InSyncSymlink
@@ -48,7 +48,7 @@ struct InSyncSymlink
InSyncSymlink(const InSyncDescrLink& l, const InSyncDescrLink& r, CompareVariant cv) : left(l), right(r), cmpVar(cv) {}
InSyncDescrLink left;
InSyncDescrLink right;
- CompareVariant cmpVar;
+ CompareVariant cmpVar = CompareVariant::TIME_SIZE;
};
struct InSyncFolder
@@ -62,7 +62,7 @@ struct InSyncFolder
};
InSyncFolder(InSyncStatus statusIn) : status(statusIn) {}
- InSyncStatus status;
+ InSyncStatus status = DIR_STATUS_STRAW_MAN;
//------------------------------------------------------------------
using FolderList = std::map<Zstring, InSyncFolder, LessFilePath>; //
diff --git a/FreeFileSync/Source/lib/dir_exist_async.h b/FreeFileSync/Source/lib/dir_exist_async.h
index 47bf5241..e61cdc41 100755
--- a/FreeFileSync/Source/lib/dir_exist_async.h
+++ b/FreeFileSync/Source/lib/dir_exist_async.h
@@ -15,7 +15,7 @@
#include "../process_callback.h"
-namespace zen
+namespace fff
{
namespace
{
@@ -27,7 +27,7 @@ struct FolderStatus
{
std::set<AbstractPath, AFS::LessAbstractPath> existing;
std::set<AbstractPath, AFS::LessAbstractPath> notExisting;
- std::map<AbstractPath, FileError, AFS::LessAbstractPath> failedChecks;
+ std::map<AbstractPath, zen::FileError, AFS::LessAbstractPath> failedChecks;
};
FolderStatus getFolderStatusNonBlocking(const std::set<AbstractPath, AFS::LessAbstractPath>& folderPaths, int folderAccessTimeout, bool allowUserInteraction, ProcessCallback& procCallback)
@@ -60,7 +60,7 @@ FolderStatus getFolderStatusNonBlocking(const std::set<AbstractPath, AFS::LessAb
procCallback.reportStatus(replaceCpy(_("Searching for folder %x..."), L"%x", displayPathFmt)); //may throw!
while (numeric::dist(std::chrono::steady_clock::now(), startTime) < std::chrono::seconds(folderAccessTimeout) && //handle potential chrono wrap-around!
- fi.second.wait_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS / 2)) != std::future_status::ready)
+ fi.second.wait_for(UI_UPDATE_INTERVAL / 2) != std::future_status::ready)
procCallback.requestUiRefresh(); //may throw!
if (isReady(fi.second))
diff --git a/FreeFileSync/Source/lib/dir_lock.cpp b/FreeFileSync/Source/lib/dir_lock.cpp
index 03149a77..ab41804f 100755
--- a/FreeFileSync/Source/lib/dir_lock.cpp
+++ b/FreeFileSync/Source/lib/dir_lock.cpp
@@ -6,12 +6,10 @@
#include "dir_lock.h"
#include <map>
#include <memory>
-//#include <chrono>
#include <zen/sys_error.h>
#include <zen/thread.h>
#include <zen/scope_guard.h>
#include <zen/guid.h>
-//#include <zen/tick_count.h>
#include <zen/file_access.h>
#include <zen/file_io.h>
#include <zen/optional.h>
@@ -25,13 +23,14 @@
#include <pwd.h> //getpwuid_r()
using namespace zen;
+using namespace fff;
namespace
{
-const int EMIT_LIFE_SIGN_INTERVAL = 5; //show life sign; unit: [s]
-const int POLL_LIFE_SIGN_INTERVAL = 4; //poll for life sign; unit: [s]
-const int DETECT_ABANDONED_INTERVAL = 30; //assume abandoned lock; unit: [s]
+const std::chrono::seconds EMIT_LIFE_SIGN_INTERVAL (5); //show life sign;
+const std::chrono::seconds POLL_LIFE_SIGN_INTERVAL (4); //poll for life sign;
+const std::chrono::seconds DETECT_ABANDONED_INTERVAL(30); //assume abandoned lock;
const char LOCK_FORMAT_DESCR[] = "FreeFileSync";
const int LOCK_FORMAT_VER = 2; //lock file format version
@@ -52,7 +51,7 @@ public:
{
for (;;)
{
- interruptibleSleep(std::chrono::seconds(EMIT_LIFE_SIGN_INTERVAL)); //throw ThreadInterruption
+ interruptibleSleep(EMIT_LIFE_SIGN_INTERVAL); //throw ThreadInterruption
//actual work
emitLifeSign(); //throw ()
@@ -91,6 +90,8 @@ Zstring abandonedLockDeletionName(const Zstring& lockFilePath) //make sure to NO
}
+#if 0
+#endif
using ProcessId = pid_t;
@@ -249,63 +250,63 @@ ProcessStatus getProcessStatus(const LockInformation& lockInfo) //throw FileErro
}
-void waitOnDirLock(const Zstring& lockFilePath, DirLockCallback* callback) //throw FileError
+void waitOnDirLock(const Zstring& lockFilePath, const DirLockCallback& notifyStatus /*throw X*/, std::chrono::milliseconds cbInterval) //throw FileError
{
- using namespace std::chrono;
std::wstring infoMsg = _("Waiting while directory is locked:") + L' ' + fmtPath(lockFilePath);
- if (callback)
- callback->reportStatus(infoMsg);
- //---------------------------------------------------------------
+ if (notifyStatus) notifyStatus(infoMsg); //throw X
+
+ //convenience optimization only: if we know the owning process crashed, we needn't wait DETECT_ABANDONED_INTERVAL sec
+ bool lockOwnderDead = false;
+ std::string originalLockId; //empty if it cannot be retrieved
try
{
- //convenience optimization only: if we know the owning process crashed, we needn't wait DETECT_ABANDONED_INTERVAL sec
- bool lockOwnderDead = false;
- std::string originalLockId; //empty if it cannot be retrieved
- try
- {
- const LockInformation& lockInfo = retrieveLockInfo(lockFilePath); //throw FileError
- //enhance status message and show which user is holding the lock:
- infoMsg += L" | " + _("Lock owner:") + L' ' + utfTo<std::wstring>(lockInfo.userId);
+ const LockInformation& lockInfo = retrieveLockInfo(lockFilePath); //throw FileError
- originalLockId = lockInfo.lockId;
- switch (getProcessStatus(lockInfo)) //throw FileError
- {
- case ProcessStatus::ITS_US: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process
- case ProcessStatus::NOT_RUNNING:
- lockOwnderDead = true;
- break;
- case ProcessStatus::RUNNING:
- case ProcessStatus::CANT_TELL:
- break;
- }
- }
- catch (FileError&) {} //logfile may be only partly written -> this is no error!
+ infoMsg += L" | " + _("Lock owner:") + L' ' + utfTo<std::wstring>(lockInfo.userId);
+ originalLockId = lockInfo.lockId;
+ switch (getProcessStatus(lockInfo)) //throw FileError
+ {
+ case ProcessStatus::ITS_US: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process
+ case ProcessStatus::NOT_RUNNING:
+ lockOwnderDead = true;
+ break;
+ case ProcessStatus::RUNNING:
+ case ProcessStatus::CANT_TELL:
+ break;
+ }
+ }
+ catch (FileError&) {} //logfile may be only partly written -> this is no error!
+ //------------------------------------------------------------------------------
+ try
+ {
uint64_t fileSizeOld = 0;
- auto lastLifeSign = steady_clock::now();
+ auto lastLifeSign = std::chrono::steady_clock::now();
for (;;)
{
- const auto now = steady_clock::now();
const uint64_t fileSizeNew = getFileSize(lockFilePath); //throw FileError
+ const auto lastCheckTime = std::chrono::steady_clock::now();
if (fileSizeNew != fileSizeOld) //received life sign from lock
{
fileSizeOld = fileSizeNew;
- lastLifeSign = now;
+ lastLifeSign = lastCheckTime;
}
if (lockOwnderDead || //no need to wait any longer...
- now >= lastLifeSign + seconds(DETECT_ABANDONED_INTERVAL))
+ lastCheckTime >= lastLifeSign + DETECT_ABANDONED_INTERVAL)
{
- DirLock dummy(abandonedLockDeletionName(lockFilePath), callback); //throw FileError
+ DirLock guardDeletion(abandonedLockDeletionName(lockFilePath), notifyStatus, cbInterval); //throw FileError
//now that the lock is in place check existence again: meanwhile another process may have deleted and created a new lock!
+ std::string currentLockId;
+ try { currentLockId = retrieveLockId(lockFilePath); /*throw FileError*/ }
+ catch (FileError&) {}
- if (!originalLockId.empty())
- if (retrieveLockId(lockFilePath) != originalLockId) //throw FileError -> since originalLockId is filled, we are not expecting errors!
- return; //another process has placed a new lock, leave scope: the wait for the old lock is technically over...
+ if (currentLockId != originalLockId) //throw FileError
+ return; //another process has placed a new lock, leave scope: the wait for the old lock is technically over...
if (getFileSize(lockFilePath) != fileSizeOld) //throw FileError
continue; //late life sign
@@ -315,29 +316,28 @@ void waitOnDirLock(const Zstring& lockFilePath, DirLockCallback* callback) //thr
}
//wait some time...
- static_assert(1000 * POLL_LIFE_SIGN_INTERVAL % GUI_CALLBACK_INTERVAL == 0, "");
- for (size_t i = 0; i < 1000 * POLL_LIFE_SIGN_INTERVAL / GUI_CALLBACK_INTERVAL; ++i)
+ const auto delayUntil = std::chrono::steady_clock::now() + POLL_LIFE_SIGN_INTERVAL;
+ for (auto now = std::chrono::steady_clock::now(); now < delayUntil; now = std::chrono::steady_clock::now())
{
- if (callback) callback->requestUiRefresh();
- std::this_thread::sleep_for(milliseconds(GUI_CALLBACK_INTERVAL));
-
- if (callback)
+ if (notifyStatus)
{
//one signal missed: it's likely this is an abandoned lock => show countdown
- if (now >= lastLifeSign + seconds(EMIT_LIFE_SIGN_INTERVAL + 1))
+ if (lastCheckTime >= lastLifeSign + EMIT_LIFE_SIGN_INTERVAL + std::chrono::seconds(1))
{
- const int remainingSeconds = std::max<int>(0, DETECT_ABANDONED_INTERVAL - duration_cast<seconds>(steady_clock::now() - lastLifeSign).count());
- const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", formatNumber(remainingSeconds));
- callback->reportStatus(infoMsg + L" | " + _("Detecting abandoned lock...") + L' ' + remSecMsg);
+ const int remainingSeconds = std::max<int>(0, std::chrono::duration_cast<std::chrono::seconds>(DETECT_ABANDONED_INTERVAL - (now - lastLifeSign)).count());
+ notifyStatus(infoMsg + L" | " + _("Detecting abandoned lock...") + L' ' + _P("1 sec", "%x sec", remainingSeconds)); //throw X
}
else
- callback->reportStatus(infoMsg); //emit a message in any case (might clear other one)
+ notifyStatus(infoMsg); //throw X; emit a message in any case (might clear other one)
}
+ std::this_thread::sleep_for(cbInterval);
}
}
}
catch (FileError&)
{
+ warn_static("race condition: above calls, e.g. getFileSize() might fail for not existing file, but another one might have been created at this point")
+
if (itemNotExisting(lockFilePath))
return; //what we are waiting for...
throw;
@@ -388,11 +388,13 @@ bool tryLock(const Zstring& lockFilePath) //throw FileError
class DirLock::SharedDirLock
{
public:
- SharedDirLock(const Zstring& lockFilePath, DirLockCallback* callback) : //throw FileError
+ SharedDirLock(const Zstring& lockFilePath, const DirLockCallback& notifyStatus, std::chrono::milliseconds cbInterval) : //throw FileError
lockFilePath_(lockFilePath)
{
- while (!::tryLock(lockFilePath)) //throw FileError
- ::waitOnDirLock(lockFilePath, callback); //
+ if (notifyStatus) notifyStatus(replaceCpy(_("Creating file %x"), L"%x", fmtPath(lockFilePath))); //throw X
+
+ while (!::tryLock(lockFilePath)) //throw FileError
+ ::waitOnDirLock(lockFilePath, notifyStatus, cbInterval); //
lifeSignthread_ = InterruptibleThread(LifeSigns(lockFilePath));
}
@@ -424,7 +426,7 @@ public:
}
//create or retrieve a SharedDirLock
- std::shared_ptr<SharedDirLock> retrieve(const Zstring& lockFilePath, DirLockCallback* callback) //throw FileError
+ std::shared_ptr<SharedDirLock> retrieve(const Zstring& lockFilePath, const DirLockCallback& notifyStatus, std::chrono::milliseconds cbInterval) //throw FileError
{
assert(std::this_thread::get_id() == mainThreadId); //function is not thread-safe!
@@ -448,7 +450,7 @@ public:
catch (FileError&) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock files
//lock not owned by us => create a new one
- auto newLock = std::make_shared<SharedDirLock>(lockFilePath, callback); //throw FileError
+ auto newLock = std::make_shared<SharedDirLock>(lockFilePath, notifyStatus, cbInterval); //throw FileError
const std::string& newLockGuid = retrieveLockId(lockFilePath); //throw FileError
//update registry
@@ -484,11 +486,20 @@ private:
};
-DirLock::DirLock(const Zstring& lockFilePath, DirLockCallback* callback) //throw FileError
+DirLock::DirLock(const Zstring& lockFilePath, const DirLockCallback& notifyStatus, std::chrono::milliseconds cbInterval) //throw FileError
{
- if (callback)
- callback->reportStatus(replaceCpy(_("Creating file %x"), L"%x", fmtPath(lockFilePath)));
-
-
- sharedLock_ = LockAdmin::instance().retrieve(lockFilePath, callback); //throw FileError
+ //#ifdef ZEN_WIN
+ // const DWORD bufferSize = 10000;
+ // std::vector<wchar_t> volName(bufferSize);
+ // if (::GetVolumePathName(lockFilePath.c_str(), //__in LPCTSTR lpszFileName,
+ // &volName[0], //__out LPTSTR lpszVolumePathName,
+ // bufferSize)) //__in DWORD cchBufferLength
+ // {
+ // const DWORD dt = ::GetDriveType(&volName[0]);
+ // if (dt == DRIVE_CDROM)
+ // return; //we don't need a lock for a CD ROM
+ // }
+ //#endif -> still relevant? better save the file I/O for the network scenario
+
+ sharedLock_ = LockAdmin::instance().retrieve(lockFilePath, notifyStatus, cbInterval); //throw FileError
}
diff --git a/FreeFileSync/Source/lib/dir_lock.h b/FreeFileSync/Source/lib/dir_lock.h
index 5a1e3b7e..910e551d 100755
--- a/FreeFileSync/Source/lib/dir_lock.h
+++ b/FreeFileSync/Source/lib/dir_lock.h
@@ -8,19 +8,13 @@
#define DIR_LOCK_H_81740832174954356
#include <memory>
+#include <chrono>
+#include <functional>
#include <zen/file_error.h>
-namespace zen
-{
-const size_t GUI_CALLBACK_INTERVAL = 100;
-struct DirLockCallback //while waiting for the lock
+namespace fff
{
- virtual ~DirLockCallback() {}
- virtual void requestUiRefresh() = 0; //allowed to throw exceptions
- virtual void reportStatus(const std::wstring& text) = 0;
-};
-
/*
RAII structure to place a directory lock against other FFS processes:
- recursive locking supported, even with alternate lockfile names, e.g. via symlinks, network mounts etc.
@@ -31,10 +25,13 @@ RAII structure to place a directory lock against other FFS processes:
- race-free (Windows, almost on Linux(NFS))
- NOT thread-safe! (1. global LockAdmin 2. locks for directory aliases should be created sequentially to detect duplicate locks!)
*/
+//while waiting for the lock
+using DirLockCallback = std::function<void(const std::wstring& msg)>; //throw X
+
class DirLock
{
public:
- DirLock(const Zstring& lockFilePath, DirLockCallback* callback = nullptr); //throw FileError, callback only used during construction
+ DirLock(const Zstring& lockFilePath, const DirLockCallback& notifyStatus, std::chrono::milliseconds cbInterval); //throw FileError, callback only used during construction
private:
class LockAdmin;
diff --git a/FreeFileSync/Source/lib/error_log.h b/FreeFileSync/Source/lib/error_log.h
index 89c2c61d..062c8fbb 100755
--- a/FreeFileSync/Source/lib/error_log.h
+++ b/FreeFileSync/Source/lib/error_log.h
@@ -13,7 +13,7 @@
#include "ffs_paths.h"
-namespace zen
+namespace fff
{
//write error message to a file (even with corrupted stack)- call in desperate situations when no other means of error handling is available
void logFatalError(const std::string& msg); //noexcept
@@ -30,6 +30,8 @@ void logFatalError(const std::string& msg); //noexcept
inline
void logFatalError(const std::string& msg) //noexcept
{
+ using namespace zen;
+
assert(false); //this is stuff we like to debug
const std::string logEntry = "[" + formatTime<std::string>(FORMAT_DATE) + " "+ formatTime<std::string>(FORMAT_TIME) + "] " + msg;
try
diff --git a/FreeFileSync/Source/lib/ffs_paths.cpp b/FreeFileSync/Source/lib/ffs_paths.cpp
index 0ae1f132..a9c43d36 100755
--- a/FreeFileSync/Source/lib/ffs_paths.cpp
+++ b/FreeFileSync/Source/lib/ffs_paths.cpp
@@ -25,14 +25,14 @@ Zstring getExecutablePathPf() //directory containing executable WITH path separa
-bool zen::isPortableVersion()
+bool fff::isPortableVersion()
{
return !endsWith(getExecutablePathPf(), "/bin/"); //this check is a bit lame...
}
-Zstring zen::getResourceDirPf()
+Zstring fff::getResourceDirPf()
{
//make independent from wxWidgets global variable "appname"; support being called by RealTimeSync
auto appName = wxTheApp->GetAppName();
@@ -46,7 +46,7 @@ Zstring zen::getResourceDirPf()
}
-Zstring zen::getConfigDirPathPf()
+Zstring fff::getConfigDirPathPf()
{
//make independent from wxWidgets global variable "appname"; support being called by RealTimeSync
auto appName = wxTheApp->GetAppName();
@@ -69,7 +69,7 @@ Zstring zen::getConfigDirPathPf()
//this function is called by RealTimeSync!!!
-Zstring zen::getFreeFileSyncLauncherPath()
+Zstring fff::getFreeFileSyncLauncherPath()
{
return getExecutablePathPf() + Zstr("FreeFileSync");
diff --git a/FreeFileSync/Source/lib/ffs_paths.h b/FreeFileSync/Source/lib/ffs_paths.h
index ba6f4b32..3cb4c07b 100755
--- a/FreeFileSync/Source/lib/ffs_paths.h
+++ b/FreeFileSync/Source/lib/ffs_paths.h
@@ -9,7 +9,8 @@
#include <zen/zstring.h>
-namespace zen
+
+namespace fff
{
//------------------------------------------------------------------------------
//global program directories
diff --git a/FreeFileSync/Source/lib/generate_logfile.h b/FreeFileSync/Source/lib/generate_logfile.h
index 8906099b..0eb85762 100755
--- a/FreeFileSync/Source/lib/generate_logfile.h
+++ b/FreeFileSync/Source/lib/generate_logfile.h
@@ -15,50 +15,30 @@
#include "../file_hierarchy.h"
-namespace zen
+namespace fff
{
struct SummaryInfo
{
std::wstring jobName; //may be empty
std::wstring finalStatus;
- int itemsProcessed;
- int64_t bytesProcessed;
- int itemsTotal;
- int64_t bytesTotal;
- int64_t totalTime; //unit: [sec]
+ int itemsProcessed = 0;
+ int64_t bytesProcessed = 0;
+ int itemsTotal = 0;
+ int64_t bytesTotal = 0;
+ int64_t totalTime = 0; //unit: [sec]
};
void streamToLogFile(const SummaryInfo& summary, //throw FileError
- const ErrorLog& log,
+ const zen::ErrorLog& log,
AFS::OutputStream& streamOut);
void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError
- const ErrorLog& log,
+ const zen::ErrorLog& log,
size_t maxBytesToWrite,
- const IOCallback& notifyUnbufferedIO);
+ const std::function<void(const std::wstring& msg)>& notifyStatus);
-Zstring getLastSyncsLogfilePath();
-
-
-
-struct OnUpdateLogfileStatusNoThrow
-{
- OnUpdateLogfileStatusNoThrow(ProcessCallback& pc, const std::wstring& logfileDisplayPath) : pc_(pc),
- msg(replaceCpy(_("Saving file %x..."), L"%x", fmtPath(logfileDisplayPath))) {}
-
- void operator()(int64_t bytesDelta)
- {
- bytesWritten += bytesDelta;
- try { pc_.reportStatus(msg + L" (" + formatFilesizeShort(bytesWritten) + L")"); /*throw X*/ }
- catch (...) {}
- }
-
-private:
- ProcessCallback& pc_;
- int64_t bytesWritten = 0;
- const std::wstring msg;
-};
+inline Zstring getDefaultLogFolderPath() { return getConfigDirPathPf() + Zstr("Logs") ; }
//####################### implementation #######################
@@ -66,6 +46,7 @@ namespace
{
std::wstring generateLogHeader(const SummaryInfo& s)
{
+ using namespace zen;
assert(s.itemsProcessed <= s.itemsTotal);
assert(s.bytesProcessed <= s.bytesTotal);
@@ -74,8 +55,8 @@ std::wstring generateLogHeader(const SummaryInfo& s)
//write header
std::wstring headerLine = formatTime<std::wstring>(FORMAT_DATE);
if (!s.jobName.empty())
- headerLine += L" - " + s.jobName;
- headerLine += L": " + s.finalStatus;
+ headerLine += L" | " + s.jobName;
+ headerLine += L" | " + s.finalStatus;
//assemble results box
std::vector<std::wstring> results;
@@ -118,9 +99,10 @@ std::wstring generateLogHeader(const SummaryInfo& s)
inline
void streamToLogFile(const SummaryInfo& summary, //throw FileError
- const ErrorLog& log,
+ const zen::ErrorLog& log,
AFS::OutputStream& streamOut)
{
+ using namespace zen;
const std::string header = replaceCpy(utfTo<std::string>(generateLogHeader(summary)), '\n', LINE_BREAK); //don't replace line break any earlier
streamOut.write(&header[0], header.size()); //throw FileError, X
@@ -141,16 +123,13 @@ void streamToLogFile(const SummaryInfo& summary, //throw FileError
inline
-Zstring getLastSyncsLogfilePath() { return getConfigDirPathPf() + Zstr("LastSyncs.log"); }
-
-
-inline
void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError
- const ErrorLog& log,
+ const zen::ErrorLog& log,
size_t maxBytesToWrite, //log may be *huge*, e.g. 1 million items; LastSyncs.log *must not* create performance problems!
- const IOCallback& notifyUnbufferedIO)
+ const std::function<void(const std::wstring& msg)>& notifyStatus)
{
- const Zstring filepath = getLastSyncsLogfilePath();
+ using namespace zen;
+ const Zstring filePath = getConfigDirPathPf() + Zstr("LastSyncs.log");
Utf8String newStream = utfTo<Utf8String>(generateLogHeader(summary));
replace(newStream, '\n', LINE_BREAK); //don't replace line break any earlier
@@ -170,13 +149,31 @@ void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError
}
}
+ auto notifyUnbufferedIOLoad = [notifyStatus,
+ bytesRead_ = int64_t(0),
+ msg_ = replaceCpy(_("Loading file %x..."), L"%x", fmtPath(filePath))]
+ (int64_t bytesDelta) mutable
+ {
+ if (notifyStatus)
+ notifyStatus(msg_ + L" (" + formatFilesizeShort(bytesRead_ += bytesDelta) + L")"); /*throw X*/
+ };
+
+ auto notifyUnbufferedIOSave = [notifyStatus,
+ bytesWritten_ = int64_t(0),
+ msg_ = replaceCpy(_("Saving file %x..."), L"%x", fmtPath(filePath))]
+ (int64_t bytesDelta) mutable
+ {
+ if (notifyStatus)
+ notifyStatus(msg_ + L" (" + formatFilesizeShort(bytesWritten_ += bytesDelta) + L")"); /*throw X*/
+ };
+
//fill up the rest of permitted space by appending old log
if (newStream.size() < maxBytesToWrite)
{
Utf8String oldStream;
try
{
- oldStream = loadBinContainer<Utf8String>(filepath, notifyUnbufferedIO); //throw FileError, X
+ oldStream = loadBinContainer<Utf8String>(filePath, notifyUnbufferedIOLoad); //throw FileError, X
//Note: we also report the loaded bytes via onUpdateSaveStatus()!
}
catch (FileError&) {}
@@ -185,7 +182,7 @@ void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError
{
newStream += LINE_BREAK;
newStream += LINE_BREAK;
- newStream += oldStream; //impliticly limited by "maxBytesToWrite"!
+ newStream += oldStream; //implicitly limited by "maxBytesToWrite"!
//truncate size if required
if (newStream.size() > maxBytesToWrite)
@@ -204,7 +201,7 @@ void saveToLastSyncsLog(const SummaryInfo& summary, //throw FileError
}
}
- saveBinContainer(filepath, newStream, notifyUnbufferedIO); //throw FileError, X
+ saveBinContainer(filePath, newStream, notifyUnbufferedIOSave); //throw FileError, X
}
}
diff --git a/FreeFileSync/Source/lib/hard_filter.cpp b/FreeFileSync/Source/lib/hard_filter.cpp
index 7fc3b7f6..0f8ebeea 100755
--- a/FreeFileSync/Source/lib/hard_filter.cpp
+++ b/FreeFileSync/Source/lib/hard_filter.cpp
@@ -12,9 +12,10 @@
#include <iterator>
using namespace zen;
+using namespace fff;
-bool zen::operator<(const HardFilter& lhs, const HardFilter& rhs)
+bool fff::operator<(const HardFilter& lhs, const HardFilter& rhs)
{
if (typeid(lhs) != typeid(rhs))
return typeid(lhs).before(typeid(rhs)); //in worst case, order is guaranteed to be stable only during each program run
@@ -217,7 +218,7 @@ bool matchesMaskBegin(const Zstring& name, const std::vector<Zstring>& masks)
}
-std::vector<Zstring> zen::splitByDelimiter(const Zstring& filterString)
+std::vector<Zstring> fff::splitByDelimiter(const Zstring& filterString)
{
//delimiters may be FILTER_ITEM_SEPARATOR or '\n'
std::vector<Zstring> output;
diff --git a/FreeFileSync/Source/lib/hard_filter.h b/FreeFileSync/Source/lib/hard_filter.h
index 801f06ca..4f6acb56 100755
--- a/FreeFileSync/Source/lib/hard_filter.h
+++ b/FreeFileSync/Source/lib/hard_filter.h
@@ -11,7 +11,8 @@
#include <memory>
#include <zen/zstring.h>
-namespace zen
+
+namespace fff
{
//------------------------------------------------------------------
/*
diff --git a/FreeFileSync/Source/lib/help_provider.h b/FreeFileSync/Source/lib/help_provider.h
index 755adad2..1ac0a278 100755
--- a/FreeFileSync/Source/lib/help_provider.h
+++ b/FreeFileSync/Source/lib/help_provider.h
@@ -8,7 +8,7 @@
#define HELP_PROVIDER_H_85930427583421563126
#if 1
-namespace zen
+namespace fff
{
inline void displayHelpEntry(const wxString& topic, wxWindow* parent) { wxLaunchDefaultBrowser(L"https://www.freefilesync.org/manual.php?topic=" + topic); }
inline void uninitializeHelp() {}
@@ -22,7 +22,7 @@ inline void uninitializeHelp() {}
#include <wx/html/helpctrl.h>
-namespace zen
+namespace fff
{
void displayHelpEntry(const wxString& topic, wxWindow* parent);
void uninitializeHelp(); //clean up gracefully during app shutdown: leaving this up to static destruction crashes on Win 8.1!
diff --git a/FreeFileSync/Source/lib/icon_buffer.cpp b/FreeFileSync/Source/lib/icon_buffer.cpp
index dc4f03c0..650bbb55 100755
--- a/FreeFileSync/Source/lib/icon_buffer.cpp
+++ b/FreeFileSync/Source/lib/icon_buffer.cpp
@@ -14,6 +14,7 @@
using namespace zen;
+using namespace fff;
using AFS = AbstractFileSystem;
@@ -330,7 +331,7 @@ struct IconBuffer::Impl
};
-IconBuffer::IconBuffer(IconSize sz) : pimpl_(std::make_unique<Impl>()), iconSizeType(sz)
+IconBuffer::IconBuffer(IconSize sz) : pimpl_(std::make_unique<Impl>()), iconSizeType_(sz)
{
pimpl_->worker = InterruptibleThread(WorkerThread(pimpl_->workload, pimpl_->buffer, sz));
}
@@ -400,7 +401,7 @@ wxBitmap IconBuffer::getIconByExtension(const Zstring& filePath)
const Zstring& templateName(ext.empty() ? Zstr("file") : Zstr("file.") + ext);
//don't pass actual file name to getIconByTemplatePath(), e.g. "AUTHORS" has own mime type on Linux!!!
//=> we want to buffer by extension only to minimize buffer-misses!
- it = pimpl_->extensionIcons.emplace(ext, extractWxBitmap(getIconByTemplatePath(templateName, IconBuffer::getSize(iconSizeType)))).first;
+ it = pimpl_->extensionIcons.emplace(ext, extractWxBitmap(getIconByTemplatePath(templateName, IconBuffer::getSize(iconSizeType_)))).first;
}
//need buffer size limit???
return it->second;
@@ -409,13 +410,13 @@ wxBitmap IconBuffer::getIconByExtension(const Zstring& filePath)
wxBitmap IconBuffer::genericFileIcon(IconSize sz)
{
- return extractWxBitmap(zen::genericFileIcon(IconBuffer::getSize(sz)));
+ return extractWxBitmap(fff::genericFileIcon(IconBuffer::getSize(sz)));
}
wxBitmap IconBuffer::genericDirIcon(IconSize sz)
{
- return extractWxBitmap(zen::genericDirIcon(IconBuffer::getSize(sz)));
+ return extractWxBitmap(fff::genericDirIcon(IconBuffer::getSize(sz)));
}
@@ -434,7 +435,7 @@ wxBitmap IconBuffer::linkOverlayIcon(IconSize sz)
}
-bool zen::hasLinkExtension(const Zstring& filepath)
+bool fff::hasLinkExtension(const Zstring& filepath)
{
const Zstring& ext = getFileExtension(filepath);
return ext == "desktop";
diff --git a/FreeFileSync/Source/lib/icon_buffer.h b/FreeFileSync/Source/lib/icon_buffer.h
index 55427fcb..e5ff932b 100755
--- a/FreeFileSync/Source/lib/icon_buffer.h
+++ b/FreeFileSync/Source/lib/icon_buffer.h
@@ -15,7 +15,7 @@
#include "../fs/abstract.h"
-namespace zen
+namespace fff
{
class IconBuffer
{
@@ -31,10 +31,10 @@ public:
~IconBuffer();
static int getSize(IconSize sz); //expected and *maximum* icon size in pixel
- int getSize() const { return getSize(iconSizeType); } //
+ int getSize() const { return getSize(iconSizeType_); } //
bool readyForRetrieval(const AbstractPath& filePath);
- Opt<wxBitmap> retrieveFileIcon (const AbstractPath& filePath); //... and mark as hot
+ zen::Opt<wxBitmap> retrieveFileIcon (const AbstractPath& filePath); //... and mark as hot
void setWorkload (const std::vector<AbstractPath>& load); //(re-)set new workload of icons to be retrieved;
wxBitmap getIconByExtension(const Zstring& filePath); //...and add to buffer
@@ -47,7 +47,7 @@ private:
struct Impl;
const std::unique_ptr<Impl> pimpl_;
- const IconSize iconSizeType;
+ const IconSize iconSizeType_;
};
bool hasLinkExtension(const Zstring& filepath);
diff --git a/FreeFileSync/Source/lib/icon_holder.h b/FreeFileSync/Source/lib/icon_holder.h
index f8a44611..52bfe474 100755
--- a/FreeFileSync/Source/lib/icon_holder.h
+++ b/FreeFileSync/Source/lib/icon_holder.h
@@ -9,9 +9,9 @@
#include <memory>
-//used by fs/abstract.h => check carefully before adding dependencies!
-namespace zen
+//used by fs/abstract.h => check carefully before adding dependencies!
+namespace fff
{
struct ImageHolder //prepare conversion to wxImage as much as possible while staying thread-safe (in contrast to wxIcon/wxBitmap)
{
diff --git a/FreeFileSync/Source/lib/icon_loader.cpp b/FreeFileSync/Source/lib/icon_loader.cpp
index 5415919b..71b783a2 100755
--- a/FreeFileSync/Source/lib/icon_loader.cpp
+++ b/FreeFileSync/Source/lib/icon_loader.cpp
@@ -12,6 +12,7 @@
using namespace zen;
+using namespace fff;
namespace
@@ -84,7 +85,7 @@ ImageHolder imageHolderFromGicon(GIcon* gicon, int pixelSize)
ZEN_ON_SCOPE_EXIT(::gtk_icon_info_free(iconInfo));
if (GdkPixbuf* pixBuf = ::gtk_icon_info_load_icon(iconInfo, nullptr))
{
- ZEN_ON_SCOPE_EXIT(::g_object_unref(pixBuf)); //superseedes "::gdk_pixbuf_unref"!
+ ZEN_ON_SCOPE_EXIT(::g_object_unref(pixBuf)); //supersedes "::gdk_pixbuf_unref"!
return copyToImageHolder(pixBuf);
}
}
@@ -93,7 +94,7 @@ ImageHolder imageHolderFromGicon(GIcon* gicon, int pixelSize)
}
-ImageHolder zen::getIconByTemplatePath(const Zstring& templatePath, int pixelSize)
+ImageHolder fff::getIconByTemplatePath(const Zstring& templatePath, int pixelSize)
{
//uses full file name, e.g. "AUTHORS" has own mime type on Linux:
if (gchar* contentType = ::g_content_type_guess(templatePath.c_str(), //const gchar* filename,
@@ -113,7 +114,7 @@ ImageHolder zen::getIconByTemplatePath(const Zstring& templatePath, int pixelSiz
}
-ImageHolder zen::genericFileIcon(int pixelSize)
+ImageHolder fff::genericFileIcon(int pixelSize)
{
//we're called by getDisplayIcon()! -> avoid endless recursion!
if (GIcon* fileIcon = ::g_content_type_get_icon("text/plain"))
@@ -126,7 +127,7 @@ ImageHolder zen::genericFileIcon(int pixelSize)
}
-ImageHolder zen::genericDirIcon(int pixelSize)
+ImageHolder fff::genericDirIcon(int pixelSize)
{
if (GIcon* dirIcon = ::g_content_type_get_icon("inode/directory")) //should contain fallback to GTK_STOCK_DIRECTORY ("gtk-directory")
{
@@ -138,7 +139,7 @@ ImageHolder zen::genericDirIcon(int pixelSize)
}
-ImageHolder zen::getFileIcon(const Zstring& filePath, int pixelSize)
+ImageHolder fff::getFileIcon(const Zstring& filePath, int pixelSize)
{
//2. retrieve file icons
GFile* file = ::g_file_new_for_path(filePath.c_str()); //documented to "never fail"
@@ -156,7 +157,7 @@ ImageHolder zen::getFileIcon(const Zstring& filePath, int pixelSize)
}
-ImageHolder zen::getThumbnailImage(const Zstring& filePath, int pixelSize) //return null icon on failure
+ImageHolder fff::getThumbnailImage(const Zstring& filePath, int pixelSize) //return null icon on failure
{
struct ::stat fileInfo = {};
if (::stat(filePath.c_str(), &fileInfo) == 0)
diff --git a/FreeFileSync/Source/lib/icon_loader.h b/FreeFileSync/Source/lib/icon_loader.h
index c93113c8..efbd530f 100755
--- a/FreeFileSync/Source/lib/icon_loader.h
+++ b/FreeFileSync/Source/lib/icon_loader.h
@@ -11,7 +11,7 @@
#include "icon_holder.h"
-namespace zen
+namespace fff
{
//=> all functions are safe to call from multiple threads!
//!!!Note: init COM + system image list before loading icons!!!
diff --git a/FreeFileSync/Source/lib/localization.cpp b/FreeFileSync/Source/lib/localization.cpp
index a594e004..a60e34e2 100755
--- a/FreeFileSync/Source/lib/localization.cpp
+++ b/FreeFileSync/Source/lib/localization.cpp
@@ -24,6 +24,7 @@
using namespace zen;
+using namespace fff;
namespace
@@ -31,7 +32,7 @@ namespace
class FFSTranslation : public TranslationHandler
{
public:
- FFSTranslation(const Zstring& lngFilePath, wxLanguage langId); //throw lngfile::ParsingError, parse_plural::ParsingError
+ FFSTranslation(const Zstring& lngFilePath, wxLanguage langId); //throw lng::ParsingError, plural::ParsingError
wxLanguage getLangId() const { return langId_; }
@@ -46,7 +47,7 @@ public:
std::wstring translate(const std::wstring& singular, const std::wstring& plural, int64_t n) const override
{
- auto it = transMappingPl.find(std::make_pair(singular, plural));
+ auto it = transMappingPl.find({ singular, plural });
if (it != transMappingPl.end())
{
const size_t formNo = pluralParser->getForm(n);
@@ -62,12 +63,12 @@ private:
Translation transMapping; //map original text |-> translation
TranslationPlural transMappingPl;
- std::unique_ptr<parse_plural::PluralForm> pluralParser; //bound!
+ std::unique_ptr<plural::PluralForm> pluralParser; //bound!
const wxLanguage langId_;
};
-FFSTranslation::FFSTranslation(const Zstring& lngFilePath, wxLanguage langId) : langId_(langId) //throw lngfile::ParsingError, parse_plural::ParsingError
+FFSTranslation::FFSTranslation(const Zstring& lngFilePath, wxLanguage langId) : langId_(langId) //throw lng::ParsingError, plural::ParsingError
{
std::string inputStream;
try
@@ -76,14 +77,14 @@ FFSTranslation::FFSTranslation(const Zstring& lngFilePath, wxLanguage langId) :
}
catch (const FileError& e)
{
- throw lngfile::ParsingError(e.toString(), 0, 0);
+ throw lng::ParsingError({ e.toString(), 0, 0 });
//passing FileError is too high a level for Parsing error, OTOH user is unlikely to see this since file I/O issues are sorted out by getExistingTranslations()!
}
- lngfile::TransHeader header;
- lngfile::TranslationMap transInput;
- lngfile::TranslationPluralMap transPluralInput;
- lngfile::parseLng(inputStream, header, transInput, transPluralInput); //throw ParsingError
+ lng::TransHeader header;
+ lng::TranslationMap transInput;
+ lng::TranslationPluralMap transPluralInput;
+ lng::parseLng(inputStream, header, transInput, transPluralInput); //throw ParsingError
for (const auto& item : transInput)
{
@@ -101,10 +102,10 @@ FFSTranslation::FFSTranslation(const Zstring& lngFilePath, wxLanguage langId) :
for (const std::string& pf : item.second)
plFormsWide.push_back(utfTo<std::wstring>(pf));
- transMappingPl.emplace(std::make_pair(engSingular, engPlural), plFormsWide);
+ transMappingPl.insert({ { engSingular, engPlural }, plFormsWide });
}
- pluralParser = std::make_unique<parse_plural::PluralForm>(header.pluralDefinition); //throw parse_plural::ParsingError
+ pluralParser = std::make_unique<plural::PluralForm>(header.pluralDefinition); //throw plural::ParsingError
}
@@ -125,7 +126,7 @@ std::vector<TranslationInfo> loadTranslations()
//search language files available
std::vector<Zstring> lngFilePaths;
- traverseFolder(zen::getResourceDirPf() + Zstr("Languages"), [&](const zen::FileInfo& fi) //FileInfo is ambiguous on OS X
+ traverseFolder(fff::getResourceDirPf() + Zstr("Languages"), [&](const FileInfo& fi) //FileInfo is ambiguous on OS X
{
if (endsWith(fi.fullPath, Zstr(".lng")))
lngFilePaths.push_back(fi.fullPath);
@@ -137,8 +138,8 @@ std::vector<TranslationInfo> loadTranslations()
{
const std::string stream = loadBinContainer<std::string>(filePath, nullptr /*notifyUnbufferedIO*/); //throw FileError
- lngfile::TransHeader lngHeader;
- lngfile::parseHeader(stream, lngHeader); //throw ParsingError
+ lng::TransHeader lngHeader;
+ lng::parseHeader(stream, lngHeader); //throw ParsingError
assert(!lngHeader.languageName .empty());
assert(!lngHeader.translatorName.empty());
@@ -165,7 +166,7 @@ std::vector<TranslationInfo> loadTranslations()
else assert(false);
}
catch (FileError&) { assert(false); }
- catch (lngfile::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs
+ catch (lng::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs
}
std::sort(locMapping.begin(), locMapping.end(), [](const TranslationInfo& lhs, const TranslationInfo& rhs)
@@ -372,21 +373,21 @@ private:
}
-const std::vector<TranslationInfo>& zen::getExistingTranslations()
+const std::vector<TranslationInfo>& fff::getExistingTranslations()
{
static const std::vector<TranslationInfo> translations = loadTranslations();
return translations;
}
-void zen::releaseWxLocale()
+void fff::releaseWxLocale()
{
wxWidgetsLocale::getInstance().tearDown();
- zen::setTranslator(nullptr); //good place for clean up rather than some time during static destruction: is this an actual benefit???
+ setTranslator(nullptr); //good place for clean up rather than some time during static destruction: is this an actual benefit???
}
-void zen::setLanguage(wxLanguage lng) //throw FileError
+void fff::setLanguage(wxLanguage lng) //throw FileError
{
if (getLanguage() == lng && wxWidgetsLocale::getInstance().getLanguage() == lng)
return; //support polling
@@ -403,21 +404,21 @@ void zen::setLanguage(wxLanguage lng) //throw FileError
//load language file into buffer
if (langFilePath.empty()) //if languageFile is empty, texts will be english by default
- zen::setTranslator(nullptr);
+ setTranslator(nullptr);
else
try
{
- zen::setTranslator(std::make_unique<FFSTranslation>(langFilePath, lng)); //throw lngfile::ParsingError, parse_plural::ParsingError
+ setTranslator(std::make_unique<FFSTranslation>(langFilePath, lng)); //throw lng::ParsingError, plural::ParsingError
}
- catch (lngfile::ParsingError& e)
+ catch (lng::ParsingError& e)
{
throw FileError(replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."),
L"%x", fmtPath(langFilePath)),
- L"%y", numberTo<std::wstring>(e.row_ + 1)),
- L"%z", numberTo<std::wstring>(e.col_ + 1))
- + L"\n\n" + e.msg_);
+ L"%y", numberTo<std::wstring>(e.row + 1)),
+ L"%z", numberTo<std::wstring>(e.col + 1))
+ + L"\n\n" + e.msg);
}
- catch (parse_plural::ParsingError&)
+ catch (plural::ParsingError&)
{
throw FileError(replaceCpy<std::wstring>(L"%x: Invalid plural form definition", L"%x", fmtPath(langFilePath))); //user should never see this!
}
@@ -427,15 +428,15 @@ void zen::setLanguage(wxLanguage lng) //throw FileError
}
-wxLanguage zen::getLanguage()
+wxLanguage fff::getLanguage()
{
- std::shared_ptr<const TranslationHandler> t = zen::getTranslator();
+ std::shared_ptr<const TranslationHandler> t = getTranslator();
const FFSTranslation* loc = dynamic_cast<const FFSTranslation*>(t.get());
return loc ? loc->getLangId() : wxLANGUAGE_ENGLISH_US;
}
-wxLanguage zen::getSystemLanguage()
+wxLanguage fff::getSystemLanguage()
{
return mapLanguageDialect(static_cast<wxLanguage>(wxLocale::GetSystemLanguage()));
}
diff --git a/FreeFileSync/Source/lib/localization.h b/FreeFileSync/Source/lib/localization.h
index ad603af2..bf2f6b60 100755
--- a/FreeFileSync/Source/lib/localization.h
+++ b/FreeFileSync/Source/lib/localization.h
@@ -11,7 +11,8 @@
#include <zen/file_error.h>
#include <wx/language.h>
-namespace zen
+
+namespace fff
{
struct TranslationInfo
{
diff --git a/FreeFileSync/Source/lib/lock_holder.h b/FreeFileSync/Source/lib/lock_holder.h
index fc3f7a5c..128f4b8e 100755
--- a/FreeFileSync/Source/lib/lock_holder.h
+++ b/FreeFileSync/Source/lib/lock_holder.h
@@ -8,7 +8,7 @@
#include "status_handler.h"
-namespace zen
+namespace fff
{
//intermediate locks created by DirLock use this extension, too:
const Zchar LOCK_FILE_ENDING[] = Zstr(".ffs_lock"); //don't use Zstring as global constant: avoid static initialization order problem in global namespace!
@@ -18,27 +18,21 @@ const Zchar LOCK_FILE_ENDING[] = Zstr(".ffs_lock"); //don't use Zstring as globa
class LockHolder
{
public:
- LockHolder(const std::set<Zstring, LessFilePath>& dirpathsExisting, //resolved paths
+ LockHolder(const std::set<Zstring, LessFilePath>& dirPathsExisting, //resolved paths
bool& warnDirectoryLockFailed,
ProcessCallback& pcb)
{
- class WaitOnLockHandler : public DirLockCallback
- {
- public:
- WaitOnLockHandler(ProcessCallback& pc) : pc_(pc) {}
- void requestUiRefresh() override { pc_.requestUiRefresh(); } //allowed to throw exceptions
- void reportStatus(const std::wstring& text) override { pc_.reportStatus(text); }
- private:
- ProcessCallback& pc_;
- } lcb(pcb);
+ using namespace zen;
std::map<Zstring, FileError, LessFilePath> failedLocks;
- for (const Zstring& dirpath : dirpathsExisting)
+ for (const Zstring& dirpath : dirPathsExisting)
try
{
//lock file creation is synchronous and may block noticeably for very slow devices (usb sticks, mapped cloud storages)
- lockHolder_.emplace_back(appendSeparator(dirpath) + Zstr("sync") + LOCK_FILE_ENDING, &lcb); //throw FileError
+ lockHolder_.emplace_back(appendSeparator(dirpath) + Zstr("sync") + LOCK_FILE_ENDING,
+ [&](const std::wstring& msg) { pcb.reportStatus(msg); /*throw X*/ },
+ UI_UPDATE_INTERVAL / 2); //throw FileError
}
catch (const FileError& e) { failedLocks.emplace(dirpath, e); }
diff --git a/FreeFileSync/Source/lib/norm_filter.h b/FreeFileSync/Source/lib/norm_filter.h
index b357bdaa..c2606ffc 100755
--- a/FreeFileSync/Source/lib/norm_filter.h
+++ b/FreeFileSync/Source/lib/norm_filter.h
@@ -11,7 +11,7 @@
#include "soft_filter.h"
-namespace zen
+namespace fff
{
struct NormalizedFilter //grade-a filter: global/local filter settings combined, units resolved, ready for use
{
@@ -45,8 +45,6 @@ bool isNullFilter(const FilterConfig& filterCfg)
-
-
// ----------------------- implementation -----------------------
inline
NormalizedFilter normalizeFilters(const FilterConfig& global, const FilterConfig& local)
diff --git a/FreeFileSync/Source/lib/parallel_scan.cpp b/FreeFileSync/Source/lib/parallel_scan.cpp
index adb13bee..3ff7c9b6 100755
--- a/FreeFileSync/Source/lib/parallel_scan.cpp
+++ b/FreeFileSync/Source/lib/parallel_scan.cpp
@@ -11,11 +11,11 @@
#include <zen/thread.h>
#include <zen/scope_guard.h>
#include <zen/fixed_list.h>
-//#include <zen/tick_count.h>
#include "db_file.h"
#include "lock_holder.h"
using namespace zen;
+using namespace fff;
namespace
@@ -159,7 +159,7 @@ using BasicWString = Zbase<wchar_t>; //thread-safe string class for UI texts
class AsyncCallback //actor pattern
{
public:
- AsyncCallback(size_t reportingIntervalMs) : reportingIntervalMs_(reportingIntervalMs) {}
+ AsyncCallback(std::chrono::milliseconds cbInterval) : cbInterval_(cbInterval) {}
//blocking call: context of worker thread
FillBufferCallback::HandleError reportError(const std::wstring& msg, size_t retryNumber) //throw ThreadInterruption
@@ -206,7 +206,8 @@ public:
const auto now = std::chrono::steady_clock::now(); //0 on error
- if (numeric::dist(now, lastReportTime) > std::chrono::milliseconds(reportingIntervalMs_)) //perform ui updates not more often than necessary + handle potential chrono wrap-around!
+ //perform ui updates not more often than necessary + handle potential chrono wrap-around!
+ if (numeric::dist(now, lastReportTime) > cbInterval_)
{
lastReportTime = now; //keep "lastReportTime" at worker thread level to avoid locking!
return true;
@@ -235,7 +236,7 @@ public:
const long activeCount = activeWorker_;
if (activeCount >= 2)
- statusText += L" [" + replaceCpy(_P("1 thread", "%x threads", activeCount), L"%x", numberTo<std::wstring>(activeCount)) + L"]";
+ statusText += L" [" + _P("1 thread", "%x threads", activeCount) + L"]";
statusText += L" ";
statusText += filepath;
@@ -262,7 +263,7 @@ private:
std::mutex lockCurrentStatus_; //use a different lock for current file: continue traversing while some thread may process an error
BasicWString currentFile_;
- const int64_t reportingIntervalMs_;
+ const std::chrono::milliseconds cbInterval_;
const BasicWString textScanning_ { copyStringTo<BasicWString>(_("Scanning:")) }; //this one is (currently) not shared and could be made a std::wstring, but we stay consistent and use thread-safe variables in this class only!
@@ -519,10 +520,10 @@ private:
}
-void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
+void fff::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
std::map<DirectoryKey, DirectoryValue>& buf, //out
FillBufferCallback& callback,
- size_t updateIntervalMs)
+ std::chrono::milliseconds cbInterval)
{
buf.clear();
@@ -537,7 +538,7 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
wt.join(); //in this context it is possible a thread is *not* joinable anymore due to the thread::try_join_for() below!
);
- auto acb = std::make_shared<AsyncCallback>(updateIntervalMs / 2 /*reportingIntervalMs*/);
+ auto acb = std::make_shared<AsyncCallback>(cbInterval);
//init worker threads
for (const DirectoryKey& key : keysToRead)
@@ -548,9 +549,9 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
const int threadId = static_cast<int>(worker.size());
worker.emplace_back(WorkerThread(threadId,
acb,
- key.folderPath_, //AbstractPath is thread-safe like an int! :)
- key.filter_,
- key.handleSymlinks_,
+ key.folderPath, //AbstractPath is thread-safe like an int! :)
+ key.filter,
+ key.handleSymlinks,
dirOutput));
}
@@ -565,7 +566,7 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
//process errors
acb->processErrors(callback);
}
- while (!wt.tryJoinFor(std::chrono::milliseconds(updateIntervalMs)));
+ while (!wt.tryJoinFor(cbInterval));
acb->incrementNotifyingThreadId(); //process info messages of one thread at a time only
}
diff --git a/FreeFileSync/Source/lib/parallel_scan.h b/FreeFileSync/Source/lib/parallel_scan.h
index fbfbca06..d28bb9d9 100755
--- a/FreeFileSync/Source/lib/parallel_scan.h
+++ b/FreeFileSync/Source/lib/parallel_scan.h
@@ -9,40 +9,34 @@
#include <map>
#include <set>
+#include <chrono>
#include "hard_filter.h"
#include "../structures.h"
#include "../file_hierarchy.h"
-namespace zen
+namespace fff
{
struct DirectoryKey
{
- DirectoryKey(const AbstractPath& folderPath,
- const HardFilter::FilterRef& filter,
- SymLinkHandling handleSymlinks) :
- folderPath_(folderPath),
- filter_(filter),
- handleSymlinks_(handleSymlinks) {}
-
- const AbstractPath folderPath_; //always bound!
- HardFilter::FilterRef filter_; //filter interface: always bound by design!
- SymLinkHandling handleSymlinks_;
+ AbstractPath folderPath;
+ HardFilter::FilterRef filter; //always bound by design!
+ SymLinkHandling handleSymlinks = SymLinkHandling::EXCLUDE;
};
inline
bool operator<(const DirectoryKey& lhs, const DirectoryKey& rhs)
{
- if (lhs.handleSymlinks_ != rhs.handleSymlinks_)
- return lhs.handleSymlinks_ < rhs.handleSymlinks_;
+ if (lhs.handleSymlinks != rhs.handleSymlinks)
+ return lhs.handleSymlinks < rhs.handleSymlinks;
- if (AFS::LessAbstractPath()(lhs.folderPath_, rhs.folderPath_))
+ if (AFS::LessAbstractPath()(lhs.folderPath, rhs.folderPath))
return true;
- if (AFS::LessAbstractPath()(rhs.folderPath_, lhs.folderPath_))
+ if (AFS::LessAbstractPath()(rhs.folderPath, lhs.folderPath))
return false;
- return *lhs.filter_ < *rhs.filter_;
+ return *lhs.filter < *rhs.filter;
}
@@ -75,7 +69,7 @@ struct FillBufferCallback
void fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
std::map<DirectoryKey, DirectoryValue>& buf, //out
FillBufferCallback& callback,
- size_t updateIntervalMs); //unit: [ms]
+ std::chrono::milliseconds cbInterval);
}
#endif //PARALLEL_SCAN_H_924588904275284572857
diff --git a/FreeFileSync/Source/lib/parse_lng.h b/FreeFileSync/Source/lib/parse_lng.h
index f2009585..78aa4a88 100755
--- a/FreeFileSync/Source/lib/parse_lng.h
+++ b/FreeFileSync/Source/lib/parse_lng.h
@@ -22,7 +22,8 @@
#include <zen/string_tools.h>
#include "parse_plural.h"
-namespace lngfile
+
+namespace lng
{
//singular forms
using TranslationMap = std::map <std::string, std::string>; //orig |-> translation
@@ -45,12 +46,11 @@ struct TransHeader
struct ParsingError
{
- ParsingError(const std::wstring& msg, size_t row, size_t col) : msg_(msg), row_(row), col_(col) {}
- std::wstring msg_; //parser error message
- size_t row_; //starting with 0
- size_t col_; //
+ std::wstring msg;
+ size_t row = 0; //starting with 0
+ size_t col = 0; //
};
-void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap& out, TranslationPluralMap& pluralOut); //throw ParsingError
+void parseLng (const std::string& fileStream, TransHeader& header, TranslationMap& out, TranslationPluralMap& pluralOut); //throw ParsingError
void parseHeader(const std::string& fileStream, TransHeader& header); //throw ParsingError
class TranslationUnorderedList; //unordered list of unique translation items
@@ -89,46 +89,46 @@ public:
void addItem(const std::string& orig)
{
- if (!transUnique.insert(orig).second) return;
+ if (!transUnique_.insert(orig).second) return;
auto it = transOld_.find(orig);
if (it != transOld_.end() && !it->second.empty()) //preserve old translation from .lng file if existing
- sequence.push_back(std::make_shared<RegularItem>(std::make_pair(orig, it->second)));
+ sequence_.push_back(std::make_shared<RegularItem>(std::make_pair(orig, it->second)));
else
switch (newItemPos_)
{
case TranslationNewItemPos::REL:
- sequence.push_back(std::make_shared<RegularItem>(std::make_pair(orig, std::string())));
+ sequence_.push_back(std::make_shared<RegularItem>(std::make_pair(orig, std::string())));
break;
case TranslationNewItemPos::TOP:
- sequence.push_front(std::make_shared<RegularItem>(std::make_pair(orig, std::string()))); //put untranslated items to the front of the .lng filebreak;
+ sequence_.push_front(std::make_shared<RegularItem>(std::make_pair(orig, std::string()))); //put untranslated items to the front of the .lng filebreak;
break;
}
}
void addItem(const SingularPluralPair& orig)
{
- if (!pluralUnique.insert(orig).second) return;
+ if (!pluralUnique_.insert(orig).second) return;
auto it = transPluralOld_.find(orig);
if (it != transPluralOld_.end() && !it->second.empty()) //preserve old translation from .lng file if existing
- sequence.push_back(std::make_shared<PluralItem>(std::make_pair(orig, it->second)));
+ sequence_.push_back(std::make_shared<PluralItem>(std::make_pair(orig, it->second)));
else
switch (newItemPos_)
{
case TranslationNewItemPos::REL:
- sequence.push_back(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms())));
+ sequence_.push_back(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms())));
break;
case TranslationNewItemPos::TOP:
- sequence.push_front(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms()))); //put untranslated items to the front of the .lng file
+ sequence_.push_front(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms()))); //put untranslated items to the front of the .lng file
break;
}
}
- bool untranslatedTextExists() const { return std::any_of(sequence.begin(), sequence.end(), [](const std::shared_ptr<Item>& item) { return !item->hasTranslation(); }); }
+ bool untranslatedTextExists() const { return std::any_of(sequence_.begin(), sequence_.end(), [](const std::shared_ptr<Item>& item) { return !item->hasTranslation(); }); }
template <class Function, class Function2>
void visitItems(Function onTrans, Function2 onPluralTrans) const //onTrans takes (const TranslationMap::value_type&), onPluralTrans takes (const TranslationPluralMap::value_type&)
{
- for (const auto& item : sequence)
+ for (const auto& item : sequence_)
if (auto regular = dynamic_cast<const RegularItem*>(item.get()))
onTrans(regular->value);
else if (auto plural = dynamic_cast<const PluralItem*>(item.get()))
@@ -142,10 +142,10 @@ private:
struct PluralItem : public Item { PluralItem (const TranslationPluralMap::value_type& val) : value(val) {} bool hasTranslation() const override { return !value.second.empty(); } TranslationPluralMap::value_type value; };
const TranslationNewItemPos newItemPos_;
- std::list<std::shared_ptr<Item>> sequence; //ordered list of translation elements
+ std::list<std::shared_ptr<Item>> sequence_; //ordered list of translation elements
- std::set<TranslationMap ::key_type> transUnique; //check uniqueness
- std::set<TranslationPluralMap::key_type> pluralUnique; //
+ std::set<TranslationMap ::key_type> transUnique_; //check uniqueness
+ std::set<TranslationPluralMap::key_type> pluralUnique_; //
const TranslationMap transOld_; //reuse existing translation
const TranslationPluralMap transPluralOld_; //
@@ -241,37 +241,37 @@ private:
class Scanner
{
public:
- Scanner(const std::string& byteStream) : stream(byteStream), pos(stream.begin())
+ Scanner(const std::string& byteStream) : stream_(byteStream), pos_(stream_.begin())
{
- if (zen::startsWith(stream, zen::BYTE_ORDER_MARK_UTF8))
- pos += zen::strLength(zen::BYTE_ORDER_MARK_UTF8);
+ if (zen::startsWith(stream_, zen::BYTE_ORDER_MARK_UTF8))
+ pos_ += zen::strLength(zen::BYTE_ORDER_MARK_UTF8);
}
Token nextToken()
{
//skip whitespace
- pos = std::find_if(pos, stream.end(), [](char c) { return !zen::isWhiteSpace(c); });
+ pos_ = std::find_if(pos_, stream_.end(), [](char c) { return !zen::isWhiteSpace(c); });
- if (pos == stream.end())
+ if (pos_ == stream_.end())
return Token(Token::TK_END);
- for (const auto& token : tokens.getList())
+ for (const auto& token : tokens_.getList())
if (startsWith(token.second))
{
- pos += token.second.size();
+ pos_ += token.second.size();
return Token(token.first);
}
//rest must be "text"
- auto itBegin = pos;
- while (pos != stream.end() && !startsWithKnownTag())
- pos = std::find(pos + 1, stream.end(), '<');
+ auto itBegin = pos_;
+ while (pos_ != stream_.end() && !startsWithKnownTag())
+ pos_ = std::find(pos_ + 1, stream_.end(), '<');
- std::string text(itBegin, pos);
+ std::string text(itBegin, pos_);
normalize(text); //remove whitespace from end ect.
- if (text.empty() && pos == stream.end())
+ if (text.empty() && pos_ == stream_.end())
return Token(Token::TK_END);
Token out(Token::TK_TEXT);
@@ -282,8 +282,8 @@ public:
size_t posRow() const //current row beginning with 0
{
//count line endings
- const size_t crSum = std::count(stream.begin(), pos, '\r'); //carriage returns
- const size_t nlSum = std::count(stream.begin(), pos, '\n'); //new lines
+ const size_t crSum = std::count(stream_.begin(), pos_, '\r'); //carriage returns
+ const size_t nlSum = std::count(stream_.begin(), pos_, '\n'); //new lines
assert(crSum == 0 || nlSum == 0 || crSum == nlSum);
return std::max(crSum, nlSum); //be compatible with Linux/Mac/Win
}
@@ -291,27 +291,27 @@ public:
size_t posCol() const //current col beginning with 0
{
//seek beginning of line
- for (auto it = pos; it != stream.begin(); )
+ for (auto it = pos_; it != stream_.begin(); )
{
--it;
if (*it == '\r' || *it == '\n')
- return pos - it - 1;
+ return pos_ - it - 1;
}
- return pos - stream.begin();
+ return pos_ - stream_.begin();
}
private:
bool startsWithKnownTag() const
{
- return std::any_of(tokens.getList().begin(), tokens.getList().end(),
+ return std::any_of(tokens_.getList().begin(), tokens_.getList().end(),
[&](const KnownTokens::TokenMap::value_type& p) { return startsWith(p.second); });
}
bool startsWith(const std::string& prefix) const
{
- if (stream.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
+ if (stream_.end() - pos_ < static_cast<ptrdiff_t>(prefix.size()))
return false;
- return std::equal(prefix.begin(), prefix.end(), pos);
+ return std::equal(prefix.begin(), prefix.end(), pos_);
}
static void normalize(std::string& text)
@@ -327,9 +327,9 @@ private:
zen::replace(text, "\r", '\n'); //ensure c-style line breaks
}
- const std::string stream;
- std::string::const_iterator pos;
- const KnownTokens tokens; //no need for static non-POD!
+ const std::string stream_;
+ std::string::const_iterator pos_;
+ const KnownTokens tokens_; //no need for static non-POD!
};
@@ -344,15 +344,15 @@ public:
try
{
- parse_plural::PluralFormInfo pi(header.pluralDefinition, header.pluralCount);
+ plural::PluralFormInfo pi(header.pluralDefinition, header.pluralCount);
//items
while (token().type != Token::TK_END)
parseRegular(out, pluralOut, pi);
}
- catch (const parse_plural::InvalidPluralForm&)
+ catch (const plural::InvalidPluralForm&)
{
- throw ParsingError(L"Invalid plural form definition", scn_.posRow(), scn_.posCol());
+ throw ParsingError({ L"Invalid plural form definition", scn_.posRow(), scn_.posCol() });
}
}
@@ -394,7 +394,7 @@ public:
}
private:
- void parseRegular(TranslationMap& out, TranslationPluralMap& pluralOut, const parse_plural::PluralFormInfo& pluralInfo)
+ void parseRegular(TranslationMap& out, TranslationPluralMap& pluralOut, const plural::PluralFormInfo& pluralInfo)
{
consumeToken(Token::TK_SRC_BEGIN);
@@ -418,7 +418,7 @@ private:
out.emplace(original, translation);
}
- void parsePlural(TranslationPluralMap& pluralOut, const parse_plural::PluralFormInfo& pluralInfo)
+ void parsePlural(TranslationPluralMap& pluralOut, const plural::PluralFormInfo& pluralInfo)
{
//Token::TK_SRC_BEGIN already consumed
@@ -457,12 +457,12 @@ private:
using namespace zen;
if (original.empty())
- throw ParsingError(L"Translation source text is empty", scn_.posRow(), scn_.posCol());
+ throw ParsingError({ L"Translation source text is empty", scn_.posRow(), scn_.posCol() });
if (!isValidUtf(original))
- throw ParsingError(L"Translation source text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol());
+ throw ParsingError({ L"Translation source text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol() });
if (!isValidUtf(translation))
- throw ParsingError(L"Translation text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol());
+ throw ParsingError({ L"Translation text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol() });
if (!translation.empty())
{
@@ -471,7 +471,7 @@ private:
{
if (contains(original, placeholder) &&
!contains(translation, placeholder))
- throw ParsingError(replaceCpy<std::wstring>(L"Placeholder %x missing in translation", L"%x", utfTo<std::wstring>(placeholder)), scn_.posRow(), scn_.posCol());
+ throw ParsingError({ replaceCpy<std::wstring>(L"Placeholder %x missing in translation", L"%x", utfTo<std::wstring>(placeholder)), scn_.posRow(), scn_.posCol() });
};
checkPlaceholder("%x");
checkPlaceholder("%y");
@@ -487,19 +487,19 @@ private:
const size_t ampCountOrig = ampersandTokenCount(original);
if (ampCountOrig != ampersandTokenCount(translation) ||
ampCountOrig > 1)
- 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());
+ 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());
+ 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
- throw ParsingError(L"Source text ends with a colon character \":\", but translation does not", scn_.posRow(), scn_.posCol());
+ 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, ".."); };
@@ -508,43 +508,43 @@ private:
!endsWithSingleDot(translation) &&
!endsWith(translation, "\xe0\xa5\xa4") && //hindi period
!endsWith(translation, "\xe3\x80\x82")) //chinese period
- throw ParsingError(L"Source text ends with a punctuation mark character \".\", but translation does not", scn_.posRow(), scn_.posCol());
+ 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?)
- throw ParsingError(L"Source text ends with an ellipsis \"...\", but translation does not", scn_.posRow(), scn_.posCol());
+ 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());
+ 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());
+ 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());
+ throw ParsingError({ L"Misspelled \"RealTimeSync\" in translation", scn_.posRow(), scn_.posCol() });
}
}
- void validateTranslation(const SingularPluralPair& original, const PluralForms& translation, const parse_plural::PluralFormInfo& pluralInfo) //throw ParsingError
+ void validateTranslation(const SingularPluralPair& original, const PluralForms& translation, const plural::PluralFormInfo& pluralInfo) //throw ParsingError
{
using namespace zen;
//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());
+ 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());
+ 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());
+ throw ParsingError({ L"Translation text contains UTF-8 encoding error", scn_.posRow(), scn_.posCol() });
if (!translation.empty())
{
//check for invalid number of plural forms
if (pluralInfo.getCount() != static_cast<int>(translation.size()))
- throw ParsingError(replaceCpy(replaceCpy<std::wstring>(L"Invalid number of plural forms; actual: %x, expected: %y", L"%x", numberTo<std::wstring>(translation.size())), L"%y", numberTo<std::wstring>(pluralInfo.getCount())), scn_.posRow(), scn_.posCol());
+ throw ParsingError({ replaceCpy(replaceCpy<std::wstring>(L"Invalid number of plural forms; actual: %x, expected: %y", L"%x", numberTo<std::wstring>(translation.size())), L"%y", numberTo<std::wstring>(pluralInfo.getCount())), scn_.posRow(), scn_.posCol() });
//check for duplicate plural form translations (catch copy & paste errors for single-number form translations)
for (auto it = translation.begin(); it != translation.end(); ++it)
@@ -552,7 +552,7 @@ private:
{
auto it2 = std::find(it + 1, translation.end(), *it);
if (it2 != translation.end())
- throw ParsingError(replaceCpy<std::wstring>(L"Duplicate plural form translation at index position %x", L"%x", numberTo<std::wstring>(it2 - translation.begin())), scn_.posRow(), scn_.posCol());
+ throw ParsingError({ replaceCpy<std::wstring>(L"Duplicate plural form translation at index position %x", L"%x", numberTo<std::wstring>(it2 - translation.begin())), scn_.posRow(), scn_.posCol() });
}
for (int pos = 0; pos < static_cast<int>(translation.size()); ++pos)
@@ -565,15 +565,15 @@ private:
const int firstNumber = pluralInfo.getFirstNumber(pos);
if (!(contains(translation[pos], "%x") ||
contains(translation[pos], numberTo<std::string>(firstNumber))))
- throw ParsingError(replaceCpy<std::wstring>(replaceCpy<std::wstring>(L"Plural form translation at index position %y needs to use the decimal number %z or the %x placeholder",
- L"%y", numberTo<std::wstring>(pos)), L"%z", numberTo<std::wstring>(firstNumber)), scn_.posRow(), scn_.posCol());
+ throw ParsingError({ replaceCpy<std::wstring>(replaceCpy<std::wstring>(L"Plural form translation at index position %y needs to use the decimal number %z or the %x placeholder",
+ L"%y", numberTo<std::wstring>(pos)), L"%z", numberTo<std::wstring>(firstNumber)), scn_.posRow(), scn_.posCol() });
}
}
else
{
//ensure the placeholder is used when needed
if (!contains(translation[pos], "%x"))
- throw ParsingError(replaceCpy<std::wstring>(L"Plural form at index position %y is missing the %x placeholder", L"%y", numberTo<std::wstring>(pos)), scn_.posRow(), scn_.posCol());
+ throw ParsingError({ replaceCpy<std::wstring>(L"Plural form at index position %y is missing the %x placeholder", L"%y", numberTo<std::wstring>(pos)), scn_.posRow(), scn_.posCol() });
}
auto checkSecondaryPlaceholder = [&](const std::string& placeholder)
@@ -584,11 +584,11 @@ private:
{
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());
+ 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());
+ 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() });
}
};
checkSecondaryPlaceholder("%y");
@@ -597,7 +597,7 @@ private:
//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());
+ throw ParsingError({ L"Source text is a one-liner, but at least one plural form translation consists of multiple lines", scn_.posRow(), scn_.posCol() });
}
}
@@ -613,7 +613,7 @@ private:
void expectToken(Token::Type t) //throw ParsingError
{
if (token().type != t)
- throw ParsingError(L"Unexpected token", scn_.posRow(), scn_.posCol());
+ throw ParsingError({ L"Unexpected token", scn_.posRow(), scn_.posCol() });
}
Scanner scn_;
diff --git a/FreeFileSync/Source/lib/parse_plural.h b/FreeFileSync/Source/lib/parse_plural.h
index 3964d7b3..8a9173e3 100755
--- a/FreeFileSync/Source/lib/parse_plural.h
+++ b/FreeFileSync/Source/lib/parse_plural.h
@@ -12,7 +12,8 @@
#include <functional>
#include <zen/string_base.h>
-namespace parse_plural
+
+namespace plural
{
//expression interface
struct Expression { virtual ~Expression() {} };
@@ -110,7 +111,7 @@ pm-expression:
.po format,e.g.: (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
*/
-namespace implementation
+namespace impl
{
template <class BinaryOp, class ParamType, class ResultType>
struct BinaryExp : public Expr<ResultType>
@@ -441,7 +442,7 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) /
forms_.resize(pluralCount);
try
{
- parse_plural::PluralForm pf(definition); //throw parse_plural::ParsingError
+ PluralForm pf(definition); //throw ParsingError
//PERF_START
//perf: 80ns per iteration max (for arabic)
@@ -459,7 +460,7 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) /
throw InvalidPluralForm();
}
}
- catch (const parse_plural::ParsingError&)
+ catch (const plural::ParsingError&)
{
throw InvalidPluralForm();
}
@@ -471,7 +472,7 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) /
inline
-PluralForm::PluralForm(const std::string& stream) : expr_(implementation::Parser(stream, n_).parse()) {} //throw ParsingError
+PluralForm::PluralForm(const std::string& stream) : expr_(impl::Parser(stream, n_).parse()) {} //throw ParsingError
}
#endif //PARSE_PLURAL_H_180465845670839576
diff --git a/FreeFileSync/Source/lib/perf_check.cpp b/FreeFileSync/Source/lib/perf_check.cpp
index b101c9b2..fe4727c7 100755
--- a/FreeFileSync/Source/lib/perf_check.cpp
+++ b/FreeFileSync/Source/lib/perf_check.cpp
@@ -5,123 +5,93 @@
// *****************************************************************************
#include "perf_check.h"
-
-#include <limits>
#include <zen/basic_math.h>
#include <zen/i18n.h>
#include <zen/format_unit.h>
using namespace zen;
+using namespace fff;
-PerfCheck::PerfCheck(unsigned int windowSizeRemainingTime,
- unsigned int windowSizeSpeed) :
- windowSizeRemTime(windowSizeRemainingTime),
- windowSizeSpeed_(windowSizeSpeed),
- windowMax(std::max(windowSizeRemainingTime, windowSizeSpeed)) {}
+PerfCheck::PerfCheck(std::chrono::milliseconds windowSizeRemTime,
+ std::chrono::milliseconds windowSizeSpeed) :
+ windowSizeRemTime_(windowSizeRemTime),
+ windowSizeSpeed_ (windowSizeSpeed),
+ windowMax_(std::max(windowSizeRemTime, windowSizeSpeed)) {}
-PerfCheck::~PerfCheck()
+void PerfCheck::addSample(std::chrono::nanoseconds timeElapsed, int itemsCurrent, double dataCurrent)
{
- /*
- //write samples to a file
- wxFFile outputFile(wxT("statistics.dat"), wxT("w"));
-
- outputFile.Write(wxT("Time(ms);Objects;Data\n"));
+ samples_.insert(samples_.end(), { timeElapsed, { itemsCurrent, dataCurrent }}); //use fact that time is monotonously ascending
- for (auto it = samples.begin(); it != samples.end(); ++it)
- {
- outputFile.Write(numberTo<wxString>(it->first));
- outputFile.Write(wxT(";"));
- outputFile.Write(numberTo<wxString>(it->second.objCount_));
- outputFile.Write(wxT(";"));
- outputFile.Write(numberTo<wxString>(it->second.data_));
- outputFile.Write(wxT("\n"));
- }
- */
+ //remove all records earlier than "now - windowMax"
+ auto it = samples_.upper_bound(timeElapsed - windowMax_);
+ if (it != samples_.begin())
+ samples_.erase(samples_.begin(), --it); //keep one point before newBegin in order to handle "measurement holes"
}
-void PerfCheck::addSample(int itemsCurrent, double dataCurrent, int64_t timeMs)
+std::tuple<double /*timeDelta*/, int /*itemsDelta*/, double /*bytesDelta*/> PerfCheck::getBlockDeltas(std::chrono::milliseconds windowSize) const
{
- samples.insert(samples.end(), std::make_pair(timeMs, Record(itemsCurrent, dataCurrent))); //use fact that time is monotonously ascending
+ if (samples_.empty()) return {};
- //remove all records earlier than "now - windowMax"
- auto it = samples.upper_bound(timeMs - windowMax);
- if (it != samples.begin())
- samples.erase(samples.begin(), --it); //keep one point before newBegin in order to handle "measurement holes"
-}
+ auto itBack = samples_.rbegin();
+ //find start of records "window"
+ auto itFront = samples_.upper_bound(itBack->first - windowSize);
+ if (itFront != samples_.begin())
+ --itFront; //one point before window begin in order to handle "measurement holes"
+ const double timeDelta = std::chrono::duration<double>(itBack->first - itFront->first).count();
+ const int itemsDelta = itBack->second.items - itFront->second.items;
+ const double bytesDelta = itBack->second.bytes - itFront->second.bytes;
-inline
-std::pair<const std::multimap<int64_t, PerfCheck::Record>::value_type*, const std::multimap<int64_t, PerfCheck::Record>::value_type*> PerfCheck::getBlockFromEnd(int64_t windowSize) const
-{
- if (!samples.empty())
- {
- auto itBack = samples.rbegin();
- //find start of records "window"
- auto itFront = samples.upper_bound(itBack->first - windowSize);
- if (itFront != samples.begin())
- --itFront; //one point before window begin in order to handle "measurement holes"
- return std::make_pair(&*itFront, &*itBack);
- }
- return std::make_pair(nullptr, nullptr);
+ //return { timeDelta, itemsDelta, bytesDelta }; -> requires C++17 (Linux only issue)
+ return std::make_tuple(timeDelta, itemsDelta, bytesDelta);
}
-zen::Opt<double> PerfCheck::getRemainingTimeSec(double dataRemaining) const
+Opt<double> PerfCheck::getRemainingTimeSec(double dataRemaining) const
{
- auto blk = getBlockFromEnd(windowSizeRemTime);
- if (blk.first && blk.second)
- {
- const auto& itemFront = *blk.first;
- const auto& itemBack = *blk.second;
- //-----------------------------------------------------------------------------------------------
- const int64_t timeDeltaMs = itemBack.first - itemFront.first;
- const double bytesDelta = itemBack.second.bytes_ - itemFront.second.bytes_;
+ 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
- //objects model logical operations *NOT* disk accesses, so we better play safe and use "bytes" only!
- //http://sourceforge.net/p/freefilesync/feature-requests/197/
+ //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;
- if (!numeric::isNull(bytesDelta)) //sign(dataRemaining) != sign(bytesDelta) usually an error, so show it!
- return dataRemaining * timeDeltaMs / 1000.0 / bytesDelta;
- }
return NoValue();
}
-zen::Opt<std::wstring> PerfCheck::getBytesPerSecond() const
+Opt<std::wstring> PerfCheck::getBytesPerSecond() const
{
- auto blk = getBlockFromEnd(windowSizeSpeed_);
- if (blk.first && blk.second)
- {
- const auto& itemFront = *blk.first;
- const auto& itemBack = *blk.second;
- //-----------------------------------------------------------------------------------------------
- const int64_t timeDeltaMs = itemBack.first - itemFront.first;
- const double bytesDelta = itemBack.second.bytes_ - itemFront.second.bytes_;
-
- if (timeDeltaMs != 0)
- return formatFilesizeShort(static_cast<int64_t>(bytesDelta * 1000.0 / timeDeltaMs)) + _("/sec");
- }
+ double timeDelta = 0;
+ int itemsDelta = 0;
+ double bytesDelta = 0;
+ std::tie(timeDelta, itemsDelta, bytesDelta) = getBlockDeltas(windowSizeSpeed_);
+
+ if (!numeric::isNull(timeDelta))
+ return formatFilesizeShort(numeric::round(bytesDelta / timeDelta)) + _("/sec");
+
return NoValue();
}
-zen::Opt<std::wstring> PerfCheck::getItemsPerSecond() const
+Opt<std::wstring> PerfCheck::getItemsPerSecond() const
{
- auto blk = getBlockFromEnd(windowSizeSpeed_);
- if (blk.first && blk.second)
- {
- const auto& itemFront = *blk.first;
- const auto& itemBack = *blk.second;
- //-----------------------------------------------------------------------------------------------
- const int64_t timeDeltaMs = itemBack.first - itemFront.first;
- const int itemsDelta = itemBack.second.items_ - itemFront.second.items_;
-
- if (timeDeltaMs != 0)
- return replaceCpy(_("%x items/sec"), L"%x", formatTwoDigitPrecision(itemsDelta * 1000.0 / timeDeltaMs));
- }
+ double timeDelta = 0;
+ int itemsDelta = 0;
+ double bytesDelta = 0;
+ std::tie(timeDelta, itemsDelta, bytesDelta) = getBlockDeltas(windowSizeSpeed_);
+
+ if (!numeric::isNull(timeDelta))
+ return replaceCpy(_("%x items/sec"), L"%x", formatTwoDigitPrecision(itemsDelta / timeDelta));
+
return NoValue();
}
diff --git a/FreeFileSync/Source/lib/perf_check.h b/FreeFileSync/Source/lib/perf_check.h
index 1f85ba63..401d08f5 100755
--- a/FreeFileSync/Source/lib/perf_check.h
+++ b/FreeFileSync/Source/lib/perf_check.h
@@ -7,41 +7,41 @@
#ifndef PERF_CHECK_H_87804217589312454
#define PERF_CHECK_H_87804217589312454
-#include <cstdint>
#include <map>
+#include <chrono>
#include <string>
#include <zen/optional.h>
+namespace fff
+{
class PerfCheck
{
public:
- PerfCheck(unsigned int windowSizeRemainingTime, //unit: [ms]
- unsigned int windowSizeSpeed); //
- ~PerfCheck();
+ PerfCheck(std::chrono::milliseconds windowSizeRemTime,
+ std::chrono::milliseconds windowSizeSpeed);
- void addSample(int itemsCurrent, double dataCurrent, int64_t timeMs); //timeMs must be ascending!
+ void addSample(std::chrono::nanoseconds timeElapsed, int itemsCurrent, double dataCurrent);
zen::Opt<double> getRemainingTimeSec(double dataRemaining) const;
zen::Opt<std::wstring> getBytesPerSecond() const; //for window
- zen::Opt<std::wstring> getItemsPerSecond() const; //for window
+ zen::Opt<std::wstring> getItemsPerSecond() const; //
private:
struct Record
{
- Record(int items, double bytes) : items_(items), bytes_(bytes) {}
- const int items_;
- const double bytes_;
+ int items = 0;
+ double bytes = 0;
};
- std::pair<const std::multimap<int64_t, Record>::value_type*,
- const std::multimap<int64_t, Record>::value_type*> getBlockFromEnd(int64_t windowSize) const;
+ std::tuple<double, int, double> getBlockDeltas(std::chrono::milliseconds windowSize) const;
- const int64_t windowSizeRemTime; //unit: [ms]
- const int64_t windowSizeSpeed_; //
- const int64_t windowMax;
+ const std::chrono::milliseconds windowSizeRemTime_;
+ const std::chrono::milliseconds windowSizeSpeed_;
+ const std::chrono::milliseconds windowMax_;
- std::map<int64_t, Record> samples; //time, unit: [ms]
+ std::map<std::chrono::nanoseconds, Record> samples_;
};
+}
#endif //PERF_CHECK_H_87804217589312454
diff --git a/FreeFileSync/Source/lib/process_xml.cpp b/FreeFileSync/Source/lib/process_xml.cpp
index 8c9eb0b2..2b9b52c8 100755
--- a/FreeFileSync/Source/lib/process_xml.cpp
+++ b/FreeFileSync/Source/lib/process_xml.cpp
@@ -5,7 +5,6 @@
// *****************************************************************************
#include "process_xml.h"
-#include <utility>
#include <zenxml/xml.h>
#include <zen/file_access.h>
#include <zen/file_io.h>
@@ -16,16 +15,14 @@
using namespace zen;
-using namespace xmlAccess; //functionally needed for correct overload resolution!!!
-using namespace std::rel_ops;
+using namespace fff; //functionally needed for correct overload resolution!!!
namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
-const int XML_FORMAT_VER_GLOBAL = 6; //2018-01-08
-const int XML_FORMAT_VER_FFS_GUI = 8; //2017-10-24
-const int XML_FORMAT_VER_FFS_BATCH = 8; //
+const int XML_FORMAT_VER_GLOBAL = 8; //2018-02-01
+const int XML_FORMAT_VER_FFS_CFG = 9; //2018-02-01
//-------------------------------------------------------------------------------------------------------------------------------
}
@@ -48,10 +45,10 @@ XmlType getXmlTypeNoThrow(const XmlDoc& doc) //throw()
}
-XmlType xmlAccess::getXmlType(const Zstring& filepath) //throw FileError
+XmlType fff::getXmlType(const Zstring& filePath) //throw FileError
{
//do NOT use zen::loadStream as it will needlessly load even huge files!
- XmlDoc doc = loadXmlDocument(filepath); //throw FileError; quick exit if file is not an FFS XML
+ XmlDoc doc = loadXmlDocument(filePath); //throw FileError; quick exit if file is not an FFS XML
return ::getXmlTypeNoThrow(doc);
}
@@ -82,13 +79,13 @@ XmlGlobalSettings::XmlGlobalSettings()
//################################################################################################################
-Zstring xmlAccess::getGlobalConfigFile()
+Zstring fff::getGlobalConfigFile()
{
- return zen::getConfigDirPathPf() + Zstr("GlobalSettings.xml");
+ return getConfigDirPathPf() + Zstr("GlobalSettings.xml");
}
-XmlGuiConfig xmlAccess::convertBatchToGui(const XmlBatchConfig& batchCfg) //noexcept
+XmlGuiConfig fff::convertBatchToGui(const XmlBatchConfig& batchCfg) //noexcept
{
XmlGuiConfig output;
output.mainCfg = batchCfg.mainCfg;
@@ -96,7 +93,7 @@ XmlGuiConfig xmlAccess::convertBatchToGui(const XmlBatchConfig& batchCfg) //noex
}
-XmlBatchConfig xmlAccess::convertGuiToBatch(const XmlGuiConfig& guiCfg, const BatchExclusiveConfig& batchExCfg) //noexcept
+XmlBatchConfig fff::convertGuiToBatch(const XmlGuiConfig& guiCfg, const BatchExclusiveConfig& batchExCfg) //noexcept
{
XmlBatchConfig output;
output.mainCfg = guiCfg.mainCfg;
@@ -284,11 +281,8 @@ void writeText(const PostSyncAction& value, std::string& output)
{
switch (value)
{
- case PostSyncAction::SUMMARY:
- output = "Summary";
- break;
- case PostSyncAction::EXIT:
- output = "Exit";
+ case PostSyncAction::NONE:
+ output = "None";
break;
case PostSyncAction::SLEEP:
output = "Sleep";
@@ -303,10 +297,8 @@ template <> inline
bool readText(const std::string& input, PostSyncAction& value)
{
const std::string tmp = trimCpy(input);
- if (tmp == "Summary")
- value = PostSyncAction::SUMMARY;
- else if (tmp == "Exit")
- value = PostSyncAction::EXIT;
+ if (tmp == "None")
+ value = PostSyncAction::NONE;
else if (tmp == "Sleep")
value = PostSyncAction::SLEEP;
else if (tmp == "Shutdown")
@@ -770,10 +762,9 @@ bool readStruc(const XmlElement& input, ViewFilterDefault& value)
success = false;
};
- XmlIn sharedView = in["Shared"];
- readAttr(sharedView, "Equal", value.equal);
- readAttr(sharedView, "Conflict", value.conflict);
- readAttr(sharedView, "Excluded", value.excluded);
+ readAttr(in, "Equal", value.equal);
+ readAttr(in, "Conflict", value.conflict);
+ readAttr(in, "Excluded", value.excluded);
XmlIn catView = in["CategoryView"];
readAttr(catView, "LeftOnly", value.leftOnly);
@@ -799,10 +790,9 @@ void writeStruc(const ViewFilterDefault& value, XmlElement& output)
{
XmlOut out(output);
- XmlOut sharedView = out["Shared"];
- sharedView.attribute("Equal", value.equal);
- sharedView.attribute("Conflict", value.conflict);
- sharedView.attribute("Excluded", value.excluded);
+ out.attribute("Equal", value.equal);
+ out.attribute("Conflict", value.conflict);
+ out.attribute("Excluded", value.excluded);
XmlOut catView = out["CategoryView"];
catView.attribute("LeftOnly", value.leftOnly);
@@ -820,6 +810,24 @@ void writeStruc(const ViewFilterDefault& value, XmlElement& output)
actView.attribute("DeleteRight", value.deleteRight);
actView.attribute("DoNothing", value.doNothing);
}
+
+
+template <> inline
+bool readStruc(const XmlElement& input, ExternalApp& value)
+{
+ XmlIn in(input);
+ const bool rv1 = in(value.cmdLine);
+ const bool rv2 = in.attribute("Label", value.description);
+ return rv1 && rv2;
+}
+
+template <> inline
+void writeStruc(const ExternalApp& value, XmlElement& output)
+{
+ XmlOut out(output);
+ out(value.cmdLine);
+ out.attribute("Label", value.description);
+}
}
@@ -870,45 +878,45 @@ void writeStruc(const ConfigFileItem& value, XmlElement& output)
namespace
{
-void readConfig(const XmlIn& in, CompConfig& cmpConfig)
+void readConfig(const XmlIn& in, CompConfig& cmpCfg)
{
- in["Variant" ](cmpConfig.compareVar);
- in["Symlinks"](cmpConfig.handleSymlinks);
+ in["Variant" ](cmpCfg.compareVar);
+ in["Symlinks"](cmpCfg.handleSymlinks);
//TODO: remove old parameter after migration! 2015-11-05
if (in["TimeShift"])
{
std::wstring timeShiftPhrase;
if (in["TimeShift"](timeShiftPhrase))
- cmpConfig.ignoreTimeShiftMinutes = fromTimeShiftPhrase(timeShiftPhrase);
+ cmpCfg.ignoreTimeShiftMinutes = fromTimeShiftPhrase(timeShiftPhrase);
}
else
{
std::wstring timeShiftPhrase;
if (in["IgnoreTimeShift"](timeShiftPhrase))
- cmpConfig.ignoreTimeShiftMinutes = fromTimeShiftPhrase(timeShiftPhrase);
+ cmpCfg.ignoreTimeShiftMinutes = fromTimeShiftPhrase(timeShiftPhrase);
}
}
-void readConfig(const XmlIn& in, DirectionConfig& directCfg)
+void readConfig(const XmlIn& in, DirectionConfig& dirCfg)
{
- in["Variant"](directCfg.var);
+ in["Variant"](dirCfg.var);
- if (directCfg.var == DirectionConfig::CUSTOM)
+ if (dirCfg.var == DirectionConfig::CUSTOM)
{
XmlIn inCustDir = in["CustomDirections"];
- inCustDir["LeftOnly" ](directCfg.custom.exLeftSideOnly);
- inCustDir["RightOnly" ](directCfg.custom.exRightSideOnly);
- inCustDir["LeftNewer" ](directCfg.custom.leftNewer);
- inCustDir["RightNewer"](directCfg.custom.rightNewer);
- inCustDir["Different" ](directCfg.custom.different);
- inCustDir["Conflict" ](directCfg.custom.conflict);
+ inCustDir["LeftOnly" ](dirCfg.custom.exLeftSideOnly);
+ inCustDir["RightOnly" ](dirCfg.custom.exRightSideOnly);
+ inCustDir["LeftNewer" ](dirCfg.custom.leftNewer);
+ inCustDir["RightNewer"](dirCfg.custom.rightNewer);
+ inCustDir["Different" ](dirCfg.custom.different);
+ inCustDir["Conflict" ](dirCfg.custom.conflict);
}
else
- directCfg.custom = DirectionSet();
+ dirCfg.custom = DirectionSet();
- in["DetectMovedFiles"](directCfg.detectMovedFiles);
+ in["DetectMovedFiles"](dirCfg.detectMovedFiles);
}
@@ -1056,96 +1064,127 @@ void readConfig(const XmlIn& in, MainConfiguration& mainCfg, int formatVer)
}
-void readConfig(const XmlIn& in, XmlGuiConfig& config, int formatVer)
+void readConfig(const XmlIn& in, XmlGuiConfig& cfg, int formatVer)
{
//read main config
- readConfig(in, config.mainCfg, formatVer);
+ readConfig(in, cfg.mainCfg, formatVer);
//read GUI specific config data
XmlIn inGuiCfg = in["GuiConfig"];
std::string val;
if (inGuiCfg["MiddleGridView"](val)) //refactor into enum!?
- config.highlightSyncAction = val == "Action";
+ cfg.highlightSyncAction = val == "Action";
//TODO: remove if clause after migration! 2017-10-24
if (formatVer < 8)
{
std::string str;
if (inGuiCfg["HandleError"](str))
- config.mainCfg.ignoreErrors = str == "Ignore";
+ cfg.mainCfg.ignoreErrors = str == "Ignore";
- str = trimCpy(utfTo<std::string>(config.mainCfg.postSyncCommand));
- if (str == "Close progress dialog")
- config.mainCfg.postSyncCommand.clear();
+ str = trimCpy(utfTo<std::string>(cfg.mainCfg.postSyncCommand));
+ if (strEqual(str, "Close progress dialog", CmpAsciiNoCase()))
+ cfg.mainCfg.postSyncCommand.clear();
}
}
-void readConfig(const XmlIn& in, BatchExclusiveConfig& config, int formatVer)
+void readConfig(const XmlIn& in, BatchExclusiveConfig& cfg, int formatVer)
{
XmlIn inBatchCfg = in["BatchConfig"];
+ //TODO: remove if clause after migration! 2018-02-01
+ if (formatVer < 9)
+ inBatchCfg["RunMinimized"](cfg.runMinimized);
+ else
+ inBatchCfg["ProgressDialog"].attribute("Minimized", cfg.runMinimized);
+
+ //TODO: remove if clause after migration! 2018-02-01
+ if (formatVer < 9)
+ ; //n/a
+ else
+ inBatchCfg["ProgressDialog"].attribute("AutoClose", cfg.autoCloseSummary);
+
//TODO: remove if clause after migration! 2017-10-24
if (formatVer < 8)
{
std::string str;
if (inBatchCfg["HandleError"](str))
- config.batchErrorDialog = str == "Stop" ? BatchErrorDialog::CANCEL : BatchErrorDialog::SHOW;
+ cfg.batchErrorDialog = str == "Stop" ? BatchErrorDialog::CANCEL : BatchErrorDialog::SHOW;
}
else
+ inBatchCfg["ErrorDialog"](cfg.batchErrorDialog);
+
+ //TODO: remove if clause after migration! 2017-10-24
+ if (formatVer < 8)
+ ; //n/a
+ //TODO: remove if clause after migration! 2018-02-01
+ else if (formatVer == 8)
{
- inBatchCfg["ErrorDialog"](config.batchErrorDialog);
- inBatchCfg["PostSyncAction"](config.postSyncAction);
+ std::string tmp;
+ if (inBatchCfg["PostSyncAction"](tmp))
+ {
+ tmp = trimCpy(tmp);
+ if (tmp == "Summary")
+ cfg.postSyncAction = PostSyncAction::NONE;
+ else if (tmp == "Exit")
+ cfg.autoCloseSummary = true;
+ else if (tmp == "Sleep")
+ cfg.postSyncAction = PostSyncAction::SLEEP;
+ else if (tmp == "Shutdown")
+ cfg.postSyncAction = PostSyncAction::SHUTDOWN;
+ }
}
+ else
+ inBatchCfg["PostSyncAction"](cfg.postSyncAction);
- inBatchCfg["RunMinimized" ](config.runMinimized);
- inBatchCfg["LogfileFolder"](config.logFolderPathPhrase);
- inBatchCfg["LogfileFolder"].attribute("Limit", config.logfilesCountLimit);
+ inBatchCfg["LogfileFolder"](cfg.logFolderPathPhrase);
+ inBatchCfg["LogfileFolder"].attribute("Limit", cfg.logfilesCountLimit);
}
-void readConfig(const XmlIn& in, XmlBatchConfig& config, int formatVer)
+void readConfig(const XmlIn& in, XmlBatchConfig& cfg, int formatVer)
{
- readConfig(in, config.mainCfg, formatVer);
- readConfig(in, config.batchExCfg, formatVer);
+ readConfig(in, cfg.mainCfg, formatVer);
+ readConfig(in, cfg.batchExCfg, formatVer);
//TODO: remove if clause after migration! 2017-10-24
if (formatVer < 8)
{
std::string str;
if (in["BatchConfig"]["HandleError"](str))
- config.mainCfg.ignoreErrors = str == "Ignore";
+ cfg.mainCfg.ignoreErrors = str == "Ignore";
- str = trimCpy(utfTo<std::string>(config.mainCfg.postSyncCommand));
- if (str == "Close progress dialog")
+ str = trimCpy(utfTo<std::string>(cfg.mainCfg.postSyncCommand));
+ if (strEqual(str, "Close progress dialog", CmpAsciiNoCase()))
{
- config.batchExCfg.postSyncAction = PostSyncAction::EXIT;
- config.mainCfg.postSyncCommand.clear();
+ cfg.batchExCfg.autoCloseSummary = true;
+ cfg.mainCfg.postSyncCommand.clear();
}
else if (str == "rundll32.exe powrprof.dll,SetSuspendState Sleep" ||
str == "rundll32.exe powrprof.dll,SetSuspendState" ||
str == "systemctl suspend" ||
str == "osascript -e \'tell application \"System Events\" to sleep\'")
{
- config.batchExCfg.postSyncAction = PostSyncAction::SLEEP;
- config.mainCfg.postSyncCommand.clear();
+ cfg.batchExCfg.postSyncAction = PostSyncAction::SLEEP;
+ cfg.mainCfg.postSyncCommand.clear();
}
else if (str == "shutdown /s /t 60" ||
str == "shutdown -s -t 60" ||
str == "systemctl poweroff" ||
str == "osascript -e \'tell application \"System Events\" to shut down\'")
{
- config.batchExCfg.postSyncAction = PostSyncAction::SHUTDOWN;
- config.mainCfg.postSyncCommand.clear();
+ cfg.batchExCfg.postSyncAction = PostSyncAction::SHUTDOWN;
+ cfg.mainCfg.postSyncCommand.clear();
}
- else if (config.batchExCfg.runMinimized)
- config.batchExCfg.postSyncAction = PostSyncAction::EXIT;
+ else if (cfg.batchExCfg.runMinimized)
+ cfg.batchExCfg.autoCloseSummary = true;
}
}
-void readConfig(const XmlIn& in, XmlGlobalSettings& config, int formatVer)
+void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
{
XmlIn inGeneral = in["General"];
@@ -1153,92 +1192,118 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config, int formatVer)
if (in["Shared"])
inGeneral = in["Shared"];
- inGeneral["Language"].attribute("Name", config.programLanguage);
-
- inGeneral["FailSafeFileCopy" ].attribute("Enabled", config.failSafeFileCopy);
- inGeneral["CopyLockedFiles" ].attribute("Enabled", config.copyLockedFiles);
- inGeneral["CopyFilePermissions" ].attribute("Enabled", config.copyFilePermissions);
- inGeneral["AutomaticRetry" ].attribute("Count", config.automaticRetryCount);
- inGeneral["AutomaticRetry" ].attribute("Delay", config.automaticRetryDelay);
- inGeneral["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance);
- inGeneral["FolderAccessTimeout" ].attribute("Seconds", config.folderAccessTimeout);
- inGeneral["RunWithBackgroundPriority"].attribute("Enabled", config.runWithBackgroundPriority);
- inGeneral["LockDirectoriesDuringSync"].attribute("Enabled", config.createLockFile);
- inGeneral["VerifyCopiedFiles" ].attribute("Enabled", config.verifyFileCopy);
- inGeneral["LastSyncsLogSizeMax" ].attribute("Bytes", config.lastSyncsLogFileSizeMax);
- inGeneral["NotificationSound" ].attribute("CompareFinished", config.soundFileCompareFinished);
- inGeneral["NotificationSound" ].attribute("SyncFinished", config.soundFileSyncFinished);
-
- XmlIn inOpt = inGeneral["OptionalDialogs"];
- inOpt["WarnUnresolvedConflicts" ].attribute("Enabled", config.optDialogs.warnUnresolvedConflicts);
- inOpt["WarnNotEnoughDiskSpace" ].attribute("Enabled", config.optDialogs.warnNotEnoughDiskSpace);
- inOpt["WarnSignificantDifference" ].attribute("Enabled", config.optDialogs.warnSignificantDifference);
- inOpt["WarnRecycleBinNotAvailable" ].attribute("Enabled", config.optDialogs.warnRecyclerMissing);
- inOpt["WarnInputFieldEmpty" ].attribute("Enabled", config.optDialogs.warnInputFieldEmpty);
- inOpt["WarnModificationTimeError" ].attribute("Enabled", config.optDialogs.warnModificationTimeError);
- //inOpt["WarnDatabaseError" ].attribute("Enabled", config.optDialogs.warnDatabaseError);
- inOpt["WarnDependentFolderPair" ].attribute("Enabled", config.optDialogs.warnDependentFolderPair);
- inOpt["WarnDependentBaseFolders" ].attribute("Enabled", config.optDialogs.warnDependentBaseFolders);
- inOpt["WarnDirectoryLockFailed" ].attribute("Enabled", config.optDialogs.warnDirectoryLockFailed);
- inOpt["WarnVersioningFolderPartOfSync" ].attribute("Enabled", config.optDialogs.warnVersioningFolderPartOfSync);
- inOpt["ConfirmSaveConfig" ].attribute("Enabled", config.optDialogs.popupOnConfigChange);
- inOpt["ConfirmStartSync" ].attribute("Enabled", config.optDialogs.confirmSyncStart);
- inOpt["ConfirmExternalCommandMassInvoke"].attribute("Enabled", config.optDialogs.confirmExternalCommandMassInvoke);
+ inGeneral["Language"].attribute("Name", cfg.programLanguage);
+
+ inGeneral["FailSafeFileCopy" ].attribute("Enabled", cfg.failSafeFileCopy);
+ inGeneral["CopyLockedFiles" ].attribute("Enabled", cfg.copyLockedFiles);
+ inGeneral["CopyFilePermissions" ].attribute("Enabled", cfg.copyFilePermissions);
+ inGeneral["AutomaticRetry" ].attribute("Count", cfg.automaticRetryCount);
+ inGeneral["AutomaticRetry" ].attribute("Delay", cfg.automaticRetryDelay);
+ inGeneral["FileTimeTolerance" ].attribute("Seconds", cfg.fileTimeTolerance);
+ inGeneral["FolderAccessTimeout" ].attribute("Seconds", cfg.folderAccessTimeout);
+ inGeneral["RunWithBackgroundPriority"].attribute("Enabled", cfg.runWithBackgroundPriority);
+ inGeneral["LockDirectoriesDuringSync"].attribute("Enabled", cfg.createLockFile);
+ inGeneral["VerifyCopiedFiles" ].attribute("Enabled", cfg.verifyFileCopy);
+ inGeneral["LastSyncsLogSizeMax" ].attribute("Bytes", cfg.lastSyncsLogFileSizeMax);
+ inGeneral["NotificationSound" ].attribute("CompareFinished", cfg.soundFileCompareFinished);
+ inGeneral["NotificationSound" ].attribute("SyncFinished", cfg.soundFileSyncFinished);
+ inGeneral["ProgressDialog" ].attribute("AutoClose", cfg.autoCloseProgressDialog);
+
+ //TODO: remove old parameter after migration! 2018-02-04
+ if (formatVer < 8)
+ {
+ XmlIn inOpt = inGeneral["OptionalDialogs"];
+ inOpt["ConfirmStartSync" ].attribute("Enabled", cfg.confirmDlgs.confirmSyncStart);
+ inOpt["ConfirmSaveConfig" ].attribute("Enabled", cfg.confirmDlgs.popupOnConfigChange);
+ inOpt["ConfirmExternalCommandMassInvoke"].attribute("Enabled", cfg.confirmDlgs.confirmExternalCommandMassInvoke);
+ inOpt["WarnUnresolvedConflicts" ].attribute("Enabled", cfg.warnDlgs.warnUnresolvedConflicts);
+ inOpt["WarnNotEnoughDiskSpace" ].attribute("Enabled", cfg.warnDlgs.warnNotEnoughDiskSpace);
+ inOpt["WarnSignificantDifference" ].attribute("Enabled", cfg.warnDlgs.warnSignificantDifference);
+ inOpt["WarnRecycleBinNotAvailable" ].attribute("Enabled", cfg.warnDlgs.warnRecyclerMissing);
+ inOpt["WarnInputFieldEmpty" ].attribute("Enabled", cfg.warnDlgs.warnInputFieldEmpty);
+ inOpt["WarnModificationTimeError" ].attribute("Enabled", cfg.warnDlgs.warnModificationTimeError);
+ inOpt["WarnDependentFolderPair" ].attribute("Enabled", cfg.warnDlgs.warnDependentFolderPair);
+ inOpt["WarnDependentBaseFolders" ].attribute("Enabled", cfg.warnDlgs.warnDependentBaseFolders);
+ inOpt["WarnDirectoryLockFailed" ].attribute("Enabled", cfg.warnDlgs.warnDirectoryLockFailed);
+ inOpt["WarnVersioningFolderPartOfSync"].attribute("Enabled", cfg.warnDlgs.warnVersioningFolderPartOfSync);
+ }
+ else
+ {
+ XmlIn inOpt = inGeneral["OptionalDialogs"];
+ inOpt["ConfirmStartSync" ].attribute("Show", cfg.confirmDlgs.confirmSyncStart);
+ inOpt["ConfirmSaveConfig" ].attribute("Show", cfg.confirmDlgs.popupOnConfigChange);
+ inOpt["ConfirmExternalCommandMassInvoke"].attribute("Show", cfg.confirmDlgs.confirmExternalCommandMassInvoke);
+ inOpt["WarnUnresolvedConflicts" ].attribute("Show", cfg.warnDlgs.warnUnresolvedConflicts);
+ inOpt["WarnNotEnoughDiskSpace" ].attribute("Show", cfg.warnDlgs.warnNotEnoughDiskSpace);
+ inOpt["WarnSignificantDifference" ].attribute("Show", cfg.warnDlgs.warnSignificantDifference);
+ inOpt["WarnRecycleBinNotAvailable" ].attribute("Show", cfg.warnDlgs.warnRecyclerMissing);
+ inOpt["WarnInputFieldEmpty" ].attribute("Show", cfg.warnDlgs.warnInputFieldEmpty);
+ inOpt["WarnModificationTimeError" ].attribute("Show", cfg.warnDlgs.warnModificationTimeError);
+ inOpt["WarnDependentFolderPair" ].attribute("Show", cfg.warnDlgs.warnDependentFolderPair);
+ inOpt["WarnDependentBaseFolders" ].attribute("Show", cfg.warnDlgs.warnDependentBaseFolders);
+ inOpt["WarnDirectoryLockFailed" ].attribute("Show", cfg.warnDlgs.warnDirectoryLockFailed);
+ inOpt["WarnVersioningFolderPartOfSync"].attribute("Show", cfg.warnDlgs.warnVersioningFolderPartOfSync);
+ }
//gui specific global settings (optional)
XmlIn inGui = in["Gui"];
XmlIn inWnd = inGui["MainDialog"];
//read application window size and position
- inWnd.attribute("Width", config.gui.mainDlg.dlgSize.x);
- inWnd.attribute("Height", config.gui.mainDlg.dlgSize.y);
- inWnd.attribute("PosX", config.gui.mainDlg.dlgPos.x);
- inWnd.attribute("PosY", config.gui.mainDlg.dlgPos.y);
- inWnd.attribute("Maximized", config.gui.mainDlg.isMaximized);
+ inWnd.attribute("Width", cfg.gui.mainDlg.dlgSize.x);
+ inWnd.attribute("Height", cfg.gui.mainDlg.dlgSize.y);
+ inWnd.attribute("PosX", cfg.gui.mainDlg.dlgPos.x);
+ inWnd.attribute("PosY", cfg.gui.mainDlg.dlgPos.y);
+ inWnd.attribute("Maximized", cfg.gui.mainDlg.isMaximized);
XmlIn inCopyTo = inWnd["ManualCopyTo"];
- inCopyTo.attribute("KeepRelativePaths", config.gui.mainDlg.copyToCfg.keepRelPaths);
- inCopyTo.attribute("OverwriteIfExists", config.gui.mainDlg.copyToCfg.overwriteIfExists);
+ inCopyTo.attribute("KeepRelativePaths", cfg.gui.mainDlg.copyToCfg.keepRelPaths);
+ inCopyTo.attribute("OverwriteIfExists", cfg.gui.mainDlg.copyToCfg.overwriteIfExists);
XmlIn inCopyToHistory = inCopyTo["FolderHistory"];
- inCopyToHistory(config.gui.mainDlg.copyToCfg.folderHistory);
- inCopyToHistory.attribute("LastUsedPath", config.gui.mainDlg.copyToCfg.lastUsedPath);
- inCopyToHistory.attribute("MaxSize", config.gui.mainDlg.copyToCfg.historySizeMax);
+ 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);
- inWnd["CaseSensitiveSearch"].attribute("Enabled", config.gui.mainDlg.textSearchRespectCase);
- inWnd["FolderPairsVisible" ].attribute("Max", config.gui.mainDlg.maxFolderPairsVisible);
+ inWnd["FolderPairsVisible" ].attribute("Max", cfg.gui.mainDlg.maxFolderPairsVisible);
//###########################################################
XmlIn inConfig = inWnd["ConfigPanel"];
- inConfig.attribute("ScrollPos", config.gui.mainDlg.cfgGridTopRowPos);
- inConfig.attribute("SyncOverdue", config.gui.mainDlg.cfgGridSyncOverdueDays);
- inConfig.attribute("SortByColumn", config.gui.mainDlg.cfgGridLastSortColumn);
- inConfig.attribute("SortAscending", config.gui.mainDlg.cfgGridLastSortAscending);
+ inConfig.attribute("ScrollPos", cfg.gui.mainDlg.cfgGridTopRowPos);
+ inConfig.attribute("SyncOverdue", cfg.gui.mainDlg.cfgGridSyncOverdueDays);
+ inConfig.attribute("SortByColumn", cfg.gui.mainDlg.cfgGridLastSortColumn);
+ inConfig.attribute("SortAscending", cfg.gui.mainDlg.cfgGridLastSortAscending);
- inConfig["Columns"](config.gui.mainDlg.cfgGridColumnAttribs);
+ inConfig["Columns"](cfg.gui.mainDlg.cfgGridColumnAttribs);
//TODO: remove parameter migration after some time! 2018-01-08
if (formatVer < 6)
{
- inGui["ConfigHistory"].attribute("MaxSize", config.gui.mainDlg.cfgHistItemsMax);
+ inGui["ConfigHistory"].attribute("MaxSize", cfg.gui.mainDlg.cfgHistItemsMax);
- std::vector<Zstring> cfgHist;
+ std::vector<Zstring> cfgHist;
inGui["ConfigHistory"](cfgHist);
- for (const Zstring& cfgPath : cfgHist)
- config.gui.mainDlg.cfgFileHistory.emplace_back(cfgPath, 0);
+ for (const Zstring& cfgPath : cfgHist)
+ cfg.gui.mainDlg.cfgFileHistory.emplace_back(cfgPath, 0);
}
else
{
- inConfig["Configurations"].attribute("MaxSize", config.gui.mainDlg.cfgHistItemsMax);
- inConfig["Configurations"](config.gui.mainDlg.cfgFileHistory);
+ inConfig["Configurations"].attribute("MaxSize", cfg.gui.mainDlg.cfgHistItemsMax);
+ inConfig["Configurations"](cfg.gui.mainDlg.cfgFileHistory);
}
//TODO: remove parameter migration after some time! 2018-01-08
if (formatVer < 6)
{
- inGui["LastUsedConfig"](config.gui.mainDlg.lastUsedConfigFiles);
+ inGui["LastUsedConfig"](cfg.gui.mainDlg.lastUsedConfigFiles);
}
else
{
@@ -1248,116 +1313,144 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config, int formatVer)
for (Zstring& filePath : cfgPaths)
filePath = resolveFreeFileSyncDriveMacro(filePath);
- config.gui.mainDlg.lastUsedConfigFiles = cfgPaths;
+ cfg.gui.mainDlg.lastUsedConfigFiles = cfgPaths;
}
}
//###########################################################
XmlIn inOverview = inWnd["OverviewPanel"];
- inOverview.attribute("ShowPercentage", config.gui.mainDlg.treeGridShowPercentBar);
- inOverview.attribute("SortByColumn", config.gui.mainDlg.treeGridLastSortColumn);
- inOverview.attribute("SortAscending", config.gui.mainDlg.treeGridLastSortAscending);
+ inOverview.attribute("ShowPercentage", cfg.gui.mainDlg.treeGridShowPercentBar);
+ inOverview.attribute("SortByColumn", cfg.gui.mainDlg.treeGridLastSortColumn);
+ inOverview.attribute("SortAscending", cfg.gui.mainDlg.treeGridLastSortAscending);
//read column attributes
XmlIn inColTree = inOverview["Columns"];
- inColTree(config.gui.mainDlg.treeGridColumnAttribs);
+ inColTree(cfg.gui.mainDlg.treeGridColumnAttribs);
XmlIn inFileGrid = inWnd["FilePanel"];
//TODO: remove parameter migration after some time! 2018-01-08
if (formatVer < 6)
inFileGrid = inWnd["CenterPanel"];
- inFileGrid.attribute("ShowIcons", config.gui.mainDlg.showIcons);
- inFileGrid.attribute("IconSize", config.gui.mainDlg.iconSize);
- inFileGrid.attribute("SashOffset", config.gui.mainDlg.sashOffset);
- inFileGrid.attribute("HistoryMaxSize", config.gui.mainDlg.folderHistItemsMax);
+ 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);
- inFileGrid["ColumnsLeft"].attribute("PathFormat", config.gui.mainDlg.itemPathFormatLeftGrid);
- inFileGrid["ColumnsLeft"](config.gui.mainDlg.columnAttribLeft);
+ inFileGrid["ColumnsLeft"].attribute("PathFormat", cfg.gui.mainDlg.itemPathFormatLeftGrid);
+ inFileGrid["ColumnsLeft"](cfg.gui.mainDlg.columnAttribLeft);
- inFileGrid["FolderHistoryLeft" ](config.gui.mainDlg.folderHistoryLeft);
+ inFileGrid["FolderHistoryLeft" ](cfg.gui.mainDlg.folderHistoryLeft);
- inFileGrid["ColumnsRight"].attribute("PathFormat", config.gui.mainDlg.itemPathFormatRightGrid);
- inFileGrid["ColumnsRight"](config.gui.mainDlg.columnAttribRight);
+ inFileGrid["ColumnsRight"].attribute("PathFormat", cfg.gui.mainDlg.itemPathFormatRightGrid);
+ inFileGrid["ColumnsRight"](cfg.gui.mainDlg.columnAttribRight);
- inFileGrid["FolderHistoryRight"](config.gui.mainDlg.folderHistoryRight);
+ inFileGrid["FolderHistoryRight"](cfg.gui.mainDlg.folderHistoryRight);
//TODO: remove parameter migration after some time! 2018-01-08
if (formatVer < 6)
{
- inGui["FolderHistoryLeft" ](config.gui.mainDlg.folderHistoryLeft);
- inGui["FolderHistoryRight"](config.gui.mainDlg.folderHistoryRight);
- inGui["FolderHistoryLeft"].attribute("MaxSize", config.gui.mainDlg.folderHistItemsMax);
+ inGui["FolderHistoryLeft" ](cfg.gui.mainDlg.folderHistoryLeft);
+ inGui["FolderHistoryRight"](cfg.gui.mainDlg.folderHistoryRight);
+ inGui["FolderHistoryLeft"].attribute("MaxSize", cfg.gui.mainDlg.folderHistItemsMax);
}
//###########################################################
- inWnd["DefaultViewFilter"](config.gui.mainDlg.viewFilterDefault);
- inWnd["Perspective5"](config.gui.mainDlg.guiPerspectiveLast);
+ inWnd["DefaultViewFilter"](cfg.gui.mainDlg.viewFilterDefault);
- std::vector<Zstring> tmp = splitFilterByLines(config.gui.defaultExclusionFilter); //default value
+ //TODO: remove old parameter after migration! 2018-02-04
+ if (formatVer < 8)
+ {
+ XmlIn sharedView = inWnd["DefaultViewFilter"]["Shared"];
+ sharedView.attribute("Equal", cfg.gui.mainDlg.viewFilterDefault.equal);
+ sharedView.attribute("Conflict", cfg.gui.mainDlg.viewFilterDefault.conflict);
+ sharedView.attribute("Excluded", cfg.gui.mainDlg.viewFilterDefault.excluded);
+ }
+
+ //TODO: remove old parameter after migration! 2018-01-16
+ if (formatVer < 7)
+ inWnd["Perspective5"](cfg.gui.mainDlg.guiPerspectiveLast);
+ else
+ inWnd["Perspective"](cfg.gui.mainDlg.guiPerspectiveLast);
+
+ std::vector<Zstring> tmp = splitFilterByLines(cfg.gui.defaultExclusionFilter); //default value
inGui["DefaultExclusionFilter"](tmp);
- config.gui.defaultExclusionFilter = mergeFilterLines(tmp);
+ cfg.gui.defaultExclusionFilter = mergeFilterLines(tmp);
//TODO: remove parameter migration after some time! 2016-09-23
if (formatVer < 4)
- config.gui.mainDlg.cfgHistItemsMax = std::max<size_t>(config.gui.mainDlg.cfgHistItemsMax, 100);
+ cfg.gui.mainDlg.cfgHistItemsMax = std::max<size_t>(cfg.gui.mainDlg.cfgHistItemsMax, 100);
//TODO: remove if clause after migration! 2017-10-24
if (formatVer < 5)
{
- inGui["OnCompletionHistory"](config.gui.commandHistory);
- inGui["OnCompletionHistory"].attribute("MaxSize", config.gui.commandHistItemsMax);
+ inGui["OnCompletionHistory"](cfg.gui.commandHistory);
+ inGui["OnCompletionHistory"].attribute("MaxSize", cfg.gui.commandHistItemsMax);
}
else
{
- inGui["CommandHistory"](config.gui.commandHistory);
- inGui["CommandHistory"].attribute("MaxSize", config.gui.commandHistItemsMax);
+ inGui["CommandHistory"](cfg.gui.commandHistory);
+ inGui["CommandHistory"].attribute("MaxSize", cfg.gui.commandHistItemsMax);
}
//external applications
//TODO: remove old parameter after migration! 2016-05-28
if (inGui["ExternalApplications"])
{
- inGui["ExternalApplications"](config.gui.externelApplications);
- if (config.gui.externelApplications.empty()) //who knows, let's repair some old failed data migrations
- config.gui.externelApplications = XmlGlobalSettings().gui.externelApplications;
+ inGui["ExternalApplications"](cfg.gui.externalApps);
+ if (cfg.gui.externalApps.empty()) //who knows, let's repair some old failed data migrations
+ cfg.gui.externalApps = XmlGlobalSettings().gui.externalApps;
else
{
}
}
else
- inGui["ExternalApps"](config.gui.externelApplications);
+ {
+ //TODO: remove old parameter after migration! 2018-01-16
+ if (formatVer < 7)
+ {
+ std::vector<std::pair<std::wstring, Zstring>> extApps;
+ if (inGui["ExternalApps"](extApps))
+ {
+ cfg.gui.externalApps.clear();
+ for (const auto& item : extApps)
+ cfg.gui.externalApps.push_back({ item.first, item.second });
+ }
+ }
+ else
+ inGui["ExternalApps"](cfg.gui.externalApps);
+ }
//TODO: remove macro migration after some time! 2016-06-30
if (formatVer < 3)
- for (auto& item : config.gui.externelApplications)
+ for (auto& item : cfg.gui.externalApps)
{
- replace(item.second, Zstr("%item2_path%"), Zstr("%item_path2%"));
- replace(item.second, Zstr("%item_folder%"), Zstr("%folder_path%"));
- replace(item.second, Zstr("%item2_folder%"), Zstr("%folder_path2%"));
-
- replace(item.second, Zstr("explorer /select, \"%item_path%\""), Zstr("explorer /select, \"%local_path%\""));
- replace(item.second, Zstr("\"%item_path%\""), Zstr("\"%local_path%\""));
- replace(item.second, Zstr("xdg-open \"%item_path%\""), Zstr("xdg-open \"%local_path%\""));
- replace(item.second, Zstr("open -R \"%item_path%\""), Zstr("open -R \"%local_path%\""));
- replace(item.second, Zstr("open \"%item_path%\""), Zstr("open \"%local_path%\""));
-
- if (contains(makeUpperCopy(item.second), Zstr("WINMERGEU.EXE")) ||
- contains(makeUpperCopy(item.second), Zstr("PSPAD.EXE")))
+ replace(item.cmdLine, Zstr("%item2_path%"), Zstr("%item_path2%"));
+ replace(item.cmdLine, Zstr("%item_folder%"), Zstr("%folder_path%"));
+ replace(item.cmdLine, Zstr("%item2_folder%"), Zstr("%folder_path2%"));
+
+ replace(item.cmdLine, Zstr("explorer /select, \"%item_path%\""), Zstr("explorer /select, \"%local_path%\""));
+ replace(item.cmdLine, Zstr("\"%item_path%\""), Zstr("\"%local_path%\""));
+ replace(item.cmdLine, Zstr("xdg-open \"%item_path%\""), Zstr("xdg-open \"%local_path%\""));
+ replace(item.cmdLine, Zstr("open -R \"%item_path%\""), Zstr("open -R \"%local_path%\""));
+ replace(item.cmdLine, Zstr("open \"%item_path%\""), Zstr("open \"%local_path%\""));
+
+ if (contains(makeUpperCopy(item.cmdLine), Zstr("WINMERGEU.EXE")) ||
+ contains(makeUpperCopy(item.cmdLine), Zstr("PSPAD.EXE")))
{
- replace(item.second, Zstr("%item_path%"), Zstr("%local_path%"));
- replace(item.second, Zstr("%item_path2%"), Zstr("%local_path2%"));
+ replace(item.cmdLine, Zstr("%item_path%"), Zstr("%local_path%"));
+ replace(item.cmdLine, Zstr("%item_path2%"), Zstr("%local_path2%"));
}
}
//TODO: remove macro migration after some time! 2016-07-18
- for (auto& item : config.gui.externelApplications)
- replace(item.second, Zstr("%item_folder%"), Zstr("%folder_path%"));
+ for (auto& item : cfg.gui.externalApps)
+ replace(item.cmdLine, Zstr("%item_folder%"), Zstr("%folder_path%"));
//last update check
- inGui["LastOnlineCheck" ](config.gui.lastUpdateCheck);
- inGui["LastOnlineVersion"](config.gui.lastOnlineVersion);
+ inGui["LastOnlineCheck" ](cfg.gui.lastUpdateCheck);
+ inGui["LastOnlineVersion"](cfg.gui.lastOnlineVersion);
//batch specific global settings
//XmlIn inBatch = in["Batch"];
@@ -1373,12 +1466,12 @@ int getConfigFormatVersion(const XmlDoc& doc)
template <class ConfigType>
-void readConfig(const Zstring& filepath, XmlType type, ConfigType& cfg, int currentXmlFormatVer, std::wstring& warningMsg) //throw FileError
+void readConfig(const Zstring& filePath, XmlType type, ConfigType& cfg, int currentXmlFormatVer, std::wstring& warningMsg) //throw FileError
{
- XmlDoc doc = loadXmlDocument(filepath); //throw FileError
+ XmlDoc doc = loadXmlDocument(filePath); //throw FileError
if (getXmlTypeNoThrow(doc) != type) //noexcept
- throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtPath(filepath)));
+ throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtPath(filePath)));
const int formatVer = getConfigFormatVersion(doc);
@@ -1387,11 +1480,11 @@ void readConfig(const Zstring& filepath, XmlType type, ConfigType& cfg, int curr
try
{
- checkForMappingErrors(in, filepath); //throw FileError
+ checkForMappingErrors(in, filePath); //throw FileError
//(try to) migrate old configuration automatically
if (formatVer< currentXmlFormatVer)
- try { xmlAccess::writeConfig(cfg, filepath); /*throw FileError*/ }
+ try { fff::writeConfig(cfg, filePath); /*throw FileError*/ }
catch (FileError&) { assert(false); } //don't bother user!
}
catch (const FileError& e)
@@ -1402,28 +1495,28 @@ void readConfig(const Zstring& filepath, XmlType type, ConfigType& cfg, int curr
}
-void xmlAccess::readConfig(const Zstring& filepath, XmlGuiConfig& cfg, std::wstring& warningMsg)
+void fff::readConfig(const Zstring& filePath, XmlGuiConfig& cfg, std::wstring& warningMsg)
{
- ::readConfig(filepath, XML_TYPE_GUI, cfg, XML_FORMAT_VER_FFS_GUI, warningMsg); //throw FileError
+ ::readConfig(filePath, XML_TYPE_GUI, cfg, XML_FORMAT_VER_FFS_CFG, warningMsg); //throw FileError
}
-void xmlAccess::readConfig(const Zstring& filepath, XmlBatchConfig& cfg, std::wstring& warningMsg)
+void fff::readConfig(const Zstring& filePath, XmlBatchConfig& cfg, std::wstring& warningMsg)
{
- ::readConfig(filepath, XML_TYPE_BATCH, cfg, XML_FORMAT_VER_FFS_BATCH, warningMsg); //throw FileError
+ ::readConfig(filePath, XML_TYPE_BATCH, cfg, XML_FORMAT_VER_FFS_CFG, warningMsg); //throw FileError
}
-void xmlAccess::readConfig(const Zstring& filepath, XmlGlobalSettings& cfg, std::wstring& warningMsg)
+void fff::readConfig(const Zstring& filePath, XmlGlobalSettings& cfg, std::wstring& warningMsg)
{
- ::readConfig(filepath, XML_TYPE_GLOBAL, cfg, XML_FORMAT_VER_GLOBAL, warningMsg); //throw FileError
+ ::readConfig(filePath, XML_TYPE_GLOBAL, cfg, XML_FORMAT_VER_GLOBAL, warningMsg); //throw FileError
}
namespace
{
template <class XmlCfg>
-XmlCfg parseConfig(const XmlDoc& doc, const Zstring& filepath, int currentXmlFormatVer, std::wstring& warningMsg) //nothrow
+XmlCfg parseConfig(const XmlDoc& doc, const Zstring& filePath, int currentXmlFormatVer, std::wstring& warningMsg) //nothrow
{
const int formatVer = getConfigFormatVersion(doc);
@@ -1433,11 +1526,11 @@ XmlCfg parseConfig(const XmlDoc& doc, const Zstring& filepath, int currentXmlFor
try
{
- checkForMappingErrors(in, filepath); //throw FileError
+ checkForMappingErrors(in, filePath); //throw FileError
//(try to) migrate old configuration if needed
if (formatVer < currentXmlFormatVer)
- try { xmlAccess::writeConfig(cfg, filepath); /*throw FileError*/ }
+ try { fff::writeConfig(cfg, filePath); /*throw FileError*/ }
catch (FileError&) { assert(false); } //don't bother user!
}
catch (const FileError& e)
@@ -1451,76 +1544,76 @@ XmlCfg parseConfig(const XmlDoc& doc, const Zstring& filepath, int currentXmlFor
}
-void xmlAccess::readAnyConfig(const std::vector<Zstring>& filePaths, XmlGuiConfig& config, std::wstring& warningMsg) //throw FileError
+void fff::readAnyConfig(const std::vector<Zstring>& filePaths, XmlGuiConfig& cfg, std::wstring& warningMsg) //throw FileError
{
assert(!filePaths.empty());
- std::vector<zen::MainConfiguration> mainCfgs;
+ std::vector<MainConfiguration> mainCfgs;
for (auto it = filePaths.begin(); it != filePaths.end(); ++it)
{
- const Zstring& filepath = *it;
+ const Zstring& filePath = *it;
const bool firstItem = it == filePaths.begin(); //init all non-"mainCfg" settings with first config file
- XmlDoc doc = loadXmlDocument(filepath); //throw FileError
+ XmlDoc doc = loadXmlDocument(filePath); //throw FileError
switch (getXmlTypeNoThrow(doc))
{
case XML_TYPE_GUI:
{
- XmlGuiConfig guiCfg = parseConfig<XmlGuiConfig>(doc, filepath, XML_FORMAT_VER_FFS_GUI, warningMsg); //nothrow
+ XmlGuiConfig guiCfg = parseConfig<XmlGuiConfig>(doc, filePath, XML_FORMAT_VER_FFS_CFG, warningMsg); //nothrow
if (firstItem)
- config = guiCfg;
+ cfg = guiCfg;
mainCfgs.push_back(guiCfg.mainCfg);
}
break;
case XML_TYPE_BATCH:
{
- XmlBatchConfig batchCfg = parseConfig<XmlBatchConfig>(doc, filepath, XML_FORMAT_VER_FFS_BATCH, warningMsg); //nothrow
+ XmlBatchConfig batchCfg = parseConfig<XmlBatchConfig>(doc, filePath, XML_FORMAT_VER_FFS_CFG, warningMsg); //nothrow
if (firstItem)
- config = convertBatchToGui(batchCfg);
+ cfg = convertBatchToGui(batchCfg);
mainCfgs.push_back(batchCfg.mainCfg);
}
break;
case XML_TYPE_GLOBAL:
case XML_TYPE_OTHER:
- throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtPath(filepath)));
+ throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtPath(filePath)));
}
}
- config.mainCfg = merge(mainCfgs);
+ cfg.mainCfg = merge(mainCfgs);
}
//################################################################################################
namespace
{
-void writeConfig(const CompConfig& cmpConfig, XmlOut& out)
+void writeConfig(const CompConfig& cmpCfg, XmlOut& out)
{
- out["Variant" ](cmpConfig.compareVar);
- out["Symlinks"](cmpConfig.handleSymlinks);
- out["IgnoreTimeShift"](toTimeShiftPhrase(cmpConfig.ignoreTimeShiftMinutes));
+ out["Variant" ](cmpCfg.compareVar);
+ out["Symlinks"](cmpCfg.handleSymlinks);
+ out["IgnoreTimeShift"](toTimeShiftPhrase(cmpCfg.ignoreTimeShiftMinutes));
}
-void writeConfig(const DirectionConfig& directCfg, XmlOut& out)
+void writeConfig(const DirectionConfig& dirCfg, XmlOut& out)
{
- out["Variant"](directCfg.var);
+ out["Variant"](dirCfg.var);
- if (directCfg.var == DirectionConfig::CUSTOM)
+ if (dirCfg.var == DirectionConfig::CUSTOM)
{
XmlOut outCustDir = out["CustomDirections"];
- outCustDir["LeftOnly" ](directCfg.custom.exLeftSideOnly);
- outCustDir["RightOnly" ](directCfg.custom.exRightSideOnly);
- outCustDir["LeftNewer" ](directCfg.custom.leftNewer);
- outCustDir["RightNewer"](directCfg.custom.rightNewer);
- outCustDir["Different" ](directCfg.custom.different);
- outCustDir["Conflict" ](directCfg.custom.conflict);
+ outCustDir["LeftOnly" ](dirCfg.custom.exLeftSideOnly);
+ outCustDir["RightOnly" ](dirCfg.custom.exRightSideOnly);
+ outCustDir["LeftNewer" ](dirCfg.custom.leftNewer);
+ outCustDir["RightNewer"](dirCfg.custom.rightNewer);
+ outCustDir["Different" ](dirCfg.custom.different);
+ outCustDir["Conflict" ](dirCfg.custom.conflict);
}
- out["DetectMovedFiles"](directCfg.detectMovedFiles);
+ out["DetectMovedFiles"](dirCfg.detectMovedFiles);
}
@@ -1619,108 +1712,109 @@ void writeConfig(const MainConfiguration& mainCfg, XmlOut& out)
}
-void writeConfig(const XmlGuiConfig& config, XmlOut& out)
+void writeConfig(const XmlGuiConfig& cfg, XmlOut& out)
{
- writeConfig(config.mainCfg, out); //write main config
+ writeConfig(cfg.mainCfg, out); //write main config
//write GUI specific config data
XmlOut outGuiCfg = out["GuiConfig"];
- outGuiCfg["MiddleGridView"](config.highlightSyncAction ? "Action" : "Category"); //refactor into enum!?
+ outGuiCfg["MiddleGridView"](cfg.highlightSyncAction ? "Action" : "Category"); //refactor into enum!?
}
-void writeConfig(const BatchExclusiveConfig& config, XmlOut& out)
+void writeConfig(const BatchExclusiveConfig& cfg, XmlOut& out)
{
XmlOut outBatchCfg = out["BatchConfig"];
- outBatchCfg["ErrorDialog" ](config.batchErrorDialog);
- outBatchCfg["PostSyncAction"](config.postSyncAction);
- outBatchCfg["RunMinimized" ](config.runMinimized);
- outBatchCfg["LogfileFolder"](config.logFolderPathPhrase);
- outBatchCfg["LogfileFolder"].attribute("Limit", config.logfilesCountLimit);
+ outBatchCfg["ProgressDialog"].attribute("Minimized", cfg.runMinimized);
+ outBatchCfg["ProgressDialog"].attribute("AutoClose", cfg.autoCloseSummary);
+ outBatchCfg["ErrorDialog" ](cfg.batchErrorDialog);
+ outBatchCfg["PostSyncAction"](cfg.postSyncAction);
+ outBatchCfg["LogfileFolder"](cfg.logFolderPathPhrase);
+ outBatchCfg["LogfileFolder"].attribute("Limit", cfg.logfilesCountLimit);
}
-void writeConfig(const XmlBatchConfig& config, XmlOut& out)
+void writeConfig(const XmlBatchConfig& cfg, XmlOut& out)
{
- writeConfig(config.mainCfg, out);
- writeConfig(config.batchExCfg, out);
+ writeConfig(cfg.mainCfg, out);
+ writeConfig(cfg.batchExCfg, out);
}
-void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
+void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
{
XmlOut outGeneral = out["General"];
- outGeneral["Language"].attribute("Name", config.programLanguage);
-
- outGeneral["FailSafeFileCopy" ].attribute("Enabled", config.failSafeFileCopy);
- outGeneral["CopyLockedFiles" ].attribute("Enabled", config.copyLockedFiles);
- outGeneral["CopyFilePermissions" ].attribute("Enabled", config.copyFilePermissions);
- outGeneral["AutomaticRetry" ].attribute("Count", config.automaticRetryCount);
- outGeneral["AutomaticRetry" ].attribute("Delay", config.automaticRetryDelay);
- outGeneral["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance);
- outGeneral["FolderAccessTimeout" ].attribute("Seconds", config.folderAccessTimeout);
- outGeneral["RunWithBackgroundPriority"].attribute("Enabled", config.runWithBackgroundPriority);
- outGeneral["LockDirectoriesDuringSync"].attribute("Enabled", config.createLockFile);
- outGeneral["VerifyCopiedFiles" ].attribute("Enabled", config.verifyFileCopy);
- outGeneral["LastSyncsLogSizeMax" ].attribute("Bytes", config.lastSyncsLogFileSizeMax);
- outGeneral["NotificationSound" ].attribute("CompareFinished", config.soundFileCompareFinished);
- outGeneral["NotificationSound" ].attribute("SyncFinished", config.soundFileSyncFinished);
+ outGeneral["Language"].attribute("Name", cfg.programLanguage);
+
+ outGeneral["FailSafeFileCopy" ].attribute("Enabled", cfg.failSafeFileCopy);
+ outGeneral["CopyLockedFiles" ].attribute("Enabled", cfg.copyLockedFiles);
+ outGeneral["CopyFilePermissions" ].attribute("Enabled", cfg.copyFilePermissions);
+ outGeneral["AutomaticRetry" ].attribute("Count", cfg.automaticRetryCount);
+ outGeneral["AutomaticRetry" ].attribute("Delay", cfg.automaticRetryDelay);
+ outGeneral["FileTimeTolerance" ].attribute("Seconds", cfg.fileTimeTolerance);
+ outGeneral["FolderAccessTimeout" ].attribute("Seconds", cfg.folderAccessTimeout);
+ outGeneral["RunWithBackgroundPriority"].attribute("Enabled", cfg.runWithBackgroundPriority);
+ outGeneral["LockDirectoriesDuringSync"].attribute("Enabled", cfg.createLockFile);
+ outGeneral["VerifyCopiedFiles" ].attribute("Enabled", cfg.verifyFileCopy);
+ outGeneral["LastSyncsLogSizeMax" ].attribute("Bytes", cfg.lastSyncsLogFileSizeMax);
+ outGeneral["NotificationSound" ].attribute("CompareFinished", cfg.soundFileCompareFinished);
+ outGeneral["NotificationSound" ].attribute("SyncFinished", cfg.soundFileSyncFinished);
+ outGeneral["ProgressDialog" ].attribute("AutoClose", cfg.autoCloseProgressDialog);
XmlOut outOpt = outGeneral["OptionalDialogs"];
- outOpt["WarnUnresolvedConflicts" ].attribute("Enabled", config.optDialogs.warnUnresolvedConflicts);
- outOpt["WarnNotEnoughDiskSpace" ].attribute("Enabled", config.optDialogs.warnNotEnoughDiskSpace);
- outOpt["WarnSignificantDifference" ].attribute("Enabled", config.optDialogs.warnSignificantDifference);
- outOpt["WarnRecycleBinNotAvailable" ].attribute("Enabled", config.optDialogs.warnRecyclerMissing);
- outOpt["WarnInputFieldEmpty" ].attribute("Enabled", config.optDialogs.warnInputFieldEmpty);
- outOpt["WarnModificationTimeError" ].attribute("Enabled", config.optDialogs.warnModificationTimeError);
- //outOpt["WarnDatabaseError" ].attribute("Enabled", config.optDialogs.warnDatabaseError);
- outOpt["WarnDependentFolderPair" ].attribute("Enabled", config.optDialogs.warnDependentFolderPair);
- outOpt["WarnDependentBaseFolders" ].attribute("Enabled", config.optDialogs.warnDependentBaseFolders);
- outOpt["WarnDirectoryLockFailed" ].attribute("Enabled", config.optDialogs.warnDirectoryLockFailed);
- outOpt["WarnVersioningFolderPartOfSync" ].attribute("Enabled", config.optDialogs.warnVersioningFolderPartOfSync);
- outOpt["ConfirmSaveConfig" ].attribute("Enabled", config.optDialogs.popupOnConfigChange);
- outOpt["ConfirmStartSync" ].attribute("Enabled", config.optDialogs.confirmSyncStart);
- outOpt["ConfirmExternalCommandMassInvoke"].attribute("Enabled", config.optDialogs.confirmExternalCommandMassInvoke);
+ outOpt["ConfirmStartSync" ].attribute("Show", cfg.confirmDlgs.confirmSyncStart);
+ outOpt["ConfirmSaveConfig" ].attribute("Show", cfg.confirmDlgs.popupOnConfigChange);
+ outOpt["ConfirmExternalCommandMassInvoke"].attribute("Show", cfg.confirmDlgs.confirmExternalCommandMassInvoke);
+ outOpt["WarnUnresolvedConflicts" ].attribute("Show", cfg.warnDlgs.warnUnresolvedConflicts);
+ outOpt["WarnNotEnoughDiskSpace" ].attribute("Show", cfg.warnDlgs.warnNotEnoughDiskSpace);
+ outOpt["WarnSignificantDifference" ].attribute("Show", cfg.warnDlgs.warnSignificantDifference);
+ outOpt["WarnRecycleBinNotAvailable" ].attribute("Show", cfg.warnDlgs.warnRecyclerMissing);
+ outOpt["WarnInputFieldEmpty" ].attribute("Show", cfg.warnDlgs.warnInputFieldEmpty);
+ outOpt["WarnModificationTimeError" ].attribute("Show", cfg.warnDlgs.warnModificationTimeError);
+ outOpt["WarnDependentFolderPair" ].attribute("Show", cfg.warnDlgs.warnDependentFolderPair);
+ outOpt["WarnDependentBaseFolders" ].attribute("Show", cfg.warnDlgs.warnDependentBaseFolders);
+ outOpt["WarnDirectoryLockFailed" ].attribute("Show", cfg.warnDlgs.warnDirectoryLockFailed);
+ outOpt["WarnVersioningFolderPartOfSync"].attribute("Show", cfg.warnDlgs.warnVersioningFolderPartOfSync);
//gui specific global settings (optional)
XmlOut outGui = out["Gui"];
XmlOut outWnd = outGui["MainDialog"];
//write application window size and position
- outWnd.attribute("Width", config.gui.mainDlg.dlgSize.x);
- outWnd.attribute("Height", config.gui.mainDlg.dlgSize.y);
- outWnd.attribute("PosX", config.gui.mainDlg.dlgPos.x);
- outWnd.attribute("PosY", config.gui.mainDlg.dlgPos.y);
- outWnd.attribute("Maximized", config.gui.mainDlg.isMaximized);
+ outWnd.attribute("Width", cfg.gui.mainDlg.dlgSize.x);
+ outWnd.attribute("Height", cfg.gui.mainDlg.dlgSize.y);
+ outWnd.attribute("PosX", cfg.gui.mainDlg.dlgPos.x);
+ outWnd.attribute("PosY", cfg.gui.mainDlg.dlgPos.y);
+ outWnd.attribute("Maximized", cfg.gui.mainDlg.isMaximized);
XmlOut outCopyTo = outWnd["ManualCopyTo"];
- outCopyTo.attribute("KeepRelativePaths", config.gui.mainDlg.copyToCfg.keepRelPaths);
- outCopyTo.attribute("OverwriteIfExists", config.gui.mainDlg.copyToCfg.overwriteIfExists);
+ outCopyTo.attribute("KeepRelativePaths", cfg.gui.mainDlg.copyToCfg.keepRelPaths);
+ outCopyTo.attribute("OverwriteIfExists", cfg.gui.mainDlg.copyToCfg.overwriteIfExists);
XmlOut outCopyToHistory = outCopyTo["FolderHistory"];
- outCopyToHistory(config.gui.mainDlg.copyToCfg.folderHistory);
- outCopyToHistory.attribute("LastUsedPath", config.gui.mainDlg.copyToCfg.lastUsedPath);
- outCopyToHistory.attribute("MaxSize", config.gui.mainDlg.copyToCfg.historySizeMax);
+ outCopyToHistory(cfg.gui.mainDlg.copyToCfg.folderHistory);
+ outCopyToHistory.attribute("LastUsedPath", cfg.gui.mainDlg.copyToCfg.lastUsedPath);
+ outCopyToHistory.attribute("MaxSize", cfg.gui.mainDlg.copyToCfg.historySizeMax);
- outWnd["CaseSensitiveSearch"].attribute("Enabled", config.gui.mainDlg.textSearchRespectCase);
- outWnd["FolderPairsVisible" ].attribute("Max", config.gui.mainDlg.maxFolderPairsVisible);
+ outWnd["Search" ].attribute("CaseSensitive", cfg.gui.mainDlg.textSearchRespectCase);
+ outWnd["FolderPairsVisible"].attribute("Max", cfg.gui.mainDlg.maxFolderPairsVisible);
//###########################################################
XmlOut outConfig = outWnd["ConfigPanel"];
- outConfig.attribute("ScrollPos", config.gui.mainDlg.cfgGridTopRowPos);
- outConfig.attribute("SyncOverdue", config.gui.mainDlg.cfgGridSyncOverdueDays);
- outConfig.attribute("SortByColumn", config.gui.mainDlg.cfgGridLastSortColumn);
- outConfig.attribute("SortAscending", config.gui.mainDlg.cfgGridLastSortAscending);
-
- outConfig["Columns"](config.gui.mainDlg.cfgGridColumnAttribs);
- outConfig["Configurations"].attribute("MaxSize", config.gui.mainDlg.cfgHistItemsMax);
- outConfig["Configurations"](config.gui.mainDlg.cfgFileHistory);
+ outConfig.attribute("ScrollPos", cfg.gui.mainDlg.cfgGridTopRowPos);
+ outConfig.attribute("SyncOverdue", cfg.gui.mainDlg.cfgGridSyncOverdueDays);
+ outConfig.attribute("SortByColumn", cfg.gui.mainDlg.cfgGridLastSortColumn);
+ outConfig.attribute("SortAscending", cfg.gui.mainDlg.cfgGridLastSortAscending);
+
+ outConfig["Columns"](cfg.gui.mainDlg.cfgGridColumnAttribs);
+ outConfig["Configurations"].attribute("MaxSize", cfg.gui.mainDlg.cfgHistItemsMax);
+ outConfig["Configurations"](cfg.gui.mainDlg.cfgFileHistory);
{
- std::vector<Zstring> cfgPaths = config.gui.mainDlg.lastUsedConfigFiles;
+ std::vector<Zstring> cfgPaths = cfg.gui.mainDlg.lastUsedConfigFiles;
for (Zstring& filePath : cfgPaths)
filePath = substituteFreeFileSyncDriveLetter(filePath);
@@ -1730,46 +1824,46 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
//###########################################################
XmlOut outOverview = outWnd["OverviewPanel"];
- outOverview.attribute("ShowPercentage", config.gui.mainDlg.treeGridShowPercentBar);
- outOverview.attribute("SortByColumn", config.gui.mainDlg.treeGridLastSortColumn);
- outOverview.attribute("SortAscending", config.gui.mainDlg.treeGridLastSortAscending);
+ outOverview.attribute("ShowPercentage", cfg.gui.mainDlg.treeGridShowPercentBar);
+ outOverview.attribute("SortByColumn", cfg.gui.mainDlg.treeGridLastSortColumn);
+ outOverview.attribute("SortAscending", cfg.gui.mainDlg.treeGridLastSortAscending);
//write column attributes
XmlOut outColTree = outOverview["Columns"];
- outColTree(config.gui.mainDlg.treeGridColumnAttribs);
+ outColTree(cfg.gui.mainDlg.treeGridColumnAttribs);
XmlOut outFileGrid = outWnd["FilePanel"];
- outFileGrid.attribute("ShowIcons", config.gui.mainDlg.showIcons);
- outFileGrid.attribute("IconSize", config.gui.mainDlg.iconSize);
- outFileGrid.attribute("SashOffset", config.gui.mainDlg.sashOffset);
- outFileGrid.attribute("HistoryMaxSize", config.gui.mainDlg.folderHistItemsMax);
+ 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["ColumnsLeft"].attribute("PathFormat", config.gui.mainDlg.itemPathFormatLeftGrid);
- outFileGrid["ColumnsLeft"](config.gui.mainDlg.columnAttribLeft);
+ outFileGrid["ColumnsLeft"].attribute("PathFormat", cfg.gui.mainDlg.itemPathFormatLeftGrid);
+ outFileGrid["ColumnsLeft"](cfg.gui.mainDlg.columnAttribLeft);
- outFileGrid["FolderHistoryLeft" ](config.gui.mainDlg.folderHistoryLeft);
+ outFileGrid["FolderHistoryLeft" ](cfg.gui.mainDlg.folderHistoryLeft);
- outFileGrid["ColumnsRight"].attribute("PathFormat", config.gui.mainDlg.itemPathFormatRightGrid);
- outFileGrid["ColumnsRight"](config.gui.mainDlg.columnAttribRight);
+ outFileGrid["ColumnsRight"].attribute("PathFormat", cfg.gui.mainDlg.itemPathFormatRightGrid);
+ outFileGrid["ColumnsRight"](cfg.gui.mainDlg.columnAttribRight);
- outFileGrid["FolderHistoryRight"](config.gui.mainDlg.folderHistoryRight);
+ outFileGrid["FolderHistoryRight"](cfg.gui.mainDlg.folderHistoryRight);
//###########################################################
- outWnd["DefaultViewFilter"](config.gui.mainDlg.viewFilterDefault);
- outWnd["Perspective5"](config.gui.mainDlg.guiPerspectiveLast);
+ outWnd["DefaultViewFilter"](cfg.gui.mainDlg.viewFilterDefault);
+ outWnd["Perspective" ](cfg.gui.mainDlg.guiPerspectiveLast);
- outGui["DefaultExclusionFilter"](splitFilterByLines(config.gui.defaultExclusionFilter));
+ outGui["DefaultExclusionFilter"](splitFilterByLines(cfg.gui.defaultExclusionFilter));
- outGui["CommandHistory"](config.gui.commandHistory);
- outGui["CommandHistory"].attribute("MaxSize", config.gui.commandHistItemsMax);
+ outGui["CommandHistory"](cfg.gui.commandHistory);
+ outGui["CommandHistory"].attribute("MaxSize", cfg.gui.commandHistItemsMax);
//external applications
- outGui["ExternalApps"](config.gui.externelApplications);
+ outGui["ExternalApps"](cfg.gui.externalApps);
//last update check
- outGui["LastOnlineCheck" ](config.gui.lastUpdateCheck);
- outGui["LastOnlineVersion"](config.gui.lastOnlineVersion);
+ outGui["LastOnlineCheck" ](cfg.gui.lastUpdateCheck);
+ outGui["LastOnlineVersion"](cfg.gui.lastOnlineVersion);
//batch specific global settings
//XmlOut outBatch = out["Batch"];
@@ -1777,7 +1871,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
template <class ConfigType>
-void writeConfig(const ConfigType& config, XmlType type, int xmlFormatVer, const Zstring& filepath)
+void writeConfig(const ConfigType& cfg, XmlType type, int xmlFormatVer, const Zstring& filePath)
{
XmlDoc doc("FreeFileSync");
setXmlType(doc, type); //throw()
@@ -1785,33 +1879,33 @@ void writeConfig(const ConfigType& config, XmlType type, int xmlFormatVer, const
doc.root().setAttribute("XmlFormat", xmlFormatVer);
XmlOut out(doc);
- writeConfig(config, out);
+ writeConfig(cfg, out);
- saveXmlDocument(doc, filepath); //throw FileError
+ saveXmlDocument(doc, filePath); //throw FileError
}
}
-void xmlAccess::writeConfig(const XmlGuiConfig& cfg, const Zstring& filepath)
+void fff::writeConfig(const XmlGuiConfig& cfg, const Zstring& filePath)
{
- ::writeConfig(cfg, XML_TYPE_GUI, XML_FORMAT_VER_FFS_GUI, filepath); //throw FileError
+ ::writeConfig(cfg, XML_TYPE_GUI, XML_FORMAT_VER_FFS_CFG, filePath); //throw FileError
}
-void xmlAccess::writeConfig(const XmlBatchConfig& cfg, const Zstring& filepath)
+void fff::writeConfig(const XmlBatchConfig& cfg, const Zstring& filePath)
{
- ::writeConfig(cfg, XML_TYPE_BATCH, XML_FORMAT_VER_FFS_BATCH, filepath); //throw FileError
+ ::writeConfig(cfg, XML_TYPE_BATCH, XML_FORMAT_VER_FFS_CFG, filePath); //throw FileError
}
-void xmlAccess::writeConfig(const XmlGlobalSettings& cfg, const Zstring& filepath)
+void fff::writeConfig(const XmlGlobalSettings& cfg, const Zstring& filePath)
{
- ::writeConfig(cfg, XML_TYPE_GLOBAL, XML_FORMAT_VER_GLOBAL, filepath); //throw FileError
+ ::writeConfig(cfg, XML_TYPE_GLOBAL, XML_FORMAT_VER_GLOBAL, filePath); //throw FileError
}
-std::wstring xmlAccess::extractJobName(const Zstring& configFilename)
+std::wstring fff::extractJobName(const Zstring& cfgFilePath)
{
- const Zstring shortName = afterLast(configFilename, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL);
+ const Zstring shortName = afterLast(cfgFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL);
const Zstring jobName = beforeLast(shortName, Zstr('.'), IF_MISSING_RETURN_ALL);
return utfTo<std::wstring>(jobName);
}
diff --git a/FreeFileSync/Source/lib/process_xml.h b/FreeFileSync/Source/lib/process_xml.h
index 1328ceb0..eeaf5c1b 100755
--- a/FreeFileSync/Source/lib/process_xml.h
+++ b/FreeFileSync/Source/lib/process_xml.h
@@ -16,7 +16,7 @@
#include "../ui/cfg_grid.h"
-namespace xmlAccess
+namespace fff
{
enum XmlType
{
@@ -26,7 +26,7 @@ enum XmlType
XML_TYPE_OTHER
};
-XmlType getXmlType(const Zstring& filepath); //throw FileError
+XmlType getXmlType(const Zstring& filePath); //throw FileError
enum class BatchErrorDialog
@@ -38,21 +38,21 @@ enum class BatchErrorDialog
enum class PostSyncAction
{
- SUMMARY,
- EXIT,
+ NONE,
SLEEP,
SHUTDOWN
};
-using Description = std::wstring;
-using Commandline = Zstring;
-using ExternalApps = std::vector<std::pair<Description, Commandline>>;
+struct ExternalApp
+{
+ std::wstring description;
+ Zstring cmdLine;
+};
//---------------------------------------------------------------------
struct XmlGuiConfig
{
- zen::MainConfiguration mainCfg;
-
+ MainConfiguration mainCfg;
bool highlightSyncAction = true;
};
@@ -63,13 +63,15 @@ bool operator==(const XmlGuiConfig& lhs, const XmlGuiConfig& rhs)
return lhs.mainCfg == rhs.mainCfg &&
lhs.highlightSyncAction == rhs.highlightSyncAction;
}
+inline bool operator!=(const XmlGuiConfig& lhs, const XmlGuiConfig& rhs) { return !(lhs == rhs); }
struct BatchExclusiveConfig
{
BatchErrorDialog batchErrorDialog = BatchErrorDialog::SHOW;
bool runMinimized = false;
- PostSyncAction postSyncAction = PostSyncAction::SUMMARY;
+ bool autoCloseSummary = false;
+ PostSyncAction postSyncAction = PostSyncAction::NONE;
Zstring logFolderPathPhrase;
int logfilesCountLimit = -1; //max logfiles; 0 := don't save logfiles; < 0 := no limit
};
@@ -77,27 +79,54 @@ struct BatchExclusiveConfig
struct XmlBatchConfig
{
- zen::MainConfiguration mainCfg;
+ MainConfiguration mainCfg;
BatchExclusiveConfig batchExCfg;
};
-struct OptionalDialogs
+struct ConfirmationDialogs
{
- bool warnDependentFolderPair = true;
- bool warnDependentBaseFolders = true;
- bool warnSignificantDifference = true;
- bool warnNotEnoughDiskSpace = true;
- bool warnUnresolvedConflicts = true;
- bool warnModificationTimeError = true;
- bool warnRecyclerMissing = true;
- bool warnInputFieldEmpty = true;
- bool warnDirectoryLockFailed = true;
- bool warnVersioningFolderPartOfSync = true;
bool popupOnConfigChange = true;
bool confirmSyncStart = true;
bool confirmExternalCommandMassInvoke = true;
};
+inline bool operator==(const ConfirmationDialogs& lhs, const ConfirmationDialogs& rhs)
+{
+ return lhs.popupOnConfigChange == rhs.popupOnConfigChange &&
+ lhs.confirmSyncStart == rhs.confirmSyncStart &&
+ lhs.confirmExternalCommandMassInvoke == rhs.confirmExternalCommandMassInvoke;
+}
+inline bool operator!=(const ConfirmationDialogs& lhs, const ConfirmationDialogs& rhs) { return !(lhs == rhs); }
+
+
+struct WarningDialogs
+{
+ bool warnDependentFolderPair = true;
+ bool warnDependentBaseFolders = true;
+ bool warnSignificantDifference = true;
+ bool warnNotEnoughDiskSpace = true;
+ bool warnUnresolvedConflicts = true;
+ bool warnModificationTimeError = true;
+ bool warnRecyclerMissing = true;
+ bool warnInputFieldEmpty = true;
+ bool warnDirectoryLockFailed = true;
+ bool warnVersioningFolderPartOfSync = true;
+};
+inline bool operator==(const WarningDialogs& lhs, const WarningDialogs& rhs)
+{
+ return lhs.warnDependentFolderPair == rhs.warnDependentFolderPair &&
+ lhs.warnDependentBaseFolders == rhs.warnDependentBaseFolders &&
+ lhs.warnSignificantDifference == rhs.warnSignificantDifference &&
+ lhs.warnNotEnoughDiskSpace == rhs.warnNotEnoughDiskSpace &&
+ lhs.warnUnresolvedConflicts == rhs.warnUnresolvedConflicts &&
+ lhs.warnModificationTimeError == rhs.warnModificationTimeError &&
+ lhs.warnRecyclerMissing == rhs.warnRecyclerMissing &&
+ lhs.warnInputFieldEmpty == rhs.warnInputFieldEmpty &&
+ lhs.warnDirectoryLockFailed == rhs.warnDirectoryLockFailed &&
+ lhs.warnVersioningFolderPartOfSync == rhs.warnVersioningFolderPartOfSync;
+}
+inline bool operator!=(const WarningDialogs& lhs, const WarningDialogs& rhs) { return !(lhs == rhs); }
+
enum FileIconSize
@@ -150,7 +179,7 @@ struct XmlGlobalSettings
//---------------------------------------------------------------------
//Shared (GUI/BATCH) settings
- wxLanguage programLanguage = zen::getSystemLanguage();
+ wxLanguage programLanguage = getSystemLanguage();
bool failSafeFileCopy = true;
bool copyLockedFiles = false; //safer default: avoid copies of partially written files
bool copyFilePermissions = false;
@@ -165,8 +194,10 @@ struct XmlGlobalSettings
size_t lastSyncsLogFileSizeMax = 100000; //maximum size for LastSyncs.log: use a human-readable number
Zstring soundFileCompareFinished;
Zstring soundFileSyncFinished = Zstr("gong.wav");
+ bool autoCloseProgressDialog = false;
- OptionalDialogs optDialogs;
+ ConfirmationDialogs confirmDlgs;
+ WarningDialogs warnDlgs;
//---------------------------------------------------------------------
struct Gui
@@ -192,17 +223,17 @@ struct XmlGlobalSettings
size_t cfgGridTopRowPos = 0;
int cfgGridSyncOverdueDays = 7;
- zen::ColumnTypeCfg cfgGridLastSortColumn = zen::cfgGridLastSortColumnDefault;
- bool cfgGridLastSortAscending = zen::getDefaultSortDirection(zen::cfgGridLastSortColumnDefault);
- std::vector<zen::ColAttributesCfg> cfgGridColumnAttribs = zen::getCfgGridDefaultColAttribs();
+ ColumnTypeCfg cfgGridLastSortColumn = cfgGridLastSortColumnDefault;
+ bool cfgGridLastSortAscending = getDefaultSortDirection(cfgGridLastSortColumnDefault);
+ std::vector<ColAttributesCfg> cfgGridColumnAttribs = getCfgGridDefaultColAttribs();
size_t cfgHistItemsMax = 100;
std::vector<ConfigFileItem> cfgFileHistory;
std::vector<Zstring> lastUsedConfigFiles;
- bool treeGridShowPercentBar = zen::treeGridShowPercentageDefault;
- zen::ColumnTypeTree treeGridLastSortColumn = zen::treeGridLastSortColumnDefault; //remember sort on overview panel
- bool treeGridLastSortAscending = zen::getDefaultSortDirection(zen::treeGridLastSortColumnDefault); //
- std::vector<zen::ColAttributesTree> treeGridColumnAttribs = zen::getTreeGridDefaultColAttribs();
+ bool treeGridShowPercentBar = treeGridShowPercentageDefault;
+ ColumnTypeTree treeGridLastSortColumn = treeGridLastSortColumnDefault; //remember sort on overview panel
+ bool treeGridLastSortAscending = getDefaultSortDirection(treeGridLastSortColumnDefault); //
+ std::vector<ColAttributesTree> treeGridColumnAttribs = getTreeGridDefaultColAttribs();
std::vector<Zstring> folderHistoryLeft;
std::vector<Zstring> folderHistoryRight;
@@ -211,11 +242,11 @@ struct XmlGlobalSettings
FileIconSize iconSize = ICON_SIZE_SMALL;
int sashOffset = 0;
- zen::ItemPathFormat itemPathFormatLeftGrid = zen::defaultItemPathFormatLeftGrid;
- zen::ItemPathFormat itemPathFormatRightGrid = zen::defaultItemPathFormatRightGrid;
+ ItemPathFormat itemPathFormatLeftGrid = defaultItemPathFormatLeftGrid;
+ ItemPathFormat itemPathFormatRightGrid = defaultItemPathFormatRightGrid;
- std::vector<zen::ColAttributesRim> columnAttribLeft = zen::getFileGridDefaultColAttribsLeft();
- std::vector<zen::ColAttributesRim> columnAttribRight = zen::getFileGridDefaultColAttribsRight();
+ std::vector<ColAttributesRim> columnAttribLeft = getFileGridDefaultColAttribsLeft();
+ std::vector<ColAttributesRim> columnAttribRight = getFileGridDefaultColAttribsRight();
ViewFilterDefault viewFilterDefault;
wxString guiPerspectiveLast; //used by wxAuiManager
@@ -227,7 +258,7 @@ struct XmlGlobalSettings
std::vector<Zstring> commandHistory;
size_t commandHistItemsMax = 8;
- ExternalApps externelApplications
+ std::vector<ExternalApp> externalApps
{
//default external app descriptions will be translated "on the fly"!!!
//CONTRACT: first entry will be used for [Enter] or mouse double-click!
@@ -242,22 +273,22 @@ struct XmlGlobalSettings
};
//read/write specific config types
-void readConfig(const Zstring& filepath, XmlGuiConfig& config, std::wstring& warningMsg); //
-void readConfig(const Zstring& filepath, XmlBatchConfig& config, std::wstring& warningMsg); //throw FileError
-void readConfig(const Zstring& filepath, XmlGlobalSettings& config, std::wstring& warningMsg); //
+void readConfig(const Zstring& filePath, XmlGuiConfig& cfg, std::wstring& warningMsg); //
+void readConfig(const Zstring& filePath, XmlBatchConfig& cfg, std::wstring& warningMsg); //throw FileError
+void readConfig(const Zstring& filePath, XmlGlobalSettings& cfg, std::wstring& warningMsg); //
-void writeConfig(const XmlGuiConfig& config, const Zstring& filepath); //
-void writeConfig(const XmlBatchConfig& config, const Zstring& filepath); //throw FileError
-void writeConfig(const XmlGlobalSettings& config, const Zstring& filepath); //
+void writeConfig(const XmlGuiConfig& cfg, const Zstring& filePath); //
+void writeConfig(const XmlBatchConfig& cfg, const Zstring& filePath); //throw FileError
+void writeConfig(const XmlGlobalSettings& cfg, const Zstring& filePath); //
//convert (multiple) *.ffs_gui, *.ffs_batch files or combinations of both into target config structure:
-void readAnyConfig(const std::vector<Zstring>& filepaths, XmlGuiConfig& config, std::wstring& warningMsg); //throw FileError
+void readAnyConfig(const std::vector<Zstring>& filePaths, XmlGuiConfig& cfg, std::wstring& warningMsg); //throw FileError
//config conversion utilities
XmlGuiConfig convertBatchToGui(const XmlBatchConfig& batchCfg); //noexcept
XmlBatchConfig convertGuiToBatch(const XmlGuiConfig& guiCfg, const BatchExclusiveConfig& batchExCfg); //
-std::wstring extractJobName(const Zstring& configFilename);
+std::wstring extractJobName(const Zstring& cfgFilePath);
}
#endif //PROCESS_XML_H_28345825704254262435
diff --git a/FreeFileSync/Source/lib/resolve_path.cpp b/FreeFileSync/Source/lib/resolve_path.cpp
index 62d56577..7a17422b 100755
--- a/FreeFileSync/Source/lib/resolve_path.cpp
+++ b/FreeFileSync/Source/lib/resolve_path.cpp
@@ -32,8 +32,8 @@ Opt<Zstring> getEnvironmentVar(const Zstring& name)
trim(value); //remove leading, trailing blanks
//remove leading, trailing double-quotes
- if (startsWith(value, Zstr("\"")) &&
- endsWith (value, Zstr("\"")) &&
+ if (startsWith(value, Zstr('\"')) &&
+ endsWith (value, Zstr('\"')) &&
value.length() >= 2)
value = Zstring(value.c_str() + 1, value.length() - 2);
@@ -124,7 +124,7 @@ const Zchar MACRO_SEP = Zstr('%');
}
//returns expanded or original string
-Zstring zen::expandMacros(const Zstring& text)
+Zstring fff::expandMacros(const Zstring& text)
{
if (contains(text, MACRO_SEP))
{
@@ -173,7 +173,6 @@ Zstring expandVolumeName(Zstring pathPhrase) // [volname]:\folder [volnam
}
return pathPhrase;
}
-}
void getDirectoryAliasesRecursive(const Zstring& pathPhrase, std::set<Zstring, LessFilePath>& output)
@@ -205,15 +204,16 @@ void getDirectoryAliasesRecursive(const Zstring& pathPhrase, std::set<Zstring, L
//4. replace (all) macros: %UserProfile% -> C:\Users\<user>
{
- const Zstring pathExp = expandMacros(pathPhrase);
+ const Zstring pathExp = fff::expandMacros(pathPhrase);
if (pathExp != pathPhrase)
if (output.insert(pathExp).second)
getDirectoryAliasesRecursive(pathExp, output); //recurse!
}
}
+}
-std::vector<Zstring> zen::getDirectoryAliases(const Zstring& folderPathPhrase)
+std::vector<Zstring> fff::getDirectoryAliases(const Zstring& folderPathPhrase)
{
const Zstring dirPath = trimCpy(folderPathPhrase, true, false);
if (dirPath.empty())
@@ -230,7 +230,7 @@ std::vector<Zstring> zen::getDirectoryAliases(const Zstring& folderPathPhrase)
//coordinate changes with acceptsFolderPathPhraseNative()!
-Zstring zen::getResolvedFilePath(const Zstring& pathPhrase) //noexcept
+Zstring fff::getResolvedFilePath(const Zstring& pathPhrase) //noexcept
{
Zstring path = pathPhrase;
diff --git a/FreeFileSync/Source/lib/resolve_path.h b/FreeFileSync/Source/lib/resolve_path.h
index 8e977c4a..dc23d1de 100755
--- a/FreeFileSync/Source/lib/resolve_path.h
+++ b/FreeFileSync/Source/lib/resolve_path.h
@@ -11,7 +11,7 @@
#include <zen/zstring.h>
-namespace zen
+namespace fff
{
/*
- expand macros
diff --git a/FreeFileSync/Source/lib/return_codes.h b/FreeFileSync/Source/lib/return_codes.h
index 21995ccc..9604142c 100755
--- a/FreeFileSync/Source/lib/return_codes.h
+++ b/FreeFileSync/Source/lib/return_codes.h
@@ -7,7 +7,7 @@
#ifndef RETURN_CODES_H_81307482137054156
#define RETURN_CODES_H_81307482137054156
-namespace zen
+namespace fff
{
enum FfsReturnCode
{
diff --git a/FreeFileSync/Source/lib/soft_filter.h b/FreeFileSync/Source/lib/soft_filter.h
index c6ce8cd0..95ff5a79 100755
--- a/FreeFileSync/Source/lib/soft_filter.h
+++ b/FreeFileSync/Source/lib/soft_filter.h
@@ -12,7 +12,7 @@
#include "../structures.h"
-namespace zen
+namespace fff
{
/*
Semantics of SoftFilter:
@@ -28,7 +28,7 @@ public:
size_t sizeMin, UnitSize unitSizeMin,
size_t sizeMax, UnitSize unitSizeMax);
- bool matchTime(int64_t writeTime) const { return timeFrom_ <= writeTime; }
+ bool matchTime(time_t writeTime) const { return timeFrom_ <= writeTime; }
bool matchSize(uint64_t fileSize) const { return sizeMin_ <= fileSize && fileSize <= sizeMax_; }
bool matchFolder() const { return matchesFolder_; }
bool isNull() const; //filter is equivalent to NullFilter, but may be technically slower
@@ -37,17 +37,17 @@ public:
friend SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second);
private:
- SoftFilter(int64_t timeFrom,
+ SoftFilter(time_t timeFrom,
uint64_t sizeMin,
uint64_t sizeMax,
bool matchesFolder);
- int64_t timeFrom_ = 0; //unit: UTC, seconds
- uint64_t sizeMin_ = 0; //unit: bytes
- uint64_t sizeMax_ = 0; //unit: bytes
+ time_t timeFrom_ = 0; //unit: UTC, seconds
+ uint64_t sizeMin_ = 0; //unit: bytes
+ uint64_t sizeMax_ = 0; //unit: bytes
const bool matchesFolder_;
};
-}
+
@@ -62,8 +62,6 @@ private:
// ----------------------- implementation -----------------------
-namespace zen
-{
inline
SoftFilter::SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
size_t sizeMin, UnitSize unitSizeMin,
@@ -81,7 +79,7 @@ SoftFilter::SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
}
inline
-SoftFilter::SoftFilter(int64_t timeFrom,
+SoftFilter::SoftFilter(time_t timeFrom,
uint64_t sizeMin,
uint64_t sizeMax,
bool matchesFolder) :
@@ -90,6 +88,7 @@ SoftFilter::SoftFilter(int64_t timeFrom,
sizeMax_ (sizeMax),
matchesFolder_(matchesFolder) {}
+
inline
SoftFilter combineFilters(const SoftFilter& lhs, const SoftFilter& rhs)
{
@@ -99,10 +98,11 @@ SoftFilter combineFilters(const SoftFilter& lhs, const SoftFilter& rhs)
lhs.matchesFolder_ && rhs.matchesFolder_);
}
+
inline
bool SoftFilter::isNull() const //filter is equivalent to NullFilter, but may be technically slower
{
- return timeFrom_ == std::numeric_limits<int64_t>::min() &&
+ return timeFrom_ == std::numeric_limits<time_t>::min() &&
sizeMin_ == 0U &&
sizeMax_ == std::numeric_limits<uint64_t>::max() &&
matchesFolder_ == true;
diff --git a/FreeFileSync/Source/lib/status_handler.cpp b/FreeFileSync/Source/lib/status_handler.cpp
index 11d04f48..9e2f78db 100755
--- a/FreeFileSync/Source/lib/status_handler.cpp
+++ b/FreeFileSync/Source/lib/status_handler.cpp
@@ -8,19 +8,18 @@
#include <chrono>
#include <zen/basic_math.h>
-using namespace zen;
-
namespace
{
std::chrono::steady_clock::time_point lastExec;
};
-bool zen::updateUiIsAllowed()
+
+bool fff::updateUiIsAllowed()
{
const auto now = std::chrono::steady_clock::now();
- if (numeric::dist(now, lastExec) > std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS)) //handle potential chrono wrap-around!
+ if (numeric::dist(now, lastExec) > UI_UPDATE_INTERVAL) //handle potential chrono wrap-around!
{
lastExec = now;
return true;
diff --git a/FreeFileSync/Source/lib/status_handler.h b/FreeFileSync/Source/lib/status_handler.h
index 6e8b5f96..779c2c60 100755
--- a/FreeFileSync/Source/lib/status_handler.h
+++ b/FreeFileSync/Source/lib/status_handler.h
@@ -9,11 +9,14 @@
#include "../process_callback.h"
#include <vector>
+#include <chrono>
+#include <thread>
#include <string>
#include <zen/i18n.h>
+#include <zen/basic_math.h>
-namespace zen
+namespace fff
{
bool updateUiIsAllowed(); //test if a specific amount of time is over
@@ -55,6 +58,7 @@ struct Statistics
virtual int64_t getBytesCurrent(ProcessCallback::Phase phaseId) const = 0;
virtual int64_t getBytesTotal (ProcessCallback::Phase phaseId) const = 0;
+ virtual zen::Opt<AbortTrigger> getAbortStatus() const = 0;
virtual const std::wstring& currentStatusText() const = 0;
};
@@ -63,8 +67,7 @@ struct Statistics
class StatusHandler : public ProcessCallback, public AbortCallback, public Statistics
{
public:
- StatusHandler() :
- numbersCurrent_(4), //init with phase count
+ StatusHandler() : numbersCurrent_(4), //init with phase count
numbersTotal_ (4) {} //
//implement parts of ProcessCallback
@@ -75,29 +78,45 @@ public:
}
void updateProcessedData(int itemsDelta, int64_t bytesDelta) override { updateData(numbersCurrent_, itemsDelta, bytesDelta); } //note: these methods MUST NOT throw in order
- void updateTotalData (int itemsDelta, int64_t bytesDelta) override { updateData(numbersTotal_, itemsDelta, bytesDelta); } //to properly allow undoing setting of statistics!
+ void updateTotalData (int itemsDelta, int64_t bytesDelta) override { updateData(numbersTotal_, itemsDelta, bytesDelta); } //to allow usage within destructors!
- void requestUiRefresh() override //throw X
+ void requestUiRefresh() override final //throw X
{
- if (abortRequested_) //triggered by requestAbortion()
+ if (updateUiIsAllowed())
+ forceUiRefresh(); //throw X
+ }
+
+ void forceUiRefresh() override final //throw X
+ {
+ const bool abortRequestedBefore = static_cast<bool>(abortRequested_);
+
+ forceUiRefreshNoThrow();
+
+ //triggered by userRequestAbort()
+ // => sufficient to evaluate occasionally when updateUiIsAllowed()!
+ // => refresh *before* throwing: support requestUiRefresh() during destruction
+ if (abortRequested_)
{
- forceUiRefresh();
+ if (!abortRequestedBefore)
+ forceUiRefreshNoThrow(); //just once to immediately show the "Stop requested..." status after user clicks cancel
throw AbortProcess();
}
- if (updateUiIsAllowed())
- forceUiRefresh();
}
- void reportStatus(const std::wstring& text) override //throw X
+ virtual void forceUiRefreshNoThrow() = 0; //noexcept
+
+ void reportStatus(const std::wstring& text) override final //throw X
{
//assert(!text.empty()); -> possible: start of parallel scan
- if (!abortRequested_) statusText_ = text;
+
+ statusText_ = text; //update text *before* running operations that can throw
requestUiRefresh(); //throw X
}
+
void reportInfo(const std::wstring& text) override //throw X
{
assert(!text.empty());
- if (!abortRequested_) statusText_ = text;
+ statusText_ = text;
requestUiRefresh(); //throw X
//log text in derived class
}
@@ -105,24 +124,25 @@ public:
void abortProcessNow() override
{
if (!abortRequested_) abortRequested_ = AbortTrigger::PROGRAM;
+ forceUiRefreshNoThrow();
throw AbortProcess();
}
void userAbortProcessNow()
{
- if (!abortRequested_) abortRequested_ = AbortTrigger::USER;
+ abortRequested_ = AbortTrigger::USER; //may overwrite AbortTrigger::PROGRAM
+ forceUiRefreshNoThrow();
throw AbortProcess();
}
//implement AbortCallback
- void userRequestAbort() override
+ void userRequestAbort() override final
{
- if (!abortRequested_) abortRequested_ = AbortTrigger::USER;
- statusText_ = _("Stop requested: Waiting for current operation to finish...");
+ abortRequested_ = AbortTrigger::USER; //may overwrite AbortTrigger::PROGRAM
} //called from GUI code: this does NOT call abortProcessNow() immediately, but later when we're out of the C GUI call stack
//implement Statistics
- Phase currentPhase() const override { return currentPhase_; }
+ Phase currentPhase() const override final { return currentPhase_; }
int getItemsCurrent(Phase phaseId) const override { return refNumbers(numbersCurrent_, phaseId).items; }
int getItemsTotal (Phase phaseId) const override { assert(phaseId != PHASE_SCANNING); return refNumbers(numbersTotal_, phaseId).items; }
@@ -132,8 +152,7 @@ public:
const std::wstring& currentStatusText() const override { return statusText_; }
-protected:
- Opt<AbortTrigger> getAbortStatus() const { return abortRequested_; }
+ zen::Opt<AbortTrigger> getAbortStatus() const override { return abortRequested_; }
private:
struct StatNumber
@@ -174,8 +193,26 @@ private:
StatNumbers numbersTotal_;
std::wstring statusText_;
- Opt<AbortTrigger> abortRequested_;
+ zen::Opt<AbortTrigger> abortRequested_;
};
+
+//------------------------------------------------------------------------------------------
+
+inline
+void delayAndCountDown(const std::wstring& operationName, size_t delayInSec, 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);
+ 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();
+ if (notifyStatus)
+ notifyStatus(operationName + L"... " + _P("1 sec", "%x sec", numeric::integerDivideRoundUp(timeMs, 1000)));
+
+ std::this_thread::sleep_for(UI_UPDATE_INTERVAL / 2);
+ }
+}
}
#endif //STATUS_HANDLER_H_81704805908341534
diff --git a/FreeFileSync/Source/lib/status_handler_impl.h b/FreeFileSync/Source/lib/status_handler_impl.h
index cffee505..eab46960 100755
--- a/FreeFileSync/Source/lib/status_handler_impl.h
+++ b/FreeFileSync/Source/lib/status_handler_impl.h
@@ -12,7 +12,7 @@
#include "../process_callback.h"
-namespace zen
+namespace fff
{
template <typename Function> inline
zen::Opt<std::wstring> tryReportingError(Function cmd, ProcessCallback& handler /*throw X*/) //return ignored error message if available
@@ -21,9 +21,9 @@ zen::Opt<std::wstring> tryReportingError(Function cmd, ProcessCallback& handler
try
{
cmd(); //throw FileError
- return NoValue();
+ return zen::NoValue();
}
- catch (FileError& error)
+ catch (zen::FileError& error)
{
switch (handler.reportError(error.toString(), retryNumber)) //throw X
{
@@ -60,7 +60,7 @@ public:
{
cb_.updateProcessedData(itemsDelta, bytesDelta); //nothrow! -> ensure client and service provider are in sync!
itemsReported_ += itemsDelta;
- bytesReported_ += bytesDelta; //
+ bytesReported_ += bytesDelta; //
//special rule: avoid temporary statistics mess up, even though they are corrected anyway below:
if (itemsReported_ > itemsExpected_)
diff --git a/FreeFileSync/Source/lib/versioning.cpp b/FreeFileSync/Source/lib/versioning.cpp
index 591b3117..6d8ea721 100755
--- a/FreeFileSync/Source/lib/versioning.cpp
+++ b/FreeFileSync/Source/lib/versioning.cpp
@@ -2,6 +2,7 @@
#include <cstddef> //required by GCC 4.8.1 to find ptrdiff_t
using namespace zen;
+using namespace fff;
namespace
@@ -14,7 +15,7 @@ Zstring getDotExtension(const Zstring& relativePath) //including "." if extensio
};
}
-bool impl::isMatchingVersion(const Zstring& shortname, const Zstring& shortnameVersioned) //e.g. ("Sample.txt", "Sample.txt 2012-05-15 131513.txt")
+bool fff::impl::isMatchingVersion(const Zstring& shortname, const Zstring& shortnameVersioned) //e.g. ("Sample.txt", "Sample.txt 2012-05-15 131513.txt")
{
auto it = shortnameVersioned.begin();
auto itLast = shortnameVersioned.end();
@@ -110,13 +111,10 @@ void moveExistingItemToVersioning(const AbstractPath& sourcePath, const Abstract
try { pd = AFS::getPathStatus(targetPath); /*throw FileError*/ }
catch (FileError&)
{
-
- warn_static("remove after test: https://www.freefilesync.org/forum/viewtopic.php?f=8&t=4765&p=15981#p15981")
- warn_static("really? is previous exception is more relevant?")
- throw;
-
-
- } //previous exception is more relevant
+ //previous exception is more relevant in general
+ //BUT, we might be hiding a second unrelated issue: https://www.freefilesync.org/forum/viewtopic.php?t=4765#p16016
+ //=> FFS considers session faulty and tries to create a new one, which might fail with: LIBSSH2_ERROR_AUTHENTICATION_FAILED
+ }
if (pd)
{
diff --git a/FreeFileSync/Source/lib/versioning.h b/FreeFileSync/Source/lib/versioning.h
index a0a437f3..4236aff2 100755
--- a/FreeFileSync/Source/lib/versioning.h
+++ b/FreeFileSync/Source/lib/versioning.h
@@ -15,7 +15,7 @@
#include "../algorithm.h"
-namespace zen
+namespace fff
{
//e.g. move C:\Source\subdir\Sample.txt -> D:\Revisions\subdir\Sample.txt 2012-05-15 131513.txt
//scheme: <revisions directory>\<relpath>\<filename>.<ext> YYYY-MM-DD HHMMSS.<ext>
@@ -34,11 +34,13 @@ class FileVersioner
public:
FileVersioner(const AbstractPath& versioningFolderPath, //throw FileError
VersioningStyle versioningStyle,
- const TimeComp& timeStamp) :
+ const zen::TimeComp& timeStamp) :
versioningFolderPath_(versioningFolderPath),
versioningStyle_(versioningStyle),
- timeStamp_(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)) //e.g. "2012-05-15 131513"
+ timeStamp_(zen::formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)) //e.g. "2012-05-15 131513"
{
+ using namespace zen;
+
if (AbstractFileSystem::isNullPath(versioningFolderPath_))
throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
@@ -49,7 +51,7 @@ public:
bool revisionFile(const FileDescriptor& fileDescr, //throw FileError; return "false" if file is not existing
const Zstring& relativePath,
//called frequently if move has to revert to copy + delete => see zen::copyFile for limitations when throwing exceptions!
- const IOCallback& notifyUnbufferedIO); //may be nullptr
+ const zen::IOCallback& notifyUnbufferedIO); //may be nullptr
bool revisionSymlink(const AbstractPath& linkPath, const Zstring& relativePath); //throw FileError; return "false" if file is not existing
@@ -59,7 +61,7 @@ public:
const std::function<void(const std::wstring& displayPathFrom, const std::wstring& displayPathTo)>& onBeforeFileMove, //one call for each *existing* object!
const std::function<void(const std::wstring& displayPathFrom, const std::wstring& displayPathTo)>& onBeforeFolderMove, //
//called frequently if move has to revert to copy + delete => see zen::copyFile for limitations when throwing exceptions!
- const IOCallback& notifyUnbufferedIO);
+ const zen::IOCallback& notifyUnbufferedIO);
//void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
@@ -67,7 +69,7 @@ private:
void revisionFolderImpl(const AbstractPath& folderPath, const Zstring& relativePath,
const std::function<void(const std::wstring& displayPathFrom, const std::wstring& displayPathTo)>& onBeforeFileMove,
const std::function<void(const std::wstring& displayPathFrom, const std::wstring& displayPathTo)>& onBeforeFolderMove,
- const IOCallback& notifyUnbufferedIO); //throw FileError
+ const zen::IOCallback& notifyUnbufferedIO); //throw FileError
AbstractPath generateVersionedPath(const Zstring& relativePath) const;
diff --git a/FreeFileSync/Source/process_callback.h b/FreeFileSync/Source/process_callback.h
index 523c888b..7a792917 100755
--- a/FreeFileSync/Source/process_callback.h
+++ b/FreeFileSync/Source/process_callback.h
@@ -9,11 +9,14 @@
#include <string>
#include <cstdint>
+#include <chrono>
+namespace fff
+{
//interface for comparison and synchronization process status updates (used by GUI or Batch mode)
-const int UI_UPDATE_INTERVAL_MS = 100; //unit: [ms]; perform ui updates not more often than necessary,
-//100 seems to be a good value with only a minimal performance loss; also used by Win 7 copy progress bar
+const std::chrono::milliseconds UI_UPDATE_INTERVAL(100); //perform ui updates not more often than necessary,
+//100 ms seems to be a good value with only a minimal performance loss; also used by Win 7 copy progress bar
//this one is required by async directory existence check!
//report status during comparison and synchronization
@@ -37,7 +40,7 @@ struct ProcessCallback
//it is in general paired with a call to requestUiRefresh() to compensate!
virtual void updateProcessedData(int itemsDelta, int64_t bytesDelta) = 0; //noexcept!!
virtual void updateTotalData (int itemsDelta, int64_t bytesDelta) = 0; //
- /*the estimated and actual total workload may change *during* sync:
+ /* the estimated and actual total workload may change *during* sync:
1. file cannot be moved -> fallback to copy + delete
2. file copy, actual size changed after comparison
3. file contains significant ADS data, is sparse or compressed
@@ -73,5 +76,6 @@ struct ProcessCallback
virtual void abortProcessNow() = 0; //will throw an exception => don't call while in a C GUI callstack
};
+}
#endif //PROCESS_CALLBACK_H_48257827842345454545
diff --git a/FreeFileSync/Source/structures.cpp b/FreeFileSync/Source/structures.cpp
index 9e9d3cf8..47552362 100755
--- a/FreeFileSync/Source/structures.cpp
+++ b/FreeFileSync/Source/structures.cpp
@@ -13,9 +13,10 @@
#include "lib/hard_filter.h"
using namespace zen;
+using namespace fff;
-std::vector<unsigned int> zen::fromTimeShiftPhrase(const std::wstring& timeShiftPhrase)
+std::vector<unsigned int> fff::fromTimeShiftPhrase(const std::wstring& timeShiftPhrase)
{
std::wstring tmp = replaceCpy(timeShiftPhrase, L';', L','); //harmonize , and ;
replace(tmp, L'-', L""); //there is no negative shift => treat as positive!
@@ -35,7 +36,7 @@ std::vector<unsigned int> zen::fromTimeShiftPhrase(const std::wstring& timeShift
}
-std::wstring zen::toTimeShiftPhrase(const std::vector<unsigned int>& ignoreTimeShiftMinutes)
+std::wstring fff::toTimeShiftPhrase(const std::vector<unsigned int>& ignoreTimeShiftMinutes)
{
std::wstring phrase;
for (auto it = ignoreTimeShiftMinutes.begin(); it != ignoreTimeShiftMinutes.end(); ++it)
@@ -51,7 +52,7 @@ std::wstring zen::toTimeShiftPhrase(const std::vector<unsigned int>& ignoreTimeS
}
-std::wstring zen::getVariantName(CompareVariant var)
+std::wstring fff::getVariantName(CompareVariant var)
{
switch (var)
{
@@ -67,40 +68,56 @@ std::wstring zen::getVariantName(CompareVariant var)
}
-std::wstring zen::getVariantName(DirectionConfig::Variant var)
+namespace
{
- const wchar_t arrowLeft [] = L"<-";
- const wchar_t arrowRight[] = L"->";
- const wchar_t angleRight[] = L">";
-#if 0
- //const wchar_t arrowLeft [] = L"\u2190"; unicode arrows -> too small
- //const wchar_t arrowRight[] = L"\u2192";
- const wchar_t arrowLeft [] = L"\uFF1C\u2013"; //fullwidth less-than + en dash
- const wchar_t arrowRight[] = L"\u2013\uFF1E"; //en dash + fullwidth greater-than
- const wchar_t angleRight[] = L"\uFF1E";
- => drawbacks:
- - not drawn correctly before Vista
- - used in sync log files where users expect ANSI: https://www.freefilesync.org/forum/viewtopic.php?t=4647
- - RTL: the full width less-than does not swap automatically
-#endif
-
- switch (var)
+std::wstring getVariantNameImpl(DirectionConfig::Variant var, const wchar_t* arrowLeft, const wchar_t* arrowRight, const wchar_t* angleRight)
+{
+ switch (var)
{
case DirectionConfig::TWO_WAY:
- return std::wstring(arrowLeft) + L" " + _("Two way") + L" " + arrowRight;
+ return arrowLeft + _("Two way") + arrowRight;
case DirectionConfig::MIRROR:
- return _("Mirror") + L" " + arrowRight;
+ return _("Mirror") + arrowRight;
case DirectionConfig::UPDATE:
- return _("Update") + L" " + angleRight;
+ return _("Update") + angleRight;
case DirectionConfig::CUSTOM:
return _("Custom");
}
assert(false);
return _("Error");
}
+}
-DirectionSet zen::extractDirections(const DirectionConfig& cfg)
+std::wstring fff::getVariantName(DirectionConfig::Variant var)
+{
+#if 1
+ const wchar_t arrowLeft [] = L"<\u2013 ";
+ const wchar_t arrowRight[] = L" \u2013>";
+ const wchar_t angleRight[] = L" >";
+#else
+ //const wchar_t arrowLeft [] = L"\u2190 "; //unicode arrows -> too small
+ //const wchar_t arrowRight[] = L" \u2192"; //
+ //const wchar_t arrowLeft [] = L"\u25C4\u2013 "; //black triangle pointer
+ //const wchar_t arrowRight[] = L" \u2013\u25BA"; //
+ const wchar_t arrowLeft [] = L"\uFF1C\u2013 "; //fullwidth less-than + en dash
+ const wchar_t arrowRight[] = L" \u2013\uFF1E"; //en dash + fullwidth greater-than
+ const wchar_t angleRight[] = L" \uFF1E";
+ //=> drawback: - not drawn correctly before Vista
+ // - RTL: the full width less-than is not mirrored automatically (=> Windows Unicode bug!?)
+#endif
+ return getVariantNameImpl(var, arrowLeft, arrowRight, angleRight);
+}
+
+
+//use in sync log files where users expect ANSI: https://www.freefilesync.org/forum/viewtopic.php?t=4647
+std::wstring fff::getVariantNameForLog(DirectionConfig::Variant var)
+{
+ return getVariantNameImpl(var, L"<-", L"->", L">");
+}
+
+
+DirectionSet fff::extractDirections(const DirectionConfig& cfg)
{
DirectionSet output;
switch (cfg.var)
@@ -134,12 +151,12 @@ DirectionSet zen::extractDirections(const DirectionConfig& cfg)
}
-bool zen::detectMovedFilesSelectable(const DirectionConfig& cfg)
+bool fff::detectMovedFilesSelectable(const DirectionConfig& cfg)
{
if (cfg.var == DirectionConfig::TWO_WAY)
return false; //moved files are always detected since we have the database file anyway
- const DirectionSet tmp = zen::extractDirections(cfg);
+ const DirectionSet tmp = fff::extractDirections(cfg);
return (tmp.exLeftSideOnly == SyncDirection::RIGHT &&
tmp.exRightSideOnly == SyncDirection::RIGHT) ||
(tmp.exLeftSideOnly == SyncDirection::LEFT &&
@@ -147,13 +164,13 @@ bool zen::detectMovedFilesSelectable(const DirectionConfig& cfg)
}
-bool zen::detectMovedFilesEnabled(const DirectionConfig& cfg)
+bool fff::detectMovedFilesEnabled(const DirectionConfig& cfg)
{
return detectMovedFilesSelectable(cfg) ? cfg.detectMovedFiles : cfg.var == DirectionConfig::TWO_WAY;
}
-DirectionSet zen::getTwoWayUpdateSet()
+DirectionSet fff::getTwoWayUpdateSet()
{
DirectionSet output;
output.exLeftSideOnly = SyncDirection::RIGHT;
@@ -208,7 +225,7 @@ std::wstring MainConfiguration::getSyncVariantName() const
}
-std::wstring zen::getSymbol(CompareFilesResult cmpRes)
+std::wstring fff::getSymbol(CompareFilesResult cmpRes)
{
switch (cmpRes)
{
@@ -233,7 +250,7 @@ std::wstring zen::getSymbol(CompareFilesResult cmpRes)
}
-std::wstring zen::getSymbol(SyncOperation op)
+std::wstring fff::getSymbol(SyncOperation op)
{
switch (op)
{
@@ -295,9 +312,14 @@ int daysSinceBeginOfWeek(int dayOfWeek) //0-6, 0=Monday, 6=Sunday
*/
-int64_t resolve(size_t value, UnitTime unit, int64_t defaultVal)
+time_t resolve(size_t value, UnitTime unit, time_t defaultVal)
{
- TimeComp locTimeStruc = zen::getLocalTime();
+ TimeComp tcLocal = getLocalTime();
+ if (tcLocal == TimeComp())
+ {
+ assert(false);
+ return defaultVal;
+ }
switch (unit)
{
@@ -305,10 +327,10 @@ int64_t resolve(size_t value, UnitTime unit, int64_t defaultVal)
return defaultVal;
case UnitTime::TODAY:
- locTimeStruc.second = 0; //0-61
- locTimeStruc.minute = 0; //0-59
- locTimeStruc.hour = 0; //0-23
- return localToTimeT(locTimeStruc); //convert local time back to UTC
+ tcLocal.second = 0; //0-61
+ tcLocal.minute = 0; //0-59
+ tcLocal.hour = 0; //0-23
+ return localToTimeT(tcLocal); //convert local time back to UTC
//case UnitTime::THIS_WEEK:
//{
@@ -324,29 +346,29 @@ int64_t resolve(size_t value, UnitTime unit, int64_t defaultVal)
//}
case UnitTime::THIS_MONTH:
- locTimeStruc.second = 0; //0-61
- locTimeStruc.minute = 0; //0-59
- locTimeStruc.hour = 0; //0-23
- locTimeStruc.day = 1; //1-31
- return localToTimeT(locTimeStruc);
+ tcLocal.second = 0; //0-61
+ tcLocal.minute = 0; //0-59
+ tcLocal.hour = 0; //0-23
+ tcLocal.day = 1; //1-31
+ return localToTimeT(tcLocal);
case UnitTime::THIS_YEAR:
- locTimeStruc.second = 0; //0-61
- locTimeStruc.minute = 0; //0-59
- locTimeStruc.hour = 0; //0-23
- locTimeStruc.day = 1; //1-31
- locTimeStruc.month = 1; //1-12
- return localToTimeT(locTimeStruc);
+ tcLocal.second = 0; //0-61
+ tcLocal.minute = 0; //0-59
+ tcLocal.hour = 0; //0-23
+ tcLocal.day = 1; //1-31
+ tcLocal.month = 1; //1-12
+ return localToTimeT(tcLocal);
case UnitTime::LAST_X_DAYS:
- locTimeStruc.second = 0; //0-61
- locTimeStruc.minute = 0; //0-59
- locTimeStruc.hour = 0; //0-23
- return localToTimeT(locTimeStruc) - static_cast<int64_t>(value) * 24 * 3600;
+ tcLocal.second = 0; //0-61
+ tcLocal.minute = 0; //0-59
+ tcLocal.hour = 0; //0-23
+ return localToTimeT(tcLocal) - value * 24 * 3600;
}
assert(false);
- return localToTimeT(locTimeStruc);
+ return localToTimeT(tcLocal);
}
@@ -372,14 +394,14 @@ uint64_t resolve(size_t value, UnitSize unit, uint64_t defaultVal)
}
}
-void zen::resolveUnits(size_t timeSpan, UnitTime unitTimeSpan,
+void fff::resolveUnits(size_t timeSpan, UnitTime unitTimeSpan,
size_t sizeMin, UnitSize unitSizeMin,
size_t sizeMax, UnitSize unitSizeMax,
- int64_t& timeFrom, //unit: UTC time, seconds
+ time_t& timeFrom, //unit: UTC time, seconds
uint64_t& sizeMinBy, //unit: bytes
uint64_t& sizeMaxBy) //unit: bytes
{
- timeFrom = resolve(timeSpan, unitTimeSpan, std::numeric_limits<int64_t>::min());
+ timeFrom = resolve(timeSpan, unitTimeSpan, std::numeric_limits<time_t>::min());
sizeMinBy = resolve(sizeMin, unitSizeMin, 0U);
sizeMaxBy = resolve(sizeMax, unitSizeMax, std::numeric_limits<uint64_t>::max());
}
@@ -401,7 +423,7 @@ FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& l
trim(out.excludeFilter, true, false);
//soft filter
- int64_t loctimeFrom = 0;
+ time_t loctimeFrom = 0;
uint64_t locSizeMinBy = 0;
uint64_t locSizeMaxBy = 0;
resolveUnits(out.timeSpan, out.unitTimeSpan,
@@ -412,7 +434,7 @@ FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& l
locSizeMaxBy); //unit: bytes
//soft filter
- int64_t glotimeFrom = 0;
+ time_t glotimeFrom = 0;
uint64_t gloSizeMinBy = 0;
uint64_t gloSizeMaxBy = 0;
resolveUnits(global.timeSpan, global.unitTimeSpan,
@@ -450,7 +472,7 @@ bool effectivelyEmpty(const FolderPairEnh& fp)
}
-MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs)
+MainConfiguration fff::merge(const std::vector<MainConfiguration>& mainCfgs)
{
assert(!mainCfgs.empty());
if (mainCfgs.empty())
diff --git a/FreeFileSync/Source/structures.h b/FreeFileSync/Source/structures.h
index 1395ca6e..4f9b6a65 100755
--- a/FreeFileSync/Source/structures.h
+++ b/FreeFileSync/Source/structures.h
@@ -11,7 +11,8 @@
#include <memory>
#include <zen/zstring.h>
-namespace zen
+
+namespace fff
{
enum class CompareVariant
{
@@ -145,7 +146,8 @@ bool detectMovedFilesEnabled (const DirectionConfig& cfg);
DirectionSet extractDirections(const DirectionConfig& cfg); //get sync directions: DON'T call for DirectionConfig::TWO_WAY!
-std::wstring getVariantName(DirectionConfig::Variant var);
+std::wstring getVariantName (DirectionConfig::Variant var);
+std::wstring getVariantNameForLog(DirectionConfig::Variant var);
inline
bool operator==(const DirectionConfig& lhs, const DirectionConfig& rhs)
@@ -179,6 +181,7 @@ bool operator==(const CompConfig& lhs, const CompConfig& rhs)
lhs.handleSymlinks == rhs.handleSymlinks &&
lhs.ignoreTimeShiftMinutes == rhs.ignoreTimeShiftMinutes;
}
+inline bool operator!=(const CompConfig& lhs, const CompConfig& rhs) { return !(lhs == rhs); }
inline
bool effectivelyEqual(const CompConfig& lhs, const CompConfig& rhs) { return lhs == rhs; } //no change in behavior
@@ -223,6 +226,7 @@ bool operator==(const SyncConfig& lhs, const SyncConfig& rhs)
lhs.versioningFolderPhrase == rhs.versioningFolderPhrase;
//adapt effectivelyEqual() on changes, too!
}
+inline bool operator!=(const SyncConfig& lhs, const SyncConfig& rhs) { return !(lhs == rhs); }
inline
@@ -310,11 +314,12 @@ bool operator==(const FilterConfig& lhs, const FilterConfig& rhs)
lhs.sizeMax == rhs.sizeMax &&
lhs.unitSizeMax == rhs.unitSizeMax;
}
+inline bool operator!=(const FilterConfig& lhs, const FilterConfig& rhs) { return !(lhs == rhs); }
void resolveUnits(size_t timeSpan, UnitTime unitTimeSpan,
size_t sizeMin, UnitSize unitSizeMin,
size_t sizeMax, UnitSize unitSizeMax,
- int64_t& timeFrom, //unit: UTC time, seconds
+ time_t& timeFrom, //unit: UTC time, seconds
uint64_t& sizeMinBy, //unit: bytes
uint64_t& sizeMaxBy); //unit: bytes
diff --git a/FreeFileSync/Source/synchronization.cpp b/FreeFileSync/Source/synchronization.cpp
index 5dae742e..b7a51fe5 100755
--- a/FreeFileSync/Source/synchronization.cpp
+++ b/FreeFileSync/Source/synchronization.cpp
@@ -23,6 +23,7 @@
#include <fcntl.h> //open
using namespace zen;
+using namespace fff;
namespace
@@ -244,7 +245,7 @@ void SyncStatistics::processFolder(const FolderPair& folder)
//-----------------------------------------------------------------------------------------------------------
-std::vector<zen::FolderPairSyncCfg> zen::extractSyncCfg(const MainConfiguration& mainCfg)
+std::vector<FolderPairSyncCfg> fff::extractSyncCfg(const MainConfiguration& mainCfg)
{
//merge first and additional pairs
std::vector<FolderPairEnh> allPairs = { mainCfg.firstPair };
@@ -336,10 +337,10 @@ public:
//always (try to) clean up, even if synchronization is aborted!
try
{
- tryCleanup(false); //throw FileError, (throw X)
+ tryCleanup(false /*allowCallbackException*/); //throw FileError, (throw X)
}
catch (FileError&) {}
- catch (...) { assert(false); } //what is this?
+ catch (...) { assert(false); } //what is this?
/*
may block heavily, but still do not allow user callback:
-> avoid throwing user cancel exception again, leading to incomplete clean-up!
@@ -347,7 +348,7 @@ public:
}
//clean-up temporary directory (recycle bin optimization)
- void tryCleanup(bool allowUserCallback); //throw FileError; throw X -> call this in non-exceptional coding, i.e. somewhere after sync!
+ void tryCleanup(bool allowCallbackException); //throw FileError; throw X -> call this in non-exceptional coding, i.e. somewhere after sync!
template <class Function> void removeFileWithCallback (const FileDescriptor& fileDescr, const Zstring& relativePath, Function onNotifyItemDeletion, const IOCallback& notifyUnbufferedIO); //
template <class Function> void removeDirWithCallback (const AbstractPath& dirPath, const Zstring& relativePath, Function onNotifyItemDeletion, const IOCallback& notifyUnbufferedIO); //throw FileError
@@ -438,7 +439,7 @@ DeletionHandling::DeletionHandling(const AbstractPath& baseFolderPath,
}
-void DeletionHandling::tryCleanup(bool allowUserCallback) //throw FileError; throw X
+void DeletionHandling::tryCleanup(bool allowCallbackException) //throw FileError; throw X
{
switch (deletionPolicy_)
{
@@ -450,17 +451,22 @@ void DeletionHandling::tryCleanup(bool allowUserCallback) //throw FileError; thr
{
auto notifyDeletionStatus = [&](const std::wstring& displayPath)
{
- if (!displayPath.empty())
- procCallback_.reportStatus(replaceCpy(txtRemovingFile_, L"%x", fmtPath(displayPath))); //throw ?
- else
- procCallback_.requestUiRefresh(); //throw ?
+ try
+ {
+ if (!displayPath.empty())
+ procCallback_.reportStatus(replaceCpy(txtRemovingFile_, L"%x", fmtPath(displayPath))); //throw X
+ else
+ procCallback_.requestUiRefresh(); //throw X
+ }
+ catch (...)
+ {
+ if (allowCallbackException)
+ throw;
+ }
};
//move content of temporary directory to recycle bin in a single call
- if (allowUserCallback)
- getOrCreateRecyclerSession().tryCleanup(notifyDeletionStatus); //throw FileError
- else
- getOrCreateRecyclerSession().tryCleanup(nullptr); //throw FileError
+ getOrCreateRecyclerSession().tryCleanup(notifyDeletionStatus); //throw FileError
}
break;
@@ -591,7 +597,7 @@ public:
{
MinimumDiskSpaceNeeded inst;
inst.recurse(baseFolder);
- return std::make_pair(inst.spaceNeededLeft_, inst.spaceNeededRight_);
+ return { inst.spaceNeededLeft_, inst.spaceNeededRight_ };
}
private:
@@ -838,7 +844,7 @@ void SynchronizeFolderPair::prepare2StepMove(FilePair& sourceObj,
tempFile .setMoveRef(targetObj.getId());
//NO statistics update!
- procCallback_.requestUiRefresh(); //may throw
+ procCallback_.requestUiRefresh(); //throw ?
}
@@ -955,8 +961,7 @@ void SynchronizeFolderPair::runZeroPass(ContainerObject& hierObj)
{
SyncStatistics statSrc(*sourceObj);
SyncStatistics statTrg(*targetObj);
- return std::make_pair(getCUD(statSrc) + getCUD(statTrg),
- statSrc.getBytesToProcess() + statTrg.getBytesToProcess());
+ return { getCUD(statSrc) + getCUD(statTrg), statSrc.getBytesToProcess() + statTrg.getBytesToProcess() };
};
const auto statBefore = getStats();
@@ -1346,7 +1351,7 @@ void SynchronizeFolderPair::synchronizeFileInt(FilePair& file, SyncOperation syn
return; //no update on processed data!
}
- procCallback_.requestUiRefresh(); //may throw
+ procCallback_.requestUiRefresh(); //throw ?
}
@@ -1485,7 +1490,7 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymlinkPair& symlink, SyncOperati
return; //no update on processed data!
}
- procCallback_.requestUiRefresh(); //may throw
+ procCallback_.requestUiRefresh(); //throw ?
}
@@ -1613,7 +1618,7 @@ void SynchronizeFolderPair::synchronizeFolderInt(FolderPair& folder, SyncOperati
return; //no update on processed data!
}
- procCallback_.requestUiRefresh(); //may throw
+ procCallback_.requestUiRefresh(); //throw ?
}
//###########################################################################################
@@ -1760,7 +1765,7 @@ enum class FolderPairJobType
}
-void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime,
+void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime,
bool verifyCopiedFiles,
bool copyLockedFiles,
bool copyFilePermissions,
@@ -1769,7 +1774,7 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
int folderAccessTimeout,
const std::vector<FolderPairSyncCfg>& syncConfig,
FolderComparison& folderCmp,
- xmlAccess::OptionalDialogs& warnings,
+ WarningDialogs& warnings,
ProcessCallback& callback)
{
//PERF_START;
@@ -1960,7 +1965,7 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
if (0 < freeSpace && //zero means "request not supported" (e.g. see WebDav)
freeSpace < minSpaceNeeded)
- diskSpaceMissing.emplace_back(baseFolderPath, std::make_pair(minSpaceNeeded, freeSpace));
+ diskSpaceMissing.push_back({ baseFolderPath, { minSpaceNeeded, freeSpace } });
}
catch (FileError&) {} //for warning only => no need for tryReportingError()
};
@@ -2104,6 +2109,10 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
try
{
+ const TimeComp timeStamp = getLocalTime(std::chrono::system_clock::to_time_t(syncStartTime));
+ if (timeStamp == TimeComp())
+ throw std::runtime_error("Failed to determine current time: " + numberTo<std::string>(syncStartTime.time_since_epoch().count()));
+
//loop through all directory pairs
for (auto itBase = begin(folderCmp); itBase != end(folderCmp); ++itBase)
{
@@ -2116,7 +2125,7 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
continue;
//------------------------------------------------------------------------------------------
- callback.reportInfo(_("Synchronizing folder pair:") + L" [" + getVariantName(folderPairCfg.syncVariant_) + L"]\n" +
+ callback.reportInfo(_("Synchronizing folder pair:") + L" " + getVariantNameForLog(folderPairCfg.syncVariant_) + L"\n" +
L" " + AFS::getDisplayPath(baseFolder.getAbstractPath< LEFT_SIDE>()) + L"\n" +
L" " + AFS::getDisplayPath(baseFolder.getAbstractPath<RIGHT_SIDE>()));
//------------------------------------------------------------------------------------------
@@ -2136,15 +2145,16 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
//execute synchronization recursively
//update synchronization database in case of errors:
- ZEN_ON_SCOPE_FAIL
- (
- try
+ auto guardDbSave = makeGuard<ScopeGuardRunMode::ON_FAIL>([&]
{
- if (folderPairCfg.saveSyncDB_)
- zen::saveLastSynchronousState(baseFolder, nullptr);
- } //throw FileError
- catch (FileError&) {}
- );
+ try
+ {
+ if (folderPairCfg.saveSyncDB_)
+ saveLastSynchronousState(baseFolder, //throw FileError
+ [&](const std::wstring& statusMsg) { try { callback.reportStatus(statusMsg); /*throw X*/} catch (...) {}});
+ }
+ catch (FileError&) {}
+ });
if (jobType[folderIndex] == FolderPairJobType::PROCESS)
{
@@ -2174,8 +2184,6 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
return folderPairCfg.handleDeletion;
};
- const TimeComp timeStamp = getLocalTime(std::chrono::system_clock::to_time_t(syncStartTime));
-
DeletionHandling delHandlerL(baseFolder.getAbstractPath<LEFT_SIDE>(),
getEffectiveDeletionPolicy(baseFolder.getAbstractPath<LEFT_SIDE>()),
folderPairCfg.versioningFolderPhrase,
@@ -2197,21 +2205,23 @@ void zen::synchronize(const std::chrono::system_clock::time_point& syncStartTime
syncFP.startSync(baseFolder);
//(try to gracefully) cleanup temporary Recycle bin folders and versioning -> will be done in ~DeletionHandling anyway...
- tryReportingError([&] { delHandlerL.tryCleanup(true /*allowUserCallback*/); /*throw FileError*/}, callback); //throw X?
- tryReportingError([&] { delHandlerR.tryCleanup(true ); /*throw FileError*/}, callback); //throw X?
+ tryReportingError([&] { delHandlerL.tryCleanup(true /*allowCallbackException*/); /*throw FileError*/}, callback); //throw X?
+ tryReportingError([&] { delHandlerR.tryCleanup(true ); /*throw FileError*/}, callback); //throw X?
}
//(try to gracefully) write database file
if (folderPairCfg.saveSyncDB_)
{
callback.reportStatus(_("Generating database..."));
- callback.forceUiRefresh();
+ callback.forceUiRefresh(); //throw X
tryReportingError([&]
{
- zen::saveLastSynchronousState(baseFolder, //throw FileError
+ saveLastSynchronousState(baseFolder, //throw FileError
[&](const std::wstring& statusMsg) { callback.reportStatus(statusMsg); /*throw X*/});
}, callback); //throw X
+
+ guardDbSave.dismiss(); //[!] after "graceful" try: user might have cancelled during DB write: ensure DB is still written
}
}
diff --git a/FreeFileSync/Source/synchronization.h b/FreeFileSync/Source/synchronization.h
index 44a58114..076f0350 100755
--- a/FreeFileSync/Source/synchronization.h
+++ b/FreeFileSync/Source/synchronization.h
@@ -7,14 +7,13 @@
#ifndef SYNCHRONIZATION_H_8913470815943295
#define SYNCHRONIZATION_H_8913470815943295
-//#include <zen/time.h>
#include <chrono>
#include "file_hierarchy.h"
#include "lib/process_xml.h"
#include "process_callback.h"
-namespace zen
+namespace fff
{
class SyncStatistics //this class counts *logical* operations, (create, update, delete + bytes), *not* disk accesses!
{
@@ -104,7 +103,7 @@ void synchronize(const std::chrono::system_clock::time_point& syncStartTime,
int folderAccessTimeout,
const std::vector<FolderPairSyncCfg>& syncConfig, //CONTRACT: syncConfig and folderCmp correspond row-wise!
FolderComparison& folderCmp, //
- xmlAccess::OptionalDialogs& warnings,
+ WarningDialogs& warnings,
ProcessCallback& callback);
}
diff --git a/FreeFileSync/Source/ui/app_icon.h b/FreeFileSync/Source/ui/app_icon.h
index 265fdf38..68fa910b 100755
--- a/FreeFileSync/Source/ui/app_icon.h
+++ b/FreeFileSync/Source/ui/app_icon.h
@@ -11,11 +11,12 @@
#include <wx+/image_resources.h>
-namespace zen
+namespace fff
{
inline
wxIcon getFfsIcon()
{
+ using namespace zen;
//wxWidgets' bitmap to icon conversion on OS X can only deal with very specific sizes => check on all platforms!
assert(getResourceImage(L"FreeFileSync").GetWidth () == getResourceImage(L"FreeFileSync").GetHeight() &&
getResourceImage(L"FreeFileSync").GetWidth() % 128 == 0);
diff --git a/FreeFileSync/Source/ui/batch_config.cpp b/FreeFileSync/Source/ui/batch_config.cpp
index 814d23c8..0e4ff689 100755
--- a/FreeFileSync/Source/ui/batch_config.cpp
+++ b/FreeFileSync/Source/ui/batch_config.cpp
@@ -14,10 +14,11 @@
#include "gui_generated.h"
#include "folder_selector.h"
#include "../lib/help_provider.h"
+#include "../lib/generate_logfile.h"
using namespace zen;
-using namespace xmlAccess;
+using namespace fff;
namespace
@@ -40,7 +41,11 @@ private:
void OnSaveBatchJob(wxCommandEvent& event) override;
void OnToggleIgnoreErrors(wxCommandEvent& event) override { updateGui(); }
- void OnToggleRunMinimized(wxCommandEvent& event) override { updateGui(); }
+ void OnToggleRunMinimized(wxCommandEvent& event) override
+ {
+ m_checkBoxAutoClose->SetValue(m_checkBoxRunMinimized->GetValue()); //usually user wants to change both
+ updateGui();
+ }
void OnHelpScheduleBatch(wxHyperlinkEvent& event) override { displayHelpEntry(L"schedule-a-batch-job", this); }
@@ -76,11 +81,12 @@ BatchDialog::BatchDialog(wxWindow* parent, BatchDialogConfig& dlgCfg) :
logfileDir_ = std::make_unique<FolderSelector>(*m_panelLogfile, *m_buttonSelectLogFolder, *m_bpButtonSelectAltLogFolder, *m_logFolderPath, nullptr /*staticText*/, nullptr /*wxWindow*/);
+ logfileDir_->setBackgroundText(utfTo<std::wstring>(getDefaultLogFolderPath()));
+
enumPostSyncAction_.
- add(PostSyncAction::SUMMARY, _("Show summary")).
- add(PostSyncAction::EXIT, replaceCpy(_("E&xit"), L"&", L"")). //reuse translation
- add(PostSyncAction::SLEEP, _("Sleep")).
- add(PostSyncAction::SHUTDOWN, _("Shut down"));
+ add(PostSyncAction::NONE, L"").
+ add(PostSyncAction::SLEEP, _("System: Sleep")).
+ add(PostSyncAction::SHUTDOWN, _("System: Shut down"));
setConfig(dlgCfg);
@@ -135,6 +141,7 @@ void BatchDialog::setConfig(const BatchDialogConfig& dlgCfg)
}
m_checkBoxRunMinimized->SetValue(dlgCfg.batchExCfg.runMinimized);
+ m_checkBoxAutoClose ->SetValue(dlgCfg.batchExCfg.autoCloseSummary);
setEnumVal(enumPostSyncAction_, *m_choicePostSyncAction, dlgCfg.batchExCfg.postSyncAction);
logfileDir_->setPath(dlgCfg.batchExCfg.logFolderPathPhrase);
@@ -156,6 +163,7 @@ BatchDialogConfig BatchDialog::getConfig() const
dlgCfg.batchExCfg.batchErrorDialog = m_radioBtnErrorDialogCancel->GetValue() ? BatchErrorDialog::CANCEL : BatchErrorDialog::SHOW;
dlgCfg.batchExCfg.runMinimized = m_checkBoxRunMinimized->GetValue();
+ dlgCfg.batchExCfg.autoCloseSummary = m_checkBoxAutoClose ->GetValue();
dlgCfg.batchExCfg.postSyncAction = getEnumVal(enumPostSyncAction_, *m_choicePostSyncAction);
dlgCfg.batchExCfg.logFolderPathPhrase = utfTo<Zstring>(logfileDir_->getPath());
@@ -180,7 +188,7 @@ void BatchDialog::OnSaveBatchJob(wxCommandEvent& event)
}
-ReturnBatchConfig::ButtonPressed zen::showBatchConfigDialog(wxWindow* parent,
+ReturnBatchConfig::ButtonPressed fff::showBatchConfigDialog(wxWindow* parent,
BatchExclusiveConfig& batchExCfg,
bool& ignoreErrors)
{
diff --git a/FreeFileSync/Source/ui/batch_config.h b/FreeFileSync/Source/ui/batch_config.h
index e79d2f25..7dc68db5 100755
--- a/FreeFileSync/Source/ui/batch_config.h
+++ b/FreeFileSync/Source/ui/batch_config.h
@@ -11,7 +11,7 @@
#include "../lib/process_xml.h"
-namespace zen
+namespace fff
{
struct ReturnBatchConfig
{
@@ -25,8 +25,7 @@ struct ReturnBatchConfig
//show and let user customize batch settings (without saving)
ReturnBatchConfig::ButtonPressed showBatchConfigDialog(wxWindow* parent,
-
- xmlAccess::BatchExclusiveConfig& batchExCfg,
+ BatchExclusiveConfig& batchExCfg,
bool& ignoreErrors);
}
diff --git a/FreeFileSync/Source/ui/batch_status_handler.cpp b/FreeFileSync/Source/ui/batch_status_handler.cpp
index e3e59690..be007e09 100755
--- a/FreeFileSync/Source/ui/batch_status_handler.cpp
+++ b/FreeFileSync/Source/ui/batch_status_handler.cpp
@@ -17,7 +17,7 @@
#include "../fs/concrete.h"
using namespace zen;
-using namespace xmlAccess;
+using namespace fff;
namespace
@@ -25,12 +25,13 @@ namespace
//"Backup FreeFileSync 2013-09-15 015052.123.log" ->
//"Backup FreeFileSync 2013-09-15 015052.123 [Error].log"
+
//return value always bound!
std::unique_ptr<AFS::OutputStream> prepareNewLogfile(const AbstractPath& logFolderPath, //throw FileError
const std::wstring& jobName,
- const std::chrono::system_clock::time_point& batchStartTime,
+ const std::chrono::system_clock::time_point& syncStartTime,
const std::wstring& failStatus,
- ProcessCallback& pc)
+ const std::function<void(const std::wstring& msg)>& notifyStatus)
{
assert(!jobName.empty());
@@ -41,11 +42,14 @@ std::unique_ptr<AFS::OutputStream> prepareNewLogfile(const AbstractPath& logFold
//=> too many issues, most notably cmd.exe is not Unicode-aware: https://www.freefilesync.org/forum/viewtopic.php?t=1679
//assemble logfile name
- const TimeComp timeStamp = getLocalTime(std::chrono::system_clock::to_time_t(batchStartTime));
- const auto timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(batchStartTime.time_since_epoch()).count() % 1000;
+ const TimeComp tc = getLocalTime(std::chrono::system_clock::to_time_t(syncStartTime));
+ if (tc == TimeComp())
+ throw FileError(L"Failed to determine current time: " + numberTo<std::wstring>(syncStartTime.time_since_epoch().count()));
+
+ const auto timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(syncStartTime.time_since_epoch()).count() % 1000;
Zstring logFileName = utfTo<Zstring>(jobName) +
- Zstr(" ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp) +
+ Zstr(" ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), tc) +
Zstr(".") + printNumber<Zstring>(Zstr("%03d"), static_cast<int>(timeMs)); //[ms] should yield a fairly unique name
if (!failStatus.empty())
logFileName += utfTo<Zstring>(L" [" + failStatus + L"]");
@@ -53,9 +57,16 @@ std::unique_ptr<AFS::OutputStream> prepareNewLogfile(const AbstractPath& logFold
const AbstractPath logFilePath = AFS::appendRelPath(logFolderPath, logFileName);
- return AFS::getOutputStream(logFilePath, //throw FileError
- nullptr, /*streamSize*/
- OnUpdateLogfileStatusNoThrow(pc, AFS::getDisplayPath(logFilePath)));
+ auto notifyUnbufferedIO = [notifyStatus,
+ bytesWritten_ = int64_t(0),
+ msg_ = replaceCpy(_("Saving file %x..."), L"%x", fmtPath(AFS::getDisplayPath(logFilePath)))]
+ (int64_t bytesDelta) mutable
+ {
+ if (notifyStatus)
+ notifyStatus(msg_ + L" (" + formatFilesizeShort(bytesWritten_ += bytesDelta) + L")"); /*throw X*/
+ };
+
+ return AFS::getOutputStream(logFilePath, nullptr, /*streamSize*/ notifyUnbufferedIO); //throw FileError
}
@@ -95,11 +106,13 @@ private:
};
-void limitLogfileCount(const AbstractPath& logFolderPath, const std::wstring& jobname, size_t maxCount, const std::function<void()>& onUpdateStatus) //throw FileError
+void limitLogfileCount(const AbstractPath& logFolderPath, const std::wstring& jobname, size_t maxCount, //throw FileError
+ const std::function<void(const std::wstring& msg)>& notifyStatus)
{
const Zstring prefix = utfTo<Zstring>(jobname);
+ const std::wstring cleaningMsg = _("Cleaning up old log files...");;
- LogTraverserCallback lt(prefix, onUpdateStatus); //traverse source directory one level deep
+ LogTraverserCallback lt(prefix, [&] { if (notifyStatus) notifyStatus(cleaningMsg); }); //traverse source directory one level deep
AFS::traverseFolder(logFolderPath, lt);
std::vector<Zstring> logFileNames = lt.refFileNames();
@@ -112,13 +125,14 @@ void limitLogfileCount(const AbstractPath& logFolderPath, const std::wstring& jo
std::for_each(logFileNames.begin(), logFileNames.end() - maxCount, [&](const Zstring& logFileName)
{
+ const AbstractPath filePath = AFS::appendRelPath(logFolderPath, logFileName);
+ if (notifyStatus) notifyStatus(cleaningMsg + L" " + fmtPath(AFS::getDisplayPath(filePath)));
+
try
{
- AFS::removeFilePlain(AFS::appendRelPath(logFolderPath, logFileName)); //throw FileError
+ AFS::removeFilePlain(filePath); //throw FileError
}
catch (const FileError& e) { if (!lastError) lastError = e; };
-
- if (onUpdateStatus) onUpdateStatus();
});
}
@@ -130,9 +144,10 @@ void limitLogfileCount(const AbstractPath& logFolderPath, const std::wstring& jo
//##############################################################################################################################
BatchStatusHandler::BatchStatusHandler(bool showProgress,
+ bool autoCloseDialog,
const std::wstring& jobName,
const Zstring& soundFileSyncComplete,
- const std::chrono::system_clock::time_point& batchStartTime,
+ const std::chrono::system_clock::time_point& startTime,
const Zstring& logFolderPathPhrase, //may be empty
int logfilesCountLimit,
size_t lastSyncsLogFileSizeMax,
@@ -150,19 +165,26 @@ BatchStatusHandler::BatchStatusHandler(bool showProgress,
returnCode_(returnCode),
automaticRetryCount_(automaticRetryCount),
automaticRetryDelay_(automaticRetryDelay),
- progressDlg_(createProgressDialog(*this, [this] { this->onProgressDialogTerminate(); },
-*this,
-nullptr, //parentWindow
-showProgress,
-jobName,
-soundFileSyncComplete,
-ignoreErrors,
-postSyncAction)),
- jobName_(jobName),
- batchStartTime_(batchStartTime),
- logFolderPathPhrase_(logFolderPathPhrase),
- postSyncCommand_(postSyncCommand),
- postSyncCondition_(postSyncCondition)
+ progressDlg_(createProgressDialog(*this, [this] { this->onProgressDialogTerminate(); }, *this, nullptr /*parentWindow*/, showProgress, autoCloseDialog,
+jobName, soundFileSyncComplete, ignoreErrors, [&]
+{
+ switch (postSyncAction)
+ {
+ case PostSyncAction::NONE:
+ return PostSyncAction2::NONE;
+ case PostSyncAction::SLEEP:
+ return PostSyncAction2::SLEEP;
+ case PostSyncAction::SHUTDOWN:
+ return PostSyncAction2::SHUTDOWN;
+ }
+ assert(false);
+ return PostSyncAction2::NONE;
+}())),
+jobName_(jobName),
+ startTime_(startTime),
+ logFolderPathPhrase_(logFolderPathPhrase),
+ postSyncCommand_(postSyncCommand),
+ 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!!!
@@ -176,8 +198,8 @@ postSyncAction)),
BatchStatusHandler::~BatchStatusHandler()
{
- const int totalErrors = errorLog_.getItemCount(TYPE_ERROR | TYPE_FATAL_ERROR); //evaluate before finalizing log
- const int totalWarnings = errorLog_.getItemCount(TYPE_WARNING);
+ const int totalErrors = errorLog_.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR); //evaluate before finalizing log
+ const int totalWarnings = errorLog_.getItemCount(MSG_TYPE_WARNING);
//finalize error log
SyncProgressDialog::SyncResult finalStatus = SyncProgressDialog::RESULT_FINISHED_WITH_SUCCESS;
@@ -187,24 +209,24 @@ BatchStatusHandler::~BatchStatusHandler()
{
finalStatus = SyncProgressDialog::RESULT_ABORTED;
raiseReturnCode(returnCode_, FFS_RC_ABORTED);
- finalStatusMsg = _("Synchronization stopped");
- errorLog_.logMsg(finalStatusMsg, TYPE_ERROR);
+ finalStatusMsg = _("Stopped");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_ERROR);
failStatus = _("Stopped");
}
else if (totalErrors > 0)
{
finalStatus = SyncProgressDialog::RESULT_FINISHED_WITH_ERROR;
raiseReturnCode(returnCode_, FFS_RC_FINISHED_WITH_ERRORS);
- finalStatusMsg = _("Synchronization completed with errors");
- errorLog_.logMsg(finalStatusMsg, TYPE_ERROR);
+ finalStatusMsg = _("Completed with errors");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_ERROR);
failStatus = _("Error");
}
else if (totalWarnings > 0)
{
finalStatus = SyncProgressDialog::RESULT_FINISHED_WITH_WARNINGS;
raiseReturnCode(returnCode_, FFS_RC_FINISHED_WITH_WARNINGS);
- finalStatusMsg = _("Synchronization completed with warnings");
- errorLog_.logMsg(finalStatusMsg, TYPE_WARNING);
+ finalStatusMsg = _("Completed with warnings");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_WARNING);
failStatus = _("Warning");
}
else
@@ -213,14 +235,16 @@ BatchStatusHandler::~BatchStatusHandler()
getBytesTotal(PHASE_SYNCHRONIZING) == 0)
finalStatusMsg = _("Nothing to synchronize"); //even if "ignored conflicts" occurred!
else
- finalStatusMsg = _("Synchronization completed successfully");
- errorLog_.logMsg(finalStatusMsg, TYPE_INFO);
+ finalStatusMsg = _("Completed");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_INFO);
}
//post sync command
Zstring commandLine = [&]
{
- if (!getAbortStatus() || *getAbortStatus() != AbortTrigger::USER) //user cancelled => don't run post sync command!
+ if (getAbortStatus() && *getAbortStatus() == AbortTrigger::USER)
+ ; //user cancelled => don't run post sync command!
+ else
switch (postSyncCondition_)
{
case PostSyncCondition::COMPLETION:
@@ -241,7 +265,7 @@ BatchStatusHandler::~BatchStatusHandler()
trim(commandLine);
if (!commandLine.empty())
- errorLog_.logMsg(replaceCpy(_("Executing command %x"), L"%x", fmtPath(commandLine)), TYPE_INFO);
+ errorLog_.logMsg(replaceCpy(_("Executing command %x"), L"%x", fmtPath(commandLine)), MSG_TYPE_INFO);
//----------------- write results into user-specified logfile ------------------------
const SummaryInfo summary =
@@ -250,110 +274,130 @@ BatchStatusHandler::~BatchStatusHandler()
finalStatusMsg,
getItemsCurrent(PHASE_SYNCHRONIZING), getBytesCurrent(PHASE_SYNCHRONIZING),
getItemsTotal (PHASE_SYNCHRONIZING), getBytesTotal (PHASE_SYNCHRONIZING),
- std::time(nullptr) - startTime_
+ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - startTime_).count()
+ };
+ if (progressDlg_) progressDlg_->timerSetStatus(false /*active*/); //keep correct summary window stats considering count down timer, system sleep
+
+ //do NOT use tryReportingError()! saving log files should not be cancellable!
+ auto notifyStatusNoThrow = [&](const std::wstring& msg)
+ {
+ try { reportStatus(msg); /*throw X*/ }
+ catch (...) {}
};
//create not before destruction: 1. avoid issues with FFS trying to sync open log file 2. simplify transactional retry on failure 3. no need to rename log file to include status
// 4. failure to write to particular stream must not be retried!
if (logfilesCountLimit_ != 0)
{
- auto requestUiRefreshNoThrow = [&] { try { requestUiRefresh(); /*throw X*/ } catch (...) {} };
-
- const AbstractPath logFolderPath = createAbstractPath(trimCpy(logFolderPathPhrase_).empty() ? getConfigDirPathPf() + Zstr("Logs") : logFolderPathPhrase_); //noexcept
+ const AbstractPath logFolderPath = createAbstractPath(trimCpy(logFolderPathPhrase_).empty() ? getDefaultLogFolderPath() : logFolderPathPhrase_); //noexcept
try
{
- tryReportingError([&] //errors logged here do not impact final status calculation above! => not a problem!
- {
- std::unique_ptr<AFS::OutputStream> logFileStream = prepareNewLogfile(logFolderPath, jobName_, batchStartTime_, failStatus, *this); //throw FileError; return value always bound!
+ std::unique_ptr<AFS::OutputStream> logFileStream = prepareNewLogfile(logFolderPath, jobName_, startTime_, failStatus, notifyStatusNoThrow); //throw FileError; return value always bound!
- streamToLogFile(summary, errorLog_, *logFileStream); //throw FileError, (X)
- logFileStream->finalize(); //throw FileError, (X)
- }, *this); //throw X! by ProcessCallback!
+ streamToLogFile(summary, errorLog_, *logFileStream); //throw FileError, (X)
+ logFileStream->finalize(); //throw FileError, (X)
}
- catch (...) {}
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
if (logfilesCountLimit_ > 0)
- {
- try { reportStatus(_("Cleaning up old log files...")); }
- catch (...) {}
-
try
{
- tryReportingError([&]
- {
- limitLogfileCount(logFolderPath, jobName_, logfilesCountLimit_, requestUiRefreshNoThrow); //throw FileError
- }, *this); //throw X
+ limitLogfileCount(logFolderPath, jobName_, logfilesCountLimit_, notifyStatusNoThrow); //throw FileError, (X)
}
- catch (...) {}
- }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
}
- //write results into LastSyncs.log
+
try
{
- saveToLastSyncsLog(summary, errorLog_, lastSyncsLogFileSizeMax_, OnUpdateLogfileStatusNoThrow(*this, utfTo<std::wstring>(getLastSyncsLogfilePath()))); //throw FileError
+ saveToLastSyncsLog(summary, errorLog_, lastSyncsLogFileSizeMax_, notifyStatusNoThrow); //throw FileError, (X)
}
- catch (FileError&) { assert(false); }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
//execute post sync command *after* writing log files, so that user can refer to the log via the command!
if (!commandLine.empty())
try
{
- //use EXEC_TYPE_ASYNC until there is reason not to: https://www.freefilesync.org/forum/viewtopic.php?t=31
- tryReportingError([&] { shellExecute(expandMacros(commandLine), EXEC_TYPE_ASYNC); /*throw FileError*/ }, *this); //throw X
+ //use ExecutionType::ASYNC until there is reason not to: https://www.freefilesync.org/forum/viewtopic.php?t=31
+ shellExecute(expandMacros(commandLine), ExecutionType::ASYNC); //throw FileError
}
- catch (...) {}
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
if (progressDlg_)
{
+ auto mayRunAfterCountDown = [&](const std::wstring& operationName)
+ {
+ auto notifyStatusThrowOnCancel = [&](const std::wstring& msg)
+ {
+ try { reportStatus(msg); /*throw X*/ }
+ catch (...)
+ {
+ if (getAbortStatus() && *getAbortStatus() == AbortTrigger::USER)
+ throw;
+ }
+ };
+
+ if (progressDlg_->getWindowIfVisible())
+ try
+ {
+ delayAndCountDown(operationName, 5 /*delayInSec*/, notifyStatusThrowOnCancel); //throw X
+ }
+ catch (...) { return false; }
+
+ return true;
+ };
+
//post sync action
- bool showSummary = true;
- bool triggerSleep = false;
- if (!getAbortStatus() || *getAbortStatus() != AbortTrigger::USER) //user cancelled => don't run post sync action!
+ bool autoClose = false;
+ if (getAbortStatus() && *getAbortStatus() == AbortTrigger::USER)
+ ; //user cancelled => don't run post sync command!
+ else
switch (progressDlg_->getOptionPostSyncAction())
{
- case PostSyncAction::SUMMARY:
+ case PostSyncAction2::NONE:
+ autoClose = progressDlg_->getOptionAutoCloseDialog();
break;
- case PostSyncAction::EXIT:
- showSummary = false;
+ case PostSyncAction2::EXIT:
+ assert(false);
break;
- case PostSyncAction::SLEEP:
- triggerSleep = true;
+ case PostSyncAction2::SLEEP:
+ if (mayRunAfterCountDown(_("System: Sleep")))
+ try
+ {
+ suspendSystem(); //throw FileError
+ autoClose = progressDlg_->getOptionAutoCloseDialog();
+ }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
break;
- case PostSyncAction::SHUTDOWN:
- showSummary = false;
- try
- {
- tryReportingError([&] { shutdownSystem(); /*throw FileError*/ }, *this); //throw X
- }
- catch (...) {}
+ case PostSyncAction2::SHUTDOWN:
+ if (mayRunAfterCountDown(_("System: Shut down")))
+ try
+ {
+ shutdownSystem(); //throw FileError
+ autoClose = true;
+ }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
break;
}
if (switchToGuiRequested_) //-> avoid recursive yield() calls, thous switch not before ending batch mode
- showSummary = false;
+ autoClose = true;
//close progress dialog
- if (showSummary) //warning: wxWindow::Show() is called within showSummary()!
+ if (autoClose) //warning: wxWindow::Show() is called within showSummary()!
+ progressDlg_->closeDirectly(true /*restoreParentFrame: n/a here*/); //progressDlg_ is main window => program will quit shortly after
+ else
//notify about (logical) application main window => program won't quit, but stay on this dialog
//setMainWindow(progressDlg_->getAsWindow()); -> not required anymore since we block waiting until dialog is closed below
progressDlg_->showSummary(finalStatus, errorLog_);
- else
- progressDlg_->closeDirectly(true /*restoreParentFrame: n/a here*/); //progressDlg_ is main window => program will quit shortly after
-
- if (triggerSleep) //sleep *after* showing results dialog (consider total time!)
- try
- {
- tryReportingError([&] { suspendSystem(); /*throw FileError*/ }, *this); //throw X
- }
- catch (...) {}
//wait until progress dialog notified shutdown via onProgressDialogTerminate()
//-> required since it has our "this" pointer captured in lambda "notifyWindowTerminate"!
//-> nicely manages dialog lifetime
- while (progressDlg_)
+ for (;;)
{
wxTheApp->Yield(); //*first* refresh GUI (removing flicker) before sleeping!
- std::this_thread::sleep_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS));
+ if (!progressDlg_) break;
+ std::this_thread::sleep_for(UI_UPDATE_INTERVAL);
}
}
}
@@ -365,7 +409,7 @@ void BatchStatusHandler::initNewPhase(int itemsTotal, int64_t bytesTotal, Proces
if (progressDlg_)
progressDlg_->initNewPhase(); //call after "StatusHandler::initNewPhase"
- forceUiRefresh(); //throw ?; OS X needs a full yield to update GUI and get rid of "dummy" texts
+ forceUiRefresh(); //throw X; OS X needs a full yield to update GUI and get rid of "dummy" texts
}
@@ -381,7 +425,7 @@ void BatchStatusHandler::updateProcessedData(int itemsDelta, int64_t bytesDelta)
void BatchStatusHandler::reportInfo(const std::wstring& text)
{
- errorLog_.logMsg(text, TYPE_INFO); //log first!
+ errorLog_.logMsg(text, MSG_TYPE_INFO); //log first!
StatusHandler::reportInfo(text); //throw X
}
@@ -390,7 +434,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
{
if (!progressDlg_) abortProcessNow();
- errorLog_.logMsg(warningMessage, TYPE_WARNING);
+ errorLog_.logMsg(warningMessage, MSG_TYPE_WARNING);
if (!warningActive)
return;
@@ -401,7 +445,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
case BatchErrorDialog::SHOW:
{
PauseTimers dummy(*progressDlg_);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
bool dontWarnAgain = false;
switch (showQuestionDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::WARNING, PopupDialogCfg().
@@ -414,7 +458,7 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
break;
case QuestionButton2::NO: //switch
- errorLog_.logMsg(_("Switching to FreeFileSync's main window"), TYPE_INFO);
+ errorLog_.logMsg(_("Switching to FreeFileSync's main window"), MSG_TYPE_INFO);
switchToGuiRequested_ = true; //treat as a special kind of cancel
userRequestAbort(); //
throw BatchRequestSwitchToMainDialog();
@@ -440,23 +484,13 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er
//auto-retry
if (retryNumber < automaticRetryCount_)
{
- errorLog_.logMsg(errorMessage + L"\n-> " +
- _P("Automatic retry in 1 second...", "Automatic retry in %x seconds...", automaticRetryDelay_), TYPE_INFO);
- //delay
- const int iterations = static_cast<int>(1000 * automaticRetryDelay_ / UI_UPDATE_INTERVAL_MS); //always round down: don't allow for negative remaining time below
- for (int i = 0; i < iterations; ++i)
- {
- reportStatus(_("Error") + L": " + _P("Automatic retry in 1 second...", "Automatic retry in %x seconds...",
- (1000 * automaticRetryDelay_ - i * UI_UPDATE_INTERVAL_MS + 999) / 1000)); //integer round up
- std::this_thread::sleep_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS));
- }
+ errorLog_.logMsg(errorMessage + L"\n-> " + _("Automatic retry"), MSG_TYPE_INFO);
+ delayAndCountDown(_("Automatic retry"), automaticRetryDelay_, [&](const std::wstring& msg) { this->reportStatus(_("Error") + L": " + msg); });
return ProcessCallback::RETRY;
}
-
//always, except for "retry":
- auto guardWriteLog = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { errorLog_.logMsg(errorMessage, TYPE_ERROR); });
-
+ auto guardWriteLog = makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { errorLog_.logMsg(errorMessage, MSG_TYPE_ERROR); });
if (!progressDlg_->getOptionIgnoreErrors())
{
@@ -465,7 +499,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er
case BatchErrorDialog::SHOW:
{
PauseTimers dummy(*progressDlg_);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::ERROR2, PopupDialogCfg().
setDetailInstructions(errorMessage),
@@ -480,7 +514,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er
case ConfirmationButton3::DECLINE: //retry
guardWriteLog.dismiss();
- errorLog_.logMsg(errorMessage + L"\n-> " + _("Retrying operation..."), TYPE_INFO);
+ errorLog_.logMsg(errorMessage + L"\n-> " + _("Retrying operation..."), MSG_TYPE_INFO);
return ProcessCallback::RETRY;
case ConfirmationButton3::CANCEL:
@@ -507,7 +541,7 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
{
if (!progressDlg_) abortProcessNow();
- errorLog_.logMsg(errorMessage, TYPE_FATAL_ERROR);
+ errorLog_.logMsg(errorMessage, MSG_TYPE_FATAL_ERROR);
if (!progressDlg_->getOptionIgnoreErrors())
switch (batchErrorDialog_)
@@ -515,7 +549,7 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
case BatchErrorDialog::SHOW:
{
PauseTimers dummy(*progressDlg_);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::ERROR2,
PopupDialogCfg().setTitle(_("Serious Error")).
@@ -543,7 +577,7 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
}
-void BatchStatusHandler::forceUiRefresh()
+void BatchStatusHandler::forceUiRefreshNoThrow()
{
if (progressDlg_)
progressDlg_->updateGui();
diff --git a/FreeFileSync/Source/ui/batch_status_handler.h b/FreeFileSync/Source/ui/batch_status_handler.h
index 072d0f80..55ceccb6 100755
--- a/FreeFileSync/Source/ui/batch_status_handler.h
+++ b/FreeFileSync/Source/ui/batch_status_handler.h
@@ -9,41 +9,43 @@
#include <chrono>
#include <zen/error_log.h>
-//#include <zen/time.h>
#include "progress_indicator.h"
#include "../lib/status_handler.h"
#include "../lib/process_xml.h"
#include "../lib/return_codes.h"
+namespace fff
+{
class BatchRequestSwitchToMainDialog {};
//BatchStatusHandler(SyncProgressDialog) will internally process Window messages! disable GUI controls to avoid unexpected callbacks!
-class BatchStatusHandler : public zen::StatusHandler //throw AbortProcess, BatchRequestSwitchToMainDialog
+class BatchStatusHandler : public StatusHandler //throw AbortProcess, BatchRequestSwitchToMainDialog
{
public:
BatchStatusHandler(bool showProgress, //defines: -start minimized and -quit immediately when finished
+ bool autoCloseDialog,
const std::wstring& jobName, //should not be empty for a batch job!
const Zstring& soundFileSyncComplete,
- const std::chrono::system_clock::time_point& batchStartTime,
+ const std::chrono::system_clock::time_point& startTime,
const Zstring& logFolderPathPhrase,
int logfilesCountLimit, //0: logging inactive; < 0: no limit
size_t lastSyncsLogFileSizeMax,
bool ignoreErrors,
- xmlAccess::BatchErrorDialog batchErrorDialog,
+ BatchErrorDialog batchErrorDialog,
size_t automaticRetryCount,
size_t automaticRetryDelay,
- zen::FfsReturnCode& returnCode,
+ FfsReturnCode& returnCode,
const Zstring& postSyncCommand,
- zen::PostSyncCondition postSyncCondition,
- xmlAccess::PostSyncAction postSyncAction);
+ PostSyncCondition postSyncCondition,
+ PostSyncAction postSyncAction);
~BatchStatusHandler();
void initNewPhase (int itemsTotal, int64_t bytesTotal, Phase phaseID) override;
void updateProcessedData(int itemsDelta, int64_t bytesDelta) override;
- void reportInfo (const std::wstring& text) override;
- void forceUiRefresh () override;
+ void reportInfo (const std::wstring& text) override;
+ void forceUiRefreshNoThrow() override;
void reportWarning (const std::wstring& warningMessage, bool& warningActive) override;
Response reportError (const std::wstring& errorMessage, size_t retryNumber ) override;
@@ -55,9 +57,9 @@ private:
bool switchToGuiRequested_ = false;
const int logfilesCountLimit_;
const size_t lastSyncsLogFileSizeMax_;
- const xmlAccess::BatchErrorDialog batchErrorDialog_;
+ const BatchErrorDialog batchErrorDialog_;
zen::ErrorLog errorLog_; //list of non-resolved errors and warnings
- zen::FfsReturnCode& returnCode_;
+ FfsReturnCode& returnCode_;
const size_t automaticRetryCount_;
const size_t automaticRetryDelay_;
@@ -65,12 +67,12 @@ private:
SyncProgressDialog* progressDlg_; //managed to have shorter lifetime than this handler!
const std::wstring jobName_;
- const std::chrono::system_clock::time_point batchStartTime_;
- const time_t startTime_ = std::time(nullptr); //don't use wxStopWatch: may overflow after a few days due to ::QueryPerformanceCounter()
+ const std::chrono::system_clock::time_point startTime_;
const Zstring logFolderPathPhrase_;
const Zstring postSyncCommand_;
- const zen::PostSyncCondition postSyncCondition_;
+ const PostSyncCondition postSyncCondition_;
};
+}
#endif //BATCH_STATUS_HANDLER_H_857390451451234566
diff --git a/FreeFileSync/Source/ui/cfg_grid.cpp b/FreeFileSync/Source/ui/cfg_grid.cpp
index 3d6cc451..775a3f16 100755
--- a/FreeFileSync/Source/ui/cfg_grid.cpp
+++ b/FreeFileSync/Source/ui/cfg_grid.cpp
@@ -15,11 +15,12 @@
#include "../lib/ffs_paths.h"
using namespace zen;
+using namespace fff;
-Zstring zen::getLastRunConfigPath()
+Zstring fff::getLastRunConfigPath()
{
- return zen::getConfigDirPathPf() + Zstr("LastRun.ffs_gui");
+ return getConfigDirPathPf() + Zstr("LastRun.ffs_gui");
}
@@ -170,6 +171,25 @@ public:
private:
size_t getRowCount() const override { return cfgView_.getRowCount(); }
+ static int getDaysPast(time_t last)
+ {
+ time_t now = std::time(nullptr);
+
+ const TimeComp tcNow = getLocalTime(now);
+ const TimeComp tcLast = getLocalTime(last);
+ if (tcNow == TimeComp() || tcLast == TimeComp())
+ {
+ assert(false);
+ return 0;
+ }
+
+ //truncate down to midnight => incorrect during DST switches, but doesn't matter due to numeric::round() below
+ now -= tcNow .hour * 3600 + tcNow .minute * 60 + tcNow .second;
+ last -= tcLast.hour * 3600 + tcLast.minute * 60 + tcLast.second;
+
+ return numeric::round((now - last) / (24.0 * 3600));
+ }
+
std::wstring getValue(size_t row, ColumnType colType) const override
{
if (const ConfigView::Details* item = cfgView_.getItem(row))
@@ -186,7 +206,7 @@ private:
if (item->lastSyncTime == 0)
return std::wstring(1, EN_DASH);
- const int daysPast = numeric::round((std::time(nullptr) - item->lastSyncTime) / (24.0 * 3600));
+ const int daysPast = getDaysPast(item->lastSyncTime);
if (daysPast == 0)
return _("Today");
@@ -240,11 +260,9 @@ private:
{
wxDCTextColourChanger dummy2(dc);
if (syncOverdueDays_ > 0)
- {
- const int daysPast = numeric::round((std::time(nullptr) - item->lastSyncTime) / (24.0 * 3600));
- if (daysPast >= syncOverdueDays_)
+ if (getDaysPast(item->lastSyncTime) >= syncOverdueDays_)
dummy2.Set(*wxRED);
- }
+
drawCellText(dc, rectTmp, getValue(row, colType), wxALIGN_CENTER);
}
break;
diff --git a/FreeFileSync/Source/ui/cfg_grid.h b/FreeFileSync/Source/ui/cfg_grid.h
index 8a898aa7..7633d3c2 100755
--- a/FreeFileSync/Source/ui/cfg_grid.h
+++ b/FreeFileSync/Source/ui/cfg_grid.h
@@ -10,7 +10,8 @@
#include <wx+/grid.h>
#include <zen/zstring.h>
-namespace zen
+
+namespace fff
{
enum class ColumnTypeCfg
{
@@ -86,7 +87,7 @@ public:
size_t getRowCount() const { assert(cfgList_.size() == cfgListView_.size()); return cfgListView_.size(); }
void setSortDirection(ColumnTypeCfg colType, bool ascending);
- std::pair<ColumnTypeCfg, bool> getSortDirection() { return std::make_pair(sortColumn_, sortAscending_); }
+ std::pair<ColumnTypeCfg, bool> getSortDirection() { return { sortColumn_, sortAscending_ }; }
private:
ConfigView (const ConfigView&) = delete;
@@ -109,13 +110,13 @@ private:
namespace cfggrid
{
-void init(Grid& grid);
-ConfigView& getDataView(Grid& grid); //grid.Refresh() after making changes!
+void init(zen::Grid& grid);
+ConfigView& getDataView(zen::Grid& grid); //grid.Refresh() after making changes!
-void addAndSelect(Grid& grid, const std::vector<Zstring>& filePaths, bool scrollToSelection);
+void addAndSelect(zen::Grid& grid, const std::vector<Zstring>& filePaths, bool scrollToSelection);
-int getSyncOverdueDays(Grid& grid);
-void setSyncOverdueDays(Grid& grid, int syncOverdueDays);
+int getSyncOverdueDays(zen::Grid& grid);
+void setSyncOverdueDays(zen::Grid& grid, int syncOverdueDays);
}
}
diff --git a/FreeFileSync/Source/ui/command_box.cpp b/FreeFileSync/Source/ui/command_box.cpp
index fc848fa2..3468415a 100755
--- a/FreeFileSync/Source/ui/command_box.cpp
+++ b/FreeFileSync/Source/ui/command_box.cpp
@@ -12,6 +12,7 @@
#include <zen/utf.h>
using namespace zen;
+using namespace fff;
namespace
@@ -24,7 +25,7 @@ std::vector<std::pair<std::wstring, Zstring>> getDefaultCommands() //(gui name/c
{
return
{
- //{_("Sleep"), Zstr("rundll32.exe powrprof.dll,SetSuspendState Sleep")},
+ //{_("System: Sleep"), Zstr("rundll32.exe powrprof.dll,SetSuspendState Sleep")},
};
}
diff --git a/FreeFileSync/Source/ui/command_box.h b/FreeFileSync/Source/ui/command_box.h
index 719a62ac..ddc6f7d0 100755
--- a/FreeFileSync/Source/ui/command_box.h
+++ b/FreeFileSync/Source/ui/command_box.h
@@ -14,9 +14,10 @@
#include <zen/string_tools.h>
#include <zen/zstring.h>
-//combobox with history function + functionality to delete items (DEL)
-
+//combobox with history function + functionality to delete items (DEL)
+namespace fff
+{
class CommandBox : public wxComboBox
{
public:
@@ -54,6 +55,6 @@ private:
const std::vector<std::pair<std::wstring, Zstring>> defaultCommands_;
};
-
+}
#endif //COMMAND_BOX_H_18947773210473214
diff --git a/FreeFileSync/Source/ui/file_grid.cpp b/FreeFileSync/Source/ui/file_grid.cpp
index 2a440adc..7e704ba1 100755
--- a/FreeFileSync/Source/ui/file_grid.cpp
+++ b/FreeFileSync/Source/ui/file_grid.cpp
@@ -21,11 +21,12 @@
#include "../file_hierarchy.h"
using namespace zen;
-using namespace filegrid;
+using namespace fff;
-const wxEventType zen::EVENT_GRID_CHECK_ROWS = wxNewEventType();
-const wxEventType zen::EVENT_GRID_SYNC_DIRECTION = wxNewEventType();
+const wxEventType fff::EVENT_GRID_CHECK_ROWS = wxNewEventType();
+const wxEventType fff::EVENT_GRID_SYNC_DIRECTION = wxNewEventType();
+
namespace
{
@@ -67,10 +68,10 @@ std::pair<ptrdiff_t, ptrdiff_t> getVisibleRows(const Grid& grid) //returns range
const ptrdiff_t rowFrom = grid.getRowAtPos(topLeft.y); //return -1 for invalid position, rowCount if out of range
const ptrdiff_t rowTo = grid.getRowAtPos(bottom.y);
if (rowFrom >= 0 && rowTo >= 0)
- return std::make_pair(rowFrom, std::min(rowTo + 1, rowCount));
+ return { rowFrom, std::min(rowTo + 1, rowCount) };
}
assert(false);
- return std::make_pair(0, 0);
+ return {};
}
@@ -1752,7 +1753,7 @@ void filegrid::highlightSyncAction(Grid& gridCenter, bool value)
}
-wxBitmap zen::getSyncOpImage(SyncOperation syncOp)
+wxBitmap fff::getSyncOpImage(SyncOperation syncOp)
{
switch (syncOp) //evaluate comparison result and sync direction
{
@@ -1792,7 +1793,7 @@ wxBitmap zen::getSyncOpImage(SyncOperation syncOp)
}
-wxBitmap zen::getCmpResultImage(CompareFilesResult cmpResult)
+wxBitmap fff::getCmpResultImage(CompareFilesResult cmpResult)
{
switch (cmpResult)
{
diff --git a/FreeFileSync/Source/ui/file_grid.h b/FreeFileSync/Source/ui/file_grid.h
index 40853ceb..3904786a 100755
--- a/FreeFileSync/Source/ui/file_grid.h
+++ b/FreeFileSync/Source/ui/file_grid.h
@@ -13,27 +13,27 @@
#include "../lib/icon_buffer.h"
-namespace zen
+namespace fff
{
//setup grid to show grid view within three components:
namespace filegrid
{
-void init(Grid& gridLeft, Grid& gridCenter, Grid& gridRight);
-FileView& getDataView(Grid& grid);
+void init(zen::Grid& gridLeft, zen::Grid& gridCenter, zen::Grid& gridRight);
+FileView& getDataView(zen::Grid& grid);
-void highlightSyncAction(Grid& gridCenter, bool value);
+void highlightSyncAction(zen::Grid& gridCenter, bool value);
-void setupIcons(Grid& gridLeft, Grid& gridCenter, Grid& gridRight, bool show, IconBuffer::IconSize sz);
+void setupIcons(zen::Grid& gridLeft, zen::Grid& gridCenter, zen::Grid& gridRight, bool show, IconBuffer::IconSize sz);
-void setItemPathForm(Grid& grid, ItemPathFormat fmt); //only for left/right grid
+void setItemPathForm(zen::Grid& grid, ItemPathFormat fmt); //only for left/right grid
-void refresh(Grid& gridLeft, Grid& gridCenter, Grid& gridRight);
+void refresh(zen::Grid& gridLeft, zen::Grid& gridCenter, zen::Grid& gridRight);
-void setScrollMaster(Grid& grid);
+void setScrollMaster(zen::Grid& grid);
//mark rows selected in overview panel and navigate to leading object
-void setNavigationMarker(Grid& gridLeft,
+void setNavigationMarker(zen::Grid& gridLeft,
std::unordered_set<const FileSystemObject*>&& markedFilesAndLinks,//mark files/symlinks directly within a container
std::unordered_set<const ContainerObject*>&& markedContainer); //mark full container including child-objects
}
diff --git a/FreeFileSync/Source/ui/file_grid_attr.h b/FreeFileSync/Source/ui/file_grid_attr.h
index 0257f268..ea3c6303 100755
--- a/FreeFileSync/Source/ui/file_grid_attr.h
+++ b/FreeFileSync/Source/ui/file_grid_attr.h
@@ -11,7 +11,7 @@
#include <cassert>
-namespace zen
+namespace fff
{
enum class ColumnTypeRim
{
diff --git a/FreeFileSync/Source/ui/file_view.cpp b/FreeFileSync/Source/ui/file_view.cpp
index f2527520..c68357b0 100755
--- a/FreeFileSync/Source/ui/file_view.cpp
+++ b/FreeFileSync/Source/ui/file_view.cpp
@@ -11,6 +11,7 @@
#include <zen/perf.h>
using namespace zen;
+using namespace fff;
template <class StatusResult>
diff --git a/FreeFileSync/Source/ui/file_view.h b/FreeFileSync/Source/ui/file_view.h
index ad399401..deaf763f 100755
--- a/FreeFileSync/Source/ui/file_view.h
+++ b/FreeFileSync/Source/ui/file_view.h
@@ -13,10 +13,9 @@
#include "../file_hierarchy.h"
-namespace zen
+namespace fff
{
-//grid view of FolderComparison
-class FileView
+class FileView //grid view of FolderComparison
{
public:
FileView() {}
@@ -101,11 +100,11 @@ public:
void removeInvalidRows(); //remove references to rows that have been deleted meanwhile: call after manual deletion and synchronization!
//sorting...
- void sortView(zen::ColumnTypeRim type, zen::ItemPathFormat pathFmt, bool onLeft, bool ascending); //always call this method for sorting, never sort externally!
+ void sortView(ColumnTypeRim type, ItemPathFormat pathFmt, bool onLeft, bool ascending); //always call this method for sorting, never sort externally!
struct SortInfo
{
- zen::ColumnTypeRim type = zen::ColumnTypeRim::ITEM_PATH;
+ ColumnTypeRim type = ColumnTypeRim::ITEM_PATH;
bool onLeft = false;
bool ascending = false;
};
@@ -173,7 +172,7 @@ private:
template <bool ascending>
struct LessSyncDirection;
- Opt<SortInfo> currentSort_;
+ zen::Opt<SortInfo> currentSort_;
};
diff --git a/FreeFileSync/Source/ui/folder_history_box.cpp b/FreeFileSync/Source/ui/folder_history_box.cpp
index ff434468..fc4902d9 100755
--- a/FreeFileSync/Source/ui/folder_history_box.cpp
+++ b/FreeFileSync/Source/ui/folder_history_box.cpp
@@ -11,6 +11,7 @@
#include <gtk/gtk.h>
using namespace zen;
+using namespace fff;
FolderHistoryBox::FolderHistoryBox(wxWindow* parent,
diff --git a/FreeFileSync/Source/ui/folder_history_box.h b/FreeFileSync/Source/ui/folder_history_box.h
index 94b9f494..0252d7cd 100755
--- a/FreeFileSync/Source/ui/folder_history_box.h
+++ b/FreeFileSync/Source/ui/folder_history_box.h
@@ -13,10 +13,10 @@
#include <zen/stl_tools.h>
#include <zen/utf.h>
-//combobox with history function + functionality to delete items (DEL)
-
-class FolderHistory
+namespace fff
+{
+class FolderHistory //combobox with history function + functionality to delete items (DEL)
{
public:
FolderHistory() {}
@@ -87,6 +87,6 @@ private:
std::shared_ptr<FolderHistory> sharedHistory_;
};
-
+}
#endif //FOLDER_HISTORY_BOX_H_08170517045945
diff --git a/FreeFileSync/Source/ui/folder_pair.h b/FreeFileSync/Source/ui/folder_pair.h
index 49a24c7c..5b71c09a 100755
--- a/FreeFileSync/Source/ui/folder_pair.h
+++ b/FreeFileSync/Source/ui/folder_pair.h
@@ -20,7 +20,7 @@
#include "../structures.h"
-namespace zen
+namespace fff
{
//basic functionality for handling alternate folder pair configuration: change sync-cfg/filter cfg, right-click context menu, button icons...
@@ -33,15 +33,15 @@ public:
void setConfig(AltCompCfgPtr compConfig, AltSyncCfgPtr syncCfg, const FilterConfig& filter)
{
- altCompConfig = compConfig;
- altSyncConfig = syncCfg;
- localFilter = filter;
+ altCompConfig_ = compConfig;
+ altSyncConfig_ = syncCfg;
+ localFilter_ = filter;
refreshButtons();
}
- AltCompCfgPtr getAltCompConfig () const { return altCompConfig; }
- AltSyncCfgPtr getAltSyncConfig () const { return altSyncConfig; }
- FilterConfig getAltFilterConfig() const { return localFilter; }
+ AltCompCfgPtr getAltCompConfig () const { return altCompConfig_; }
+ AltSyncCfgPtr getAltSyncConfig () const { return altSyncConfig_; }
+ FilterConfig getAltFilterConfig() const { return localFilter_; }
FolderPairPanelBasic(GuiPanel& basicPanel) : //takes reference on basic panel to be enhanced
@@ -52,16 +52,18 @@ public:
basicPanel_.m_bpButtonAltSyncCfg ->Connect(wxEVT_RIGHT_DOWN, wxCommandEventHandler(FolderPairPanelBasic::OnAltSyncCfgContext ), nullptr, this);
basicPanel_.m_bpButtonLocalFilter->Connect(wxEVT_RIGHT_DOWN, wxCommandEventHandler(FolderPairPanelBasic::OnLocalFilterCfgContext), nullptr, this);
- basicPanel_.m_bpButtonRemovePair->SetBitmapLabel(getResourceImage(L"item_remove"));
+ basicPanel_.m_bpButtonRemovePair->SetBitmapLabel(zen::getResourceImage(L"item_remove"));
}
private:
void refreshButtons()
{
- if (altCompConfig.get())
+ using namespace zen;
+
+ if (altCompConfig_.get())
{
setImage(*basicPanel_.m_bpButtonAltCompCfg, getResourceImage(L"cfg_compare_small"));
- basicPanel_.m_bpButtonAltCompCfg->SetToolTip(_("Local comparison settings") + L" (" + getVariantName(altCompConfig->compareVar) + L")");
+ basicPanel_.m_bpButtonAltCompCfg->SetToolTip(_("Local comparison settings") + L" (" + getVariantName(altCompConfig_->compareVar) + L")");
}
else
{
@@ -69,10 +71,10 @@ private:
basicPanel_.m_bpButtonAltCompCfg->SetToolTip(_("Local comparison settings"));
}
- if (altSyncConfig.get())
+ if (altSyncConfig_.get())
{
setImage(*basicPanel_.m_bpButtonAltSyncCfg, getResourceImage(L"cfg_sync_small"));
- basicPanel_.m_bpButtonAltSyncCfg->SetToolTip(_("Local synchronization settings") + L" (" + getVariantName(altSyncConfig->directionCfg.var) + L")");
+ basicPanel_.m_bpButtonAltSyncCfg->SetToolTip(_("Local synchronization settings") + L" (" + getVariantName(altSyncConfig_->directionCfg.var) + L")");
}
else
{
@@ -80,7 +82,7 @@ private:
basicPanel_.m_bpButtonAltSyncCfg->SetToolTip(_("Local synchronization settings"));
}
- if (!isNullFilter(localFilter))
+ if (!isNullFilter(localFilter_))
{
setImage(*basicPanel_.m_bpButtonLocalFilter, getResourceImage(L"filter_small"));
basicPanel_.m_bpButtonLocalFilter->SetToolTip(_("Local filter") + L" (" + _("Active") + L")");
@@ -96,13 +98,13 @@ private:
{
auto removeAltCompCfg = [&]
{
- this->altCompConfig.reset(); //"this->" galore: workaround GCC compiler bugs
+ this->altCompConfig_.reset(); //"this->" galore: workaround GCC compiler bugs
this->refreshButtons();
this->onAltCompCfgChange();
};
- ContextMenu menu;
- menu.addItem(_("Remove local settings"), removeAltCompCfg, nullptr, altCompConfig.get() != nullptr);
+ zen::ContextMenu menu;
+ menu.addItem(_("Remove local settings"), removeAltCompCfg, nullptr, altCompConfig_.get() != nullptr);
menu.popup(basicPanel_);
}
@@ -110,13 +112,13 @@ private:
{
auto removeAltSyncCfg = [&]
{
- this->altSyncConfig.reset();
+ this->altSyncConfig_.reset();
this->refreshButtons();
this->onAltSyncCfgChange();
};
- ContextMenu menu;
- menu.addItem(_("Remove local settings"), removeAltSyncCfg, nullptr, altSyncConfig.get() != nullptr);
+ zen::ContextMenu menu;
+ menu.addItem(_("Remove local settings"), removeAltSyncCfg, nullptr, altSyncConfig_.get() != nullptr);
menu.popup(basicPanel_);
}
@@ -124,28 +126,28 @@ private:
{
auto removeLocalFilterCfg = [&]
{
- this->localFilter = FilterConfig();
+ this->localFilter_ = FilterConfig();
this->refreshButtons();
this->onLocalFilterCfgChange();
};
std::unique_ptr<FilterConfig>& filterCfgOnClipboard = getFilterCfgOnClipboardRef();
- auto copyFilter = [&] { filterCfgOnClipboard = std::make_unique<FilterConfig>(this->localFilter); };
+ auto copyFilter = [&] { filterCfgOnClipboard = std::make_unique<FilterConfig>(this->localFilter_); };
auto pasteFilter = [&]
{
if (filterCfgOnClipboard)
{
- this->localFilter = *filterCfgOnClipboard;
+ this->localFilter_ = *filterCfgOnClipboard;
this->refreshButtons();
this->onLocalFilterCfgChange();
}
};
- ContextMenu menu;
- menu.addItem(_("Clear local filter"), removeLocalFilterCfg, nullptr, !isNullFilter(localFilter));
+ zen::ContextMenu menu;
+ menu.addItem(_("Clear local filter"), removeLocalFilterCfg, nullptr, !isNullFilter(localFilter_));
menu.addSeparator();
- menu.addItem( _("Copy"), copyFilter, nullptr, !isNullFilter(localFilter));
+ menu.addItem( _("Copy"), copyFilter, nullptr, !isNullFilter(localFilter_));
menu.addItem( _("Paste"), pasteFilter, nullptr, filterCfgOnClipboard.get() != nullptr);
menu.popup(basicPanel_);
}
@@ -162,9 +164,9 @@ private:
GuiPanel& basicPanel_; //panel to be enhanced by this template
//alternate configuration attached to it
- AltCompCfgPtr altCompConfig; //optional
- AltSyncCfgPtr altSyncConfig; //
- FilterConfig localFilter;
+ AltCompCfgPtr altCompConfig_; //optional
+ AltSyncCfgPtr altSyncConfig_; //
+ FilterConfig localFilter_;
};
}
diff --git a/FreeFileSync/Source/ui/folder_selector.cpp b/FreeFileSync/Source/ui/folder_selector.cpp
index 73d4d461..eed43dc6 100755
--- a/FreeFileSync/Source/ui/folder_selector.cpp
+++ b/FreeFileSync/Source/ui/folder_selector.cpp
@@ -20,6 +20,7 @@
using namespace zen;
+using namespace fff;
using AFS = AbstractFileSystem;
@@ -49,8 +50,8 @@ void setFolderPathPhrase(const Zstring& folderPathPhrase, FolderHistoryBox* comb
//##############################################################################################################
-const wxEventType zen::EVENT_ON_FOLDER_SELECTED = wxNewEventType();
-const wxEventType zen::EVENT_ON_FOLDER_MANUAL_EDIT = wxNewEventType();
+const wxEventType fff::EVENT_ON_FOLDER_SELECTED = wxNewEventType();
+const wxEventType fff::EVENT_ON_FOLDER_MANUAL_EDIT = wxNewEventType();
FolderSelector::FolderSelector(wxWindow& dropWindow,
diff --git a/FreeFileSync/Source/ui/folder_selector.h b/FreeFileSync/Source/ui/folder_selector.h
index a0271f6f..a2154ac6 100755
--- a/FreeFileSync/Source/ui/folder_selector.h
+++ b/FreeFileSync/Source/ui/folder_selector.h
@@ -14,7 +14,7 @@
#include "folder_history_box.h"
-namespace zen
+namespace fff
{
//handle drag and drop, tooltip, label and manual input, coordinating a wxWindow, wxButton, and wxComboBox/wxTextCtrl
/*
@@ -46,11 +46,13 @@ public:
Zstring getPath() const;
void setPath(const Zstring& folderPathPhrase);
+ void setBackgroundText(const std::wstring& text) { folderComboBox_.SetHint(text); }
+
private:
virtual bool shouldSetDroppedPaths(const std::vector<Zstring>& shellItemPaths) { return true; } //return true if drop should be processed
void onMouseWheel (wxMouseEvent& event);
- void onItemPathDropped(FileDropEvent& event);
+ void onItemPathDropped(zen::FileDropEvent& event);
void onEditFolderPath (wxCommandEvent& event);
void onSelectFolder (wxCommandEvent& event);
void onSelectAltFolder(wxCommandEvent& event);
diff --git a/FreeFileSync/Source/ui/gui_generated.cpp b/FreeFileSync/Source/ui/gui_generated.cpp
index cbe00bd7..747095d1 100755
--- a/FreeFileSync/Source/ui/gui_generated.cpp
+++ b/FreeFileSync/Source/ui/gui_generated.cpp
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Nov 6 2017)
+// C++ code generated with wxFormBuilder (version Jan 23 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -280,7 +280,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer182;
bSizer182 = new wxBoxSizer( wxHORIZONTAL );
- m_folderPathLeft = new FolderHistoryBox( m_panelTopLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_folderPathLeft = new fff::FolderHistoryBox( m_panelTopLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer182->Add( m_folderPathLeft, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectFolderLeft = new wxButton( m_panelTopLeft, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -351,7 +351,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer179;
bSizer179 = new wxBoxSizer( wxHORIZONTAL );
- m_folderPathRight = new FolderHistoryBox( m_panelTopRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_folderPathRight = new fff::FolderHistoryBox( m_panelTopRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer179->Add( m_folderPathRight, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectFolderRight = new wxButton( m_panelTopRight, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -402,7 +402,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer1711;
bSizer1711 = new wxBoxSizer( wxVERTICAL );
- m_splitterMain = new zen::TripleSplitter( m_panelCenter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_splitterMain = new fff::TripleSplitter( m_panelCenter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer1781;
bSizer1781 = new wxBoxSizer( wxHORIZONTAL );
@@ -703,10 +703,10 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
m_staticTextViewType->Wrap( -1 );
bSizerViewFilter->Add( m_staticTextViewType, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonViewTypeSyncAction = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 82, 42 ), wxBU_AUTODRAW );
+ m_bpButtonViewTypeSyncAction = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 82, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonViewTypeSyncAction, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxRIGHT, 5 );
- m_bpButtonShowExcluded = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowExcluded = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowExcluded, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
@@ -716,46 +716,46 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
m_staticTextSelectView->Wrap( -1 );
bSizerViewFilter->Add( m_staticTextSelectView, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowDeleteLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowDeleteLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowDeleteLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowUpdateLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowUpdateLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowUpdateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowCreateLeft = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowCreateLeft = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowLeftOnly = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowLeftOnly = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowLeftOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowLeftNewer = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowLeftNewer = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowLeftNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowEqual = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowEqual = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowEqual, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowDoNothing = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowDoNothing = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowDoNothing, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowDifferent = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowDifferent = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowDifferent, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowRightNewer = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowRightNewer = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowRightNewer, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowRightOnly = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowRightOnly = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowRightOnly, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowCreateRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowCreateRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowUpdateRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowUpdateRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowUpdateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowDeleteRight = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowDeleteRight = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowDeleteRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonShowConflict = new ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
+ m_bpButtonShowConflict = new zen::ToggleButton( m_panelViewFilter, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42, 42 ), wxBU_AUTODRAW );
bSizerViewFilter->Add( m_bpButtonShowConflict, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
@@ -1769,7 +1769,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
wxBoxSizer* bSizer156;
bSizer156 = new wxBoxSizer( wxHORIZONTAL );
- m_versioningFolderPath = new FolderHistoryBox( m_panelVersioning, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_versioningFolderPath = new fff::FolderHistoryBox( m_panelVersioning, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer156->Add( m_versioningFolderPath, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectVersioningFolder = new wxButton( m_panelVersioning, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -1867,7 +1867,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_choicePostSyncCondition->SetSelection( 0 );
bSizer251->Add( m_choicePostSyncCondition, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_comboBoxPostSyncCommand = new CommandBox( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_comboBoxPostSyncCommand = new fff::CommandBox( m_panelSyncSettings, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer251->Add( m_comboBoxPostSyncCommand, 1, wxALIGN_CENTER_VERTICAL, 5 );
@@ -1991,7 +1991,7 @@ FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID
bSizer134->Add( m_bpButtonRemovePair, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_folderPathLeft = new FolderHistoryBox( m_panelLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_folderPathLeft = new fff::FolderHistoryBox( m_panelLeft, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer134->Add( m_folderPathLeft, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectFolderLeft = new wxButton( m_panelLeft, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -2041,7 +2041,7 @@ FolderPairPanelGenerated::FolderPairPanelGenerated( wxWindow* parent, wxWindowID
wxBoxSizer* bSizer135;
bSizer135 = new wxBoxSizer( wxHORIZONTAL );
- m_folderPathRight = new FolderHistoryBox( m_panelRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_folderPathRight = new fff::FolderHistoryBox( m_panelRight, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer135->Add( m_folderPathRight, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectFolderRight = new wxButton( m_panelRight, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -3213,11 +3213,14 @@ SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWind
bSizerStdButtons = new wxBoxSizer( wxHORIZONTAL );
+ m_checkBoxAutoClose = new wxCheckBox( this, wxID_ANY, _("Auto-Close"), wxDefaultPosition, wxDefaultSize, 0 );
+ bSizerStdButtons->Add( m_checkBoxAutoClose, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
m_buttonClose = new wxButton( this, wxID_OK, _("Close"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
m_buttonClose->SetDefault();
m_buttonClose->Enable( false );
- bSizerStdButtons->Add( m_buttonClose, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ bSizerStdButtons->Add( m_buttonClose, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
m_buttonPause = new wxButton( this, wxID_ANY, _("&Pause"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
bSizerStdButtons->Add( m_buttonPause, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
@@ -3226,7 +3229,7 @@ SyncProgressPanelGenerated::SyncProgressPanelGenerated( wxWindow* parent, wxWind
bSizerStdButtons->Add( m_buttonStop, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
- bSizerRoot->Add( bSizerStdButtons, 0, wxALIGN_RIGHT, 5 );
+ bSizerRoot->Add( bSizerStdButtons, 0, wxEXPAND, 5 );
this->SetSizer( bSizerRoot );
@@ -3248,13 +3251,13 @@ LogPanelGenerated::LogPanelGenerated( wxWindow* parent, wxWindowID id, const wxP
wxBoxSizer* bSizer154;
bSizer154 = new wxBoxSizer( wxVERTICAL );
- m_bpButtonErrors = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49, 49 ), wxBU_AUTODRAW );
+ m_bpButtonErrors = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49, 49 ), wxBU_AUTODRAW );
bSizer154->Add( m_bpButtonErrors, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonWarnings = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49, 49 ), wxBU_AUTODRAW );
+ m_bpButtonWarnings = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49, 49 ), wxBU_AUTODRAW );
bSizer154->Add( m_bpButtonWarnings, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
- m_bpButtonInfo = new ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49, 49 ), wxBU_AUTODRAW );
+ m_bpButtonInfo = new zen::ToggleButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 49, 49 ), wxBU_AUTODRAW );
bSizer154->Add( m_bpButtonInfo, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
@@ -3315,17 +3318,35 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer180;
bSizer180 = new wxBoxSizer( wxHORIZONTAL );
- wxBoxSizer* bSizer236;
- bSizer236 = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* bSizer2361;
+ bSizer2361 = new wxBoxSizer( wxVERTICAL );
+
+ m_staticText146 = new wxStaticText( m_panel35, wxID_ANY, _("Progress dialog:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText146->Wrap( -1 );
+ bSizer2361->Add( m_staticText146, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+
+ ffgSizer11 = new wxFlexGridSizer( 0, 2, 5, 5 );
+ ffgSizer11->SetFlexibleDirection( wxBOTH );
+ ffgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_bitmapMinimizeToTray = new wxStaticBitmap( m_panel35, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer236->Add( m_bitmapMinimizeToTray, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
+ ffgSizer11->Add( m_bitmapMinimizeToTray, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_checkBoxRunMinimized = new wxCheckBox( m_panel35, wxID_ANY, _("Run minimized"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer236->Add( m_checkBoxRunMinimized, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ ffgSizer11->Add( m_checkBoxRunMinimized, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
+
+
+ ffgSizer11->Add( 0, 0, 1, wxEXPAND, 5 );
+
+ m_checkBoxAutoClose = new wxCheckBox( m_panel35, wxID_ANY, _("Auto-Close"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_checkBoxAutoClose->SetValue(true);
+ ffgSizer11->Add( m_checkBoxAutoClose, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+
+
+ bSizer2361->Add( ffgSizer11, 0, wxEXPAND|wxALL, 5 );
- bSizer180->Add( bSizer236, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer180->Add( bSizer2361, 0, wxALL, 5 );
m_staticline26 = new wxStaticLine( m_panel35, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
bSizer180->Add( m_staticline26, 0, wxEXPAND, 5 );
@@ -3426,7 +3447,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer1721;
bSizer1721 = new wxBoxSizer( wxHORIZONTAL );
- m_logFolderPath = new FolderHistoryBox( m_panelLogfile, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ 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 );
@@ -3632,7 +3653,7 @@ CopyToDlgGenerated::CopyToDlgGenerated( wxWindow* parent, wxWindowID id, const w
wxBoxSizer* bSizer182;
bSizer182 = new wxBoxSizer( wxHORIZONTAL );
- m_targetFolderPath = new FolderHistoryBox( m_panel31, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
+ m_targetFolderPath = new fff::FolderHistoryBox( m_panel31, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
bSizer182->Add( m_targetFolderPath, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_buttonSelectTargetFolder = new wxButton( m_panel31, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
@@ -3938,15 +3959,16 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
bSizer1881 = new wxBoxSizer( wxHORIZONTAL );
m_buttonResetDialogs = new zen::BitmapTextButton( m_panel39, wxID_ANY, _("Show hidden dialogs again"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
- m_buttonResetDialogs->SetToolTip( _("Show all permanently hidden dialogs and warning messages again") );
+ bSizer1881->Add( m_buttonResetDialogs, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
- bSizer1881->Add( m_buttonResetDialogs, 0, wxALL|wxALIGN_CENTER_VERTICAL, 10 );
+ m_staticText923 = new wxStaticText( m_panel39, wxID_ANY, _("Show all permanently hidden dialogs and warning messages again"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText923->Wrap( 350 );
+ m_staticText923->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
- m_staticline40 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
- bSizer1881->Add( m_staticline40, 0, wxEXPAND, 5 );
+ bSizer1881->Add( m_staticText923, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
- bSizer166->Add( bSizer1881, 0, 0, 5 );
+ bSizer166->Add( bSizer1881, 0, wxALL, 5 );
m_panel39->SetSizer( bSizer166 );
diff --git a/FreeFileSync/Source/ui/gui_generated.h b/FreeFileSync/Source/ui/gui_generated.h
index 2272410e..3b2287e1 100755
--- a/FreeFileSync/Source/ui/gui_generated.h
+++ b/FreeFileSync/Source/ui/gui_generated.h
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Nov 6 2017)
+// C++ code generated with wxFormBuilder (version Jan 23 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@@ -11,13 +11,13 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
-class CommandBox;
-class FolderHistoryBox;
-class ToggleButton;
+namespace fff { class CommandBox; }
+namespace fff { class FolderHistoryBox; }
+namespace fff { class TripleSplitter; }
namespace zen { class BitmapTextButton; }
namespace zen { class Graph2D; }
namespace zen { class Grid; }
-namespace zen { class TripleSplitter; }
+namespace zen { class ToggleButton; }
#include <wx/string.h>
#include <wx/bitmap.h>
@@ -119,7 +119,7 @@ protected:
wxBoxSizer* bSizerAddFolderPairs;
zen::Grid* m_gridOverview;
wxPanel* m_panelCenter;
- zen::TripleSplitter* m_splitterMain;
+ fff::TripleSplitter* m_splitterMain;
zen::Grid* m_gridMainL;
zen::Grid* m_gridMainC;
zen::Grid* m_gridMainR;
@@ -166,23 +166,23 @@ protected:
wxPanel* m_panelViewFilter;
wxBoxSizer* bSizerViewFilter;
wxStaticText* m_staticTextViewType;
- ToggleButton* m_bpButtonViewTypeSyncAction;
- ToggleButton* m_bpButtonShowExcluded;
+ zen::ToggleButton* m_bpButtonViewTypeSyncAction;
+ zen::ToggleButton* m_bpButtonShowExcluded;
wxStaticText* m_staticTextSelectView;
- ToggleButton* m_bpButtonShowDeleteLeft;
- ToggleButton* m_bpButtonShowUpdateLeft;
- ToggleButton* m_bpButtonShowCreateLeft;
- ToggleButton* m_bpButtonShowLeftOnly;
- ToggleButton* m_bpButtonShowLeftNewer;
- ToggleButton* m_bpButtonShowEqual;
- ToggleButton* m_bpButtonShowDoNothing;
- ToggleButton* m_bpButtonShowDifferent;
- ToggleButton* m_bpButtonShowRightNewer;
- ToggleButton* m_bpButtonShowRightOnly;
- ToggleButton* m_bpButtonShowCreateRight;
- ToggleButton* m_bpButtonShowUpdateRight;
- ToggleButton* m_bpButtonShowDeleteRight;
- ToggleButton* m_bpButtonShowConflict;
+ zen::ToggleButton* m_bpButtonShowDeleteLeft;
+ zen::ToggleButton* m_bpButtonShowUpdateLeft;
+ zen::ToggleButton* m_bpButtonShowCreateLeft;
+ zen::ToggleButton* m_bpButtonShowLeftOnly;
+ zen::ToggleButton* m_bpButtonShowLeftNewer;
+ zen::ToggleButton* m_bpButtonShowEqual;
+ zen::ToggleButton* m_bpButtonShowDoNothing;
+ zen::ToggleButton* m_bpButtonShowDifferent;
+ zen::ToggleButton* m_bpButtonShowRightNewer;
+ zen::ToggleButton* m_bpButtonShowRightOnly;
+ zen::ToggleButton* m_bpButtonShowCreateRight;
+ zen::ToggleButton* m_bpButtonShowUpdateRight;
+ zen::ToggleButton* m_bpButtonShowDeleteRight;
+ zen::ToggleButton* m_bpButtonShowConflict;
wxStaticText* m_staticText96;
wxPanel* m_panelStatistics;
wxBoxSizer* bSizer1801;
@@ -244,13 +244,13 @@ protected:
public:
wxPanel* m_panelTopLeft;
wxBitmapButton* m_bpButtonRemovePair;
- FolderHistoryBox* m_folderPathLeft;
+ fff::FolderHistoryBox* m_folderPathLeft;
wxBitmapButton* m_bpButtonSelectAltFolderLeft;
wxBitmapButton* m_bpButtonAltCompCfg;
wxBitmapButton* m_bpButtonLocalFilter;
wxBitmapButton* m_bpButtonAltSyncCfg;
wxPanel* m_panelTopRight;
- FolderHistoryBox* m_folderPathRight;
+ fff::FolderHistoryBox* m_folderPathRight;
wxBitmapButton* m_bpButtonSelectAltFolderRight;
wxBoxSizer* bSizerStatistics;
wxBoxSizer* bSizerData;
@@ -379,7 +379,7 @@ protected:
wxStaticText* m_staticTextDeletionTypeDescription;
wxHyperlinkCtrl* m_hyperlinkVersioning;
wxPanel* m_panelVersioning;
- FolderHistoryBox* m_versioningFolderPath;
+ fff::FolderHistoryBox* m_versioningFolderPath;
wxButton* m_buttonSelectVersioningFolder;
wxStaticText* m_staticText93;
wxChoice* m_choiceVersioningStyle;
@@ -393,7 +393,7 @@ protected:
wxStaticLine* m_staticline57;
wxBoxSizer* bSizerOnCompletion;
wxStaticText* m_staticText89;
- CommandBox* m_comboBoxPostSyncCommand;
+ fff::CommandBox* m_comboBoxPostSyncCommand;
wxBoxSizer* bSizerStdButtons;
wxButton* m_buttonOkay;
wxButton* m_buttonCancel;
@@ -467,14 +467,14 @@ public:
wxPanel* m_panelLeft;
wxBitmapButton* m_bpButtonFolderPairOptions;
wxBitmapButton* m_bpButtonRemovePair;
- FolderHistoryBox* m_folderPathLeft;
+ fff::FolderHistoryBox* m_folderPathLeft;
wxBitmapButton* m_bpButtonSelectAltFolderLeft;
wxPanel* m_panel20;
wxBitmapButton* m_bpButtonAltCompCfg;
wxBitmapButton* m_bpButtonLocalFilter;
wxBitmapButton* m_bpButtonAltSyncCfg;
wxPanel* m_panelRight;
- FolderHistoryBox* m_folderPathRight;
+ fff::FolderHistoryBox* m_folderPathRight;
wxBitmapButton* m_bpButtonSelectAltFolderRight;
FolderPairPanelGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0 );
@@ -739,6 +739,7 @@ public:
wxNotebook* m_notebookResult;
wxStaticLine* m_staticlineFooter;
wxBoxSizer* bSizerStdButtons;
+ wxCheckBox* m_checkBoxAutoClose;
wxButton* m_buttonClose;
wxButton* m_buttonPause;
wxButton* m_buttonStop;
@@ -756,9 +757,9 @@ class LogPanelGenerated : public wxPanel
private:
protected:
- ToggleButton* m_bpButtonErrors;
- ToggleButton* m_bpButtonWarnings;
- ToggleButton* m_bpButtonInfo;
+ zen::ToggleButton* m_bpButtonErrors;
+ zen::ToggleButton* m_bpButtonWarnings;
+ zen::ToggleButton* m_bpButtonInfo;
wxStaticLine* m_staticline13;
zen::Grid* m_gridMessages;
@@ -787,6 +788,8 @@ protected:
wxStaticText* m_staticTextDescr;
wxStaticLine* m_staticline18;
wxPanel* m_panel35;
+ wxStaticText* m_staticText146;
+ wxFlexGridSizer* ffgSizer11;
wxStaticBitmap* m_bitmapMinimizeToTray;
wxCheckBox* m_checkBoxRunMinimized;
wxStaticLine* m_staticline26;
@@ -824,8 +827,9 @@ protected:
public:
+ wxCheckBox* m_checkBoxAutoClose;
wxChoice* m_choicePostSyncAction;
- FolderHistoryBox* m_logFolderPath;
+ 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 );
@@ -897,7 +901,7 @@ protected:
public:
- FolderHistoryBox* m_targetFolderPath;
+ fff::FolderHistoryBox* m_targetFolderPath;
wxBitmapButton* m_bpButtonSelectAltTargetFolder;
CopyToDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Copy items"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1, -1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER );
@@ -944,7 +948,7 @@ protected:
wxHyperlinkCtrl* m_hyperlink17;
wxStaticLine* m_staticline192;
zen::BitmapTextButton* m_buttonResetDialogs;
- wxStaticLine* m_staticline40;
+ wxStaticText* m_staticText923;
wxStaticLine* m_staticline36;
wxBoxSizer* bSizerStdButtons;
wxButton* m_buttonDefault;
diff --git a/FreeFileSync/Source/ui/gui_status_handler.cpp b/FreeFileSync/Source/ui/gui_status_handler.cpp
index ac9f2479..ee14082a 100755
--- a/FreeFileSync/Source/ui/gui_status_handler.cpp
+++ b/FreeFileSync/Source/ui/gui_status_handler.cpp
@@ -17,7 +17,7 @@
#include "../lib/status_handler_impl.h"
using namespace zen;
-using namespace xmlAccess;
+using namespace fff;
StatusHandlerTemporaryPanel::StatusHandlerTemporaryPanel(MainDialog& dlg) : mainDlg_(dlg)
@@ -122,13 +122,13 @@ void StatusHandlerTemporaryPanel::initNewPhase(int itemsTotal, int64_t bytesTota
mainDlg_.compareStatus_->initNewPhase(); //call after "StatusHandler::initNewPhase"
- forceUiRefresh(); //throw ?; OS X needs a full yield to update GUI and get rid of "dummy" texts
+ forceUiRefresh(); //throw X; OS X needs a full yield to update GUI and get rid of "dummy" texts
}
void StatusHandlerTemporaryPanel::reportInfo(const std::wstring& text)
{
- errorLog_.logMsg(text, TYPE_INFO); //log first!
+ errorLog_.logMsg(text, MSG_TYPE_INFO); //log first!
StatusHandler::reportInfo(text); //throw X
}
@@ -139,11 +139,11 @@ ProcessCallback::Response StatusHandlerTemporaryPanel::reportError(const std::ws
//=> similar behavior like "ignoreErrors" which is also not used for the comparison phase in GUI mode
//always, except for "retry":
- auto guardWriteLog = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { errorLog_.logMsg(errorMessage, TYPE_ERROR); });
+ auto guardWriteLog = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { errorLog_.logMsg(errorMessage, MSG_TYPE_ERROR); });
if (!mainDlg_.compareStatus_->getOptionIgnoreErrors())
{
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(&mainDlg_, DialogInfoType::ERROR2, PopupDialogCfg().
setDetailInstructions(errorMessage),
@@ -158,7 +158,7 @@ ProcessCallback::Response StatusHandlerTemporaryPanel::reportError(const std::ws
case ConfirmationButton3::DECLINE: //retry
guardWriteLog.dismiss();
- errorLog_.logMsg(errorMessage + L"\n-> " + _("Retrying operation..."), TYPE_INFO); //explain why there are duplicate "doing operation X" info messages in the log!
+ errorLog_.logMsg(errorMessage + L"\n-> " + _("Retrying operation..."), MSG_TYPE_INFO); //explain why there are duplicate "doing operation X" info messages in the log!
return ProcessCallback::RETRY;
case ConfirmationButton3::CANCEL:
@@ -176,23 +176,23 @@ ProcessCallback::Response StatusHandlerTemporaryPanel::reportError(const std::ws
void StatusHandlerTemporaryPanel::reportFatalError(const std::wstring& errorMessage)
{
- errorLog_.logMsg(errorMessage, TYPE_FATAL_ERROR);
+ errorLog_.logMsg(errorMessage, MSG_TYPE_FATAL_ERROR);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
showNotificationDialog(&mainDlg_, DialogInfoType::ERROR2, PopupDialogCfg().setTitle(_("Serious Error")).setDetailInstructions(errorMessage));
}
void StatusHandlerTemporaryPanel::reportWarning(const std::wstring& warningMessage, bool& warningActive)
{
- errorLog_.logMsg(warningMessage, TYPE_WARNING);
+ errorLog_.logMsg(warningMessage, MSG_TYPE_WARNING);
if (!warningActive) //if errors are ignored, then warnings should also
return;
if (!mainDlg_.compareStatus_->getOptionIgnoreErrors())
{
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
bool dontWarnAgain = false;
switch (showConfirmationDialog(&mainDlg_, DialogInfoType::WARNING,
@@ -212,7 +212,7 @@ void StatusHandlerTemporaryPanel::reportWarning(const std::wstring& warningMessa
}
-void StatusHandlerTemporaryPanel::forceUiRefresh()
+void StatusHandlerTemporaryPanel::forceUiRefreshNoThrow()
{
mainDlg_.compareStatus_->updateGui();
}
@@ -226,6 +226,7 @@ void StatusHandlerTemporaryPanel::OnAbortCompare(wxCommandEvent& event)
//########################################################################################################
StatusHandlerFloatingDialog::StatusHandlerFloatingDialog(wxFrame* parentDlg,
+ const std::chrono::system_clock::time_point& startTime,
size_t lastSyncsLogFileSizeMax,
bool ignoreErrors,
size_t automaticRetryCount,
@@ -234,23 +235,19 @@ StatusHandlerFloatingDialog::StatusHandlerFloatingDialog(wxFrame* parentDlg,
const Zstring& soundFileSyncComplete,
const Zstring& postSyncCommand,
PostSyncCondition postSyncCondition,
- bool& exitAfterSync) :
- progressDlg_(createProgressDialog(*this, [this] { this->onProgressDialogTerminate(); },
-*this,
-parentDlg,
-true, /*showProgress*/
-jobName,
-soundFileSyncComplete,
-ignoreErrors,
-PostSyncAction::SUMMARY)),
- lastSyncsLogFileSizeMax_(lastSyncsLogFileSizeMax),
- automaticRetryCount_(automaticRetryCount),
- automaticRetryDelay_(automaticRetryDelay),
- jobName_(jobName),
- startTime_(std::time(nullptr)),
- postSyncCommand_(postSyncCommand),
- postSyncCondition_(postSyncCondition),
- exitAfterSync_(exitAfterSync)
+ bool& exitAfterSync,
+ bool& autoCloseDialog) :
+ progressDlg_(createProgressDialog(*this, [this] { this->onProgressDialogTerminate(); }, *this, parentDlg, true /*showProgress*/, autoCloseDialog,
+jobName, soundFileSyncComplete, ignoreErrors, PostSyncAction2::NONE)),
+ lastSyncsLogFileSizeMax_(lastSyncsLogFileSizeMax),
+ automaticRetryCount_(automaticRetryCount),
+ automaticRetryDelay_(automaticRetryDelay),
+ jobName_(jobName),
+ startTime_(startTime),
+ postSyncCommand_(postSyncCommand),
+ postSyncCondition_(postSyncCondition),
+ exitAfterSync_(exitAfterSync),
+ autoCloseDialogOut_(autoCloseDialog)
{
assert(!exitAfterSync);
}
@@ -258,8 +255,8 @@ PostSyncAction::SUMMARY)),
StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
{
- const int totalErrors = errorLog_.getItemCount(TYPE_ERROR | TYPE_FATAL_ERROR); //evaluate before finalizing log
- const int totalWarnings = errorLog_.getItemCount(TYPE_WARNING);
+ const int totalErrors = errorLog_.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR); //evaluate before finalizing log
+ const int totalWarnings = errorLog_.getItemCount(MSG_TYPE_WARNING);
//finalize error log
SyncProgressDialog::SyncResult finalStatus = SyncProgressDialog::RESULT_FINISHED_WITH_SUCCESS;
@@ -267,20 +264,20 @@ StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
if (getAbortStatus())
{
finalStatus = SyncProgressDialog::RESULT_ABORTED;
- finalStatusMsg = _("Synchronization stopped");
- errorLog_.logMsg(finalStatusMsg, TYPE_ERROR);
+ finalStatusMsg = _("Stopped");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_ERROR);
}
else if (totalErrors > 0)
{
finalStatus = SyncProgressDialog::RESULT_FINISHED_WITH_ERROR;
- finalStatusMsg = _("Synchronization completed with errors");
- errorLog_.logMsg(finalStatusMsg, TYPE_ERROR);
+ finalStatusMsg = _("Completed with errors");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_ERROR);
}
else if (totalWarnings > 0)
{
finalStatus = SyncProgressDialog::RESULT_FINISHED_WITH_WARNINGS;
- finalStatusMsg = _("Synchronization completed with warnings");
- errorLog_.logMsg(finalStatusMsg, TYPE_WARNING); //give status code same warning priority as display category!
+ finalStatusMsg = _("Completed with warnings");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_WARNING); //give status code same warning priority as display category!
}
else
{
@@ -288,14 +285,16 @@ StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
getBytesTotal(PHASE_SYNCHRONIZING) == 0)
finalStatusMsg = _("Nothing to synchronize"); //even if "ignored conflicts" occurred!
else
- finalStatusMsg = _("Synchronization completed successfully");
- errorLog_.logMsg(finalStatusMsg, TYPE_INFO);
+ finalStatusMsg = _("Completed");
+ errorLog_.logMsg(finalStatusMsg, MSG_TYPE_INFO);
}
//post sync command
Zstring commandLine = [&]
{
- if (!getAbortStatus() || *getAbortStatus() != AbortTrigger::USER) //user cancelled => don't run post sync command!
+ if (getAbortStatus() && *getAbortStatus() == AbortTrigger::USER)
+ ; //user cancelled => don't run post sync command!
+ else
switch (postSyncCondition_)
{
case PostSyncCondition::COMPLETION:
@@ -316,7 +315,7 @@ StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
trim(commandLine);
if (!commandLine.empty())
- errorLog_.logMsg(replaceCpy(_("Executing command %x"), L"%x", fmtPath(commandLine)), TYPE_INFO);
+ errorLog_.logMsg(replaceCpy(_("Executing command %x"), L"%x", fmtPath(commandLine)), MSG_TYPE_INFO);
//----------------- write results into LastSyncs.log------------------------
const SummaryInfo summary =
@@ -324,72 +323,103 @@ StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
jobName_, finalStatusMsg,
getItemsCurrent(PHASE_SYNCHRONIZING), getBytesCurrent(PHASE_SYNCHRONIZING),
getItemsTotal (PHASE_SYNCHRONIZING), getBytesTotal (PHASE_SYNCHRONIZING),
- std::time(nullptr) - startTime_
+ std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - startTime_).count()
+ };
+ if (progressDlg_) progressDlg_->timerSetStatus(false /*active*/); //keep correct summary window stats considering count down timer, system sleep
+
+ //do NOT use tryReportingError()! saving log files should not be cancellable!
+ auto notifyStatusNoThrow = [&](const std::wstring& msg)
+ {
+ try { reportStatus(msg); /*throw X*/ }
+ catch (...) {}
};
try
{
- saveToLastSyncsLog(summary, errorLog_, lastSyncsLogFileSizeMax_, OnUpdateLogfileStatusNoThrow(*this, utfTo<std::wstring>(getLastSyncsLogfilePath()))); //throw FileError
+ saveToLastSyncsLog(summary, errorLog_, lastSyncsLogFileSizeMax_, notifyStatusNoThrow); //throw FileError, (X)
}
- catch (FileError&) { assert(false); }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
//execute post sync command *after* writing log files, so that user can refer to the log via the command!
if (!commandLine.empty())
try
{
- //use EXEC_TYPE_ASYNC until there is reason not to: https://www.freefilesync.org/forum/viewtopic.php?t=31
- tryReportingError([&] { shellExecute(expandMacros(commandLine), EXEC_TYPE_ASYNC); /*throw FileError*/ }, *this); //throw X
+ //use ExecutionType::ASYNC until there is reason not to: https://www.freefilesync.org/forum/viewtopic.php?t=31
+ shellExecute(expandMacros(commandLine), ExecutionType::ASYNC); //throw FileError
}
- catch (...) {}
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
if (progressDlg_)
{
+ auto mayRunAfterCountDown = [&](const std::wstring& operationName)
+ {
+ auto notifyStatusThrowOnCancel = [&](const std::wstring& msg)
+ {
+ try { reportStatus(msg); /*throw X*/ }
+ catch (...)
+ {
+ if (getAbortStatus() && *getAbortStatus() == AbortTrigger::USER)
+ throw;
+ }
+ };
+
+ if (progressDlg_->getWindowIfVisible())
+ try
+ {
+ delayAndCountDown(operationName, 5 /*delayInSec*/, notifyStatusThrowOnCancel); //throw X
+ }
+ catch (...) { return false; }
+
+ return true;
+ };
+
//post sync action
- bool showSummary = true;
- bool triggerSleep = false;
- if (!getAbortStatus() || *getAbortStatus() != AbortTrigger::USER) //user cancelled => don't run post sync action!
+ bool autoClose = false;
+ if (getAbortStatus() && *getAbortStatus() == AbortTrigger::USER)
+ ; //user cancelled => don't run post sync command!
+ else
switch (progressDlg_->getOptionPostSyncAction())
{
- case PostSyncAction::SUMMARY:
+ case PostSyncAction2::NONE:
+ autoClose = progressDlg_->getOptionAutoCloseDialog();
break;
- case PostSyncAction::EXIT:
- showSummary = false;
- exitAfterSync_ = true; //program shutdown must be handled by calling context!
+ case PostSyncAction2::EXIT:
+ autoClose = exitAfterSync_ = true; //program exit must be handled by calling context!
break;
- case PostSyncAction::SLEEP:
- triggerSleep = true;
+ case PostSyncAction2::SLEEP:
+ if (mayRunAfterCountDown(_("System: Sleep")))
+ try
+ {
+ suspendSystem(); //throw FileError
+ autoClose = progressDlg_->getOptionAutoCloseDialog();
+ }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
break;
- case PostSyncAction::SHUTDOWN:
- showSummary = false;
- exitAfterSync_ = true;
- try
- {
- tryReportingError([&] { shutdownSystem(); /*throw FileError*/ }, *this); //throw X
- }
- catch (...) {}
+ case PostSyncAction2::SHUTDOWN:
+ if (mayRunAfterCountDown(_("System: Shut down")))
+ try
+ {
+ shutdownSystem(); //throw FileError
+ autoClose = exitAfterSync_ = true;
+ }
+ catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
break;
}
//close progress dialog
- if (showSummary)
- progressDlg_->showSummary(finalStatus, errorLog_);
+ if (autoClose)
+ progressDlg_->closeDirectly(!exitAfterSync_ /*restoreParentFrame*/);
else
- progressDlg_->closeDirectly(false /*restoreParentFrame*/);
-
- if (triggerSleep) //sleep *after* showing results dialog (consider total time!)
- try
- {
- tryReportingError([&] { suspendSystem(); /*throw FileError*/ }, *this); //throw X
- }
- catch (...) {}
+ progressDlg_->showSummary(finalStatus, errorLog_);
//wait until progress dialog notified shutdown via onProgressDialogTerminate()
//-> required since it has our "this" pointer captured in lambda "notifyWindowTerminate"!
//-> nicely manages dialog lifetime
- while (progressDlg_)
+ for (;;)
{
wxTheApp->Yield(); //*first* refresh GUI (removing flicker) before sleeping!
- std::this_thread::sleep_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS));
+ if (!progressDlg_) break;
+ std::this_thread::sleep_for(UI_UPDATE_INTERVAL);
}
}
}
@@ -402,7 +432,7 @@ void StatusHandlerFloatingDialog::initNewPhase(int itemsTotal, int64_t bytesTota
if (progressDlg_)
progressDlg_->initNewPhase(); //call after "StatusHandler::initNewPhase"
- forceUiRefresh(); //throw ?; OS X needs a full yield to update GUI and get rid of "dummy" texts
+ forceUiRefresh(); //throw X; OS X needs a full yield to update GUI and get rid of "dummy" texts
}
@@ -417,7 +447,7 @@ void StatusHandlerFloatingDialog::updateProcessedData(int itemsDelta, int64_t by
void StatusHandlerFloatingDialog::reportInfo(const std::wstring& text)
{
- errorLog_.logMsg(text, TYPE_INFO); //log first!
+ errorLog_.logMsg(text, MSG_TYPE_INFO); //log first!
StatusHandler::reportInfo(text); //throw X
}
@@ -429,26 +459,18 @@ ProcessCallback::Response StatusHandlerFloatingDialog::reportError(const std::ws
//auto-retry
if (retryNumber < automaticRetryCount_)
{
- errorLog_.logMsg(errorMessage + L"\n-> " +
- _P("Automatic retry in 1 second...", "Automatic retry in %x seconds...", automaticRetryDelay_), TYPE_INFO);
- //delay
- const int iterations = static_cast<int>(1000 * automaticRetryDelay_ / UI_UPDATE_INTERVAL_MS); //always round down: don't allow for negative remaining time below
- for (int i = 0; i < iterations; ++i)
- {
- reportStatus(_("Error") + L": " + _P("Automatic retry in 1 second...", "Automatic retry in %x seconds...",
- (1000 * automaticRetryDelay_ - i * UI_UPDATE_INTERVAL_MS + 999) / 1000)); //integer round up
- std::this_thread::sleep_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS));
- }
+ errorLog_.logMsg(errorMessage + L"\n-> " + _("Automatic retry"), MSG_TYPE_INFO);
+ delayAndCountDown(_("Automatic retry"), automaticRetryDelay_, [&](const std::wstring& msg) { this->reportStatus(_("Error") + L": " + msg); });
return ProcessCallback::RETRY;
}
//always, except for "retry":
- auto guardWriteLog = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { errorLog_.logMsg(errorMessage, TYPE_ERROR); });
+ auto guardWriteLog = zen::makeGuard<ScopeGuardRunMode::ON_EXIT>([&] { errorLog_.logMsg(errorMessage, MSG_TYPE_ERROR); });
if (!progressDlg_->getOptionIgnoreErrors())
{
PauseTimers dummy(*progressDlg_);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::ERROR2, PopupDialogCfg().
setDetailInstructions(errorMessage),
@@ -463,7 +485,7 @@ ProcessCallback::Response StatusHandlerFloatingDialog::reportError(const std::ws
case ConfirmationButton3::DECLINE: //retry
guardWriteLog.dismiss();
- errorLog_.logMsg(errorMessage + L"\n-> " + _("Retrying operation..."), TYPE_INFO); //explain why there are duplicate "doing operation X" info messages in the log!
+ errorLog_.logMsg(errorMessage + L"\n-> " + _("Retrying operation..."), MSG_TYPE_INFO); //explain why there are duplicate "doing operation X" info messages in the log!
return ProcessCallback::RETRY;
case ConfirmationButton3::CANCEL:
@@ -483,12 +505,12 @@ void StatusHandlerFloatingDialog::reportFatalError(const std::wstring& errorMess
{
if (!progressDlg_) abortProcessNow();
- errorLog_.logMsg(errorMessage, TYPE_FATAL_ERROR);
+ errorLog_.logMsg(errorMessage, MSG_TYPE_FATAL_ERROR);
if (!progressDlg_->getOptionIgnoreErrors())
{
PauseTimers dummy(*progressDlg_);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::ERROR2,
PopupDialogCfg().setTitle(_("Serious Error")).
@@ -514,7 +536,7 @@ void StatusHandlerFloatingDialog::reportWarning(const std::wstring& warningMessa
{
if (!progressDlg_) abortProcessNow();
- errorLog_.logMsg(warningMessage, TYPE_WARNING);
+ errorLog_.logMsg(warningMessage, MSG_TYPE_WARNING);
if (!warningActive)
return;
@@ -522,7 +544,7 @@ void StatusHandlerFloatingDialog::reportWarning(const std::wstring& warningMessa
if (!progressDlg_->getOptionIgnoreErrors())
{
PauseTimers dummy(*progressDlg_);
- forceUiRefresh();
+ forceUiRefreshNoThrow(); //noexcept! => don't throw here when error occurs during clean up!
bool dontWarnAgain = false;
switch (showConfirmationDialog(progressDlg_->getWindowIfVisible(), DialogInfoType::WARNING,
@@ -542,7 +564,7 @@ void StatusHandlerFloatingDialog::reportWarning(const std::wstring& warningMessa
}
-void StatusHandlerFloatingDialog::forceUiRefresh()
+void StatusHandlerFloatingDialog::forceUiRefreshNoThrow()
{
if (progressDlg_)
progressDlg_->updateGui();
@@ -551,5 +573,9 @@ void StatusHandlerFloatingDialog::forceUiRefresh()
void StatusHandlerFloatingDialog::onProgressDialogTerminate()
{
+ //output parameters owned by SyncProgressDialog
+ if (progressDlg_)
+ autoCloseDialogOut_ = progressDlg_->getOptionAutoCloseDialog();
+
progressDlg_ = nullptr;
}
diff --git a/FreeFileSync/Source/ui/gui_status_handler.h b/FreeFileSync/Source/ui/gui_status_handler.h
index e72ae864..c9d9eef3 100755
--- a/FreeFileSync/Source/ui/gui_status_handler.h
+++ b/FreeFileSync/Source/ui/gui_status_handler.h
@@ -12,13 +12,14 @@
#include "progress_indicator.h"
#include "main_dlg.h"
#include "../lib/status_handler.h"
-//#include "../lib/process_xml.h"
+namespace fff
+{
//classes handling sync and compare errors as well as status feedback
//StatusHandlerTemporaryPanel(CompareProgressDialog) will internally process Window messages! disable GUI controls to avoid unexpected callbacks!
-class StatusHandlerTemporaryPanel : private wxEvtHandler, public zen::StatusHandler //throw AbortProcess
+class StatusHandlerTemporaryPanel : private wxEvtHandler, public StatusHandler //throw AbortProcess
{
public:
StatusHandlerTemporaryPanel(MainDialog& dlg);
@@ -31,7 +32,7 @@ public:
void reportFatalError(const std::wstring& errorMessage) override;
void reportWarning (const std::wstring& warningMessage, bool& warningActive) override;
- void forceUiRefresh() override;
+ void forceUiRefreshNoThrow() override;
zen::ErrorLog getErrorLog() const { return errorLog_; }
@@ -45,10 +46,11 @@ private:
//StatusHandlerFloatingDialog(SyncProgressDialog) will internally process Window messages! disable GUI controls to avoid unexpected callbacks!
-class StatusHandlerFloatingDialog : public zen::StatusHandler //throw AbortProcess
+class StatusHandlerFloatingDialog : public StatusHandler //throw AbortProcess
{
public:
StatusHandlerFloatingDialog(wxFrame* parentDlg,
+ const std::chrono::system_clock::time_point& startTime,
size_t lastSyncsLogFileSizeMax,
bool ignoreErrors,
size_t automaticRetryCount,
@@ -56,8 +58,9 @@ public:
const std::wstring& jobName,
const Zstring& soundFileSyncComplete,
const Zstring& postSyncCommand,
- zen::PostSyncCondition postSyncCondition,
- bool& exitAfterSync);
+ PostSyncCondition postSyncCondition,
+ bool& exitAfterSync,
+ bool& autoCloseDialog);
~StatusHandlerFloatingDialog();
void initNewPhase (int itemsTotal, int64_t bytesTotal, Phase phaseID) override;
@@ -68,7 +71,7 @@ public:
void reportFatalError(const std::wstring& errorMessage ) override;
void reportWarning (const std::wstring& warningMessage, bool& warningActive) override;
- void forceUiRefresh() override;
+ void forceUiRefreshNoThrow() override;
private:
void onProgressDialogTerminate();
@@ -79,11 +82,12 @@ private:
const size_t automaticRetryCount_;
const size_t automaticRetryDelay_;
const std::wstring jobName_;
- const time_t startTime_; //don't use wxStopWatch: may overflow after a few days due to ::QueryPerformanceCounter()
+ const std::chrono::system_clock::time_point startTime_; //don't use wxStopWatch: may overflow after a few days due to ::QueryPerformanceCounter()
const Zstring postSyncCommand_;
- const zen::PostSyncCondition postSyncCondition_;
+ const PostSyncCondition postSyncCondition_;
bool& exitAfterSync_;
+ bool& autoCloseDialogOut_; //owned by SyncProgressDialog
};
-
+}
#endif //GUI_STATUS_HANDLER_H_0183247018545
diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp
index 41ccf802..b20b4b08 100755
--- a/FreeFileSync/Source/ui/main_dlg.cpp
+++ b/FreeFileSync/Source/ui/main_dlg.cpp
@@ -49,17 +49,18 @@
using namespace zen;
-using namespace std::rel_ops;
+using namespace fff;
+
namespace
{
const size_t EXT_APP_MASS_INVOKE_THRESHOLD = 10; //more than this is likely a user mistake (Explorer uses limit of 15)
+const int TOP_BUTTON_OPTIMAL_WIDTH = 180;
-IconBuffer::IconSize convert(xmlAccess::FileIconSize isize)
+IconBuffer::IconSize convert(FileIconSize isize)
{
- using namespace xmlAccess;
switch (isize)
{
case ICON_SIZE_SMALL:
@@ -85,7 +86,7 @@ bool acceptDialogFileDrop(const std::vector<Zstring>& shellItemPaths)
}
-class FolderSelectorImpl : public FolderSelector
+class fff::FolderSelectorImpl : public FolderSelector
{
public:
FolderSelectorImpl(MainDialog& mainDlg,
@@ -132,7 +133,7 @@ private:
*/
template <class GuiPanel>
-class FolderPairCallback : public FolderPairPanelBasic<GuiPanel> //implements callback functionality to MainDialog as imposed by FolderPairPanelBasic
+class fff::FolderPairCallback : public FolderPairPanelBasic<GuiPanel> //implements callback functionality to MainDialog as imposed by FolderPairPanelBasic
{
public:
FolderPairCallback(GuiPanel& basicPanel, MainDialog& mainDialog) :
@@ -152,7 +153,7 @@ private:
};
-class FolderPairPanel :
+class fff::FolderPairPanel :
public FolderPairPanelGenerated, //FolderPairPanel "owns" FolderPairPanelGenerated!
public FolderPairCallback<FolderPairPanelGenerated>
{
@@ -191,7 +192,7 @@ private:
};
-class FolderPairFirst : public FolderPairCallback<MainDialogGenerated>
+class fff::FolderPairFirst : public FolderPairCallback<MainDialogGenerated>
{
public:
FolderPairFirst(MainDialog& mainDialog) :
@@ -247,9 +248,6 @@ private:
namespace
{
-const int TOP_BUTTON_OPTIMAL_WIDTH = 180;
-
-
void updateTopButton(wxBitmapButton& btn, const wxBitmap& bmp, const wxString& variantName, bool makeGrey)
{
wxImage labelImage = createImageFromText(btn.GetLabel(), btn.GetFont(), wxSystemSettings::GetColour(makeGrey ? wxSYS_COLOUR_GRAYTEXT : wxSYS_COLOUR_BTNTEXT));
@@ -274,10 +272,8 @@ void updateTopButton(wxBitmapButton& btn, const wxBitmap& bmp, const wxString& v
//##################################################################################################################################
-xmlAccess::XmlGlobalSettings tryLoadGlobalConfig(const Zstring& globalConfigFilePath) //blocks on GUI on errors!
+XmlGlobalSettings tryLoadGlobalConfig(const Zstring& globalConfigFilePath) //blocks on GUI on errors!
{
- using namespace xmlAccess;
-
XmlGlobalSettings globalCfg;
try
{
@@ -298,8 +294,6 @@ xmlAccess::XmlGlobalSettings tryLoadGlobalConfig(const Zstring& globalConfigFile
void MainDialog::create(const Zstring& globalConfigFilePath)
{
- using namespace xmlAccess;
-
const XmlGlobalSettings globalSettings = tryLoadGlobalConfig(globalConfigFilePath);
std::vector<Zstring> cfgFilePaths = globalSettings.gui.mainDlg.lastUsedConfigFiles;
@@ -332,18 +326,16 @@ void MainDialog::create(const Zstring& globalConfigFilePath)
//else: not-existing/access error? => user may click on <Last Session> later
}
- XmlGuiConfig guiCfg; //structure to receive gui settings with default values
+ XmlGuiConfig guiCfg; //contains default values
- if (cfgFilePaths.empty())
- {
- //add default exclusion filter: this is only ever relevant when creating new configurations!
- //a default XmlGuiConfig does not need these user-specific exclusions!
- Zstring& excludeFilter = guiCfg.mainCfg.globalFilter.excludeFilter;
- if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
- excludeFilter += Zstr("\n");
- excludeFilter += globalSettings.gui.defaultExclusionFilter;
- }
- else
+ //add default exclusion filter: this is only ever relevant when creating new configurations!
+ //a default XmlGuiConfig does not need these user-specific exclusions!
+ Zstring& excludeFilter = guiCfg.mainCfg.globalFilter.excludeFilter;
+ if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
+ excludeFilter += Zstr("\n");
+ excludeFilter += globalSettings.gui.defaultExclusionFilter;
+
+ if (!cfgFilePaths.empty())
try
{
std::wstring warningMsg;
@@ -365,12 +357,12 @@ void MainDialog::create(const Zstring& globalConfigFilePath)
void MainDialog::create(const Zstring& globalConfigFilePath,
- const xmlAccess::XmlGlobalSettings* globalSettings,
- const xmlAccess::XmlGuiConfig& guiCfg,
+ const XmlGlobalSettings* globalSettings,
+ const XmlGuiConfig& guiCfg,
const std::vector<Zstring>& referenceFiles,
bool startComparison)
{
- const xmlAccess::XmlGlobalSettings globSett = globalSettings ? *globalSettings : tryLoadGlobalConfig(globalConfigFilePath);
+ const XmlGlobalSettings globSett = globalSettings ? *globalSettings : tryLoadGlobalConfig(globalConfigFilePath);
try
{
@@ -389,9 +381,9 @@ void MainDialog::create(const Zstring& globalConfigFilePath,
MainDialog::MainDialog(const Zstring& globalConfigFilePath,
- const xmlAccess::XmlGuiConfig& guiCfg,
+ const XmlGuiConfig& guiCfg,
const std::vector<Zstring>& referenceFiles,
- const xmlAccess::XmlGlobalSettings& globalSettings,
+ const XmlGlobalSettings& globalSettings,
bool startComparison) :
MainDialogGenerated(nullptr),
globalConfigFilePath_(globalConfigFilePath),
@@ -637,7 +629,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
}
//notify about (logical) application main window => program won't quit, but stay on this dialog
- zen::setMainWindow(this);
+ setMainWindow(this);
//init handling of first folder pair
firstFolderPair_ = std::make_unique<FolderPairFirst>(*this);
@@ -715,7 +707,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
//some convenience: if FFS is started with a *.ffs_gui file as commandline parameter AND all directories contained exist, comparison shall be started right away
if (startComparison)
{
- const zen::MainConfiguration currMainCfg = getConfig().mainCfg;
+ const MainConfiguration currMainCfg = getConfig().mainCfg;
//------------------------------------------------------------------------------------------
//harmonize checks with comparison.cpp:: checkForIncompleteInput()
@@ -779,8 +771,6 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
MainDialog::~MainDialog()
{
- using namespace xmlAccess;
-
Opt<FileError> firstError;
try //save "GlobalSettings.xml"
{
@@ -814,8 +804,6 @@ MainDialog::~MainDialog()
void MainDialog::onQueryEndSession()
{
- using namespace xmlAccess;
-
//we try our best to do something useful in this extreme situation - no reason to notify or even log errors here!
try { writeConfig(getGlobalCfgBeforeExit(), globalConfigFilePath_); }
catch (const FileError&) {}
@@ -853,7 +841,7 @@ void MainDialog::OnClose(wxCloseEvent& event)
}
-void MainDialog::setGlobalCfgOnInit(const xmlAccess::XmlGlobalSettings& globalSettings)
+void MainDialog::setGlobalCfgOnInit(const XmlGlobalSettings& globalSettings)
{
globalCfg_ = globalSettings;
@@ -914,28 +902,27 @@ void MainDialog::setGlobalCfgOnInit(const xmlAccess::XmlGlobalSettings& globalSe
//load list of configuration files
std::vector<Zstring> cfgFilePaths;
std::vector<std::pair<Zstring, time_t>> lastSyncTimes;
- //list is stored with last used files first in XML, however m_gridCfgHistory needs them last!!!
+ //list is stored with last used files first in XML, however m_gridCfgHistory expects them last!!!
std::for_each(globalSettings.gui.mainDlg.cfgFileHistory.crbegin(),
globalSettings.gui.mainDlg.cfgFileHistory.crend(),
- [&](const xmlAccess::ConfigFileItem& item)
+ [&](const ConfigFileItem& item)
{
cfgFilePaths.push_back(item.filePath);
lastSyncTimes.emplace_back(item.filePath, item.lastSyncTime);
});
- warn_static("finish")
cfgFilePaths.push_back(lastRunConfigPath_); //make sure <Last session> is always part of history list (if existing)
+
cfggrid::getDataView(*m_gridCfgHistory).addCfgFiles(cfgFilePaths);
cfggrid::getDataView(*m_gridCfgHistory).setLastSyncTime(lastSyncTimes);
m_gridCfgHistory->Refresh();
+ //globalSettings.gui.mainDlg.cfgGridTopRowPos => defer evaluation until later within MainDialog constructor
m_gridCfgHistory->setColumnConfig(convertColAttributes(globalSettings.gui.mainDlg.cfgGridColumnAttribs, getCfgGridDefaultColAttribs()));
cfggrid::getDataView(*m_gridCfgHistory).setSortDirection(globalSettings.gui.mainDlg.cfgGridLastSortColumn, globalSettings.gui.mainDlg.cfgGridLastSortAscending);
cfggrid::setSyncOverdueDays(*m_gridCfgHistory, globalSettings.gui.mainDlg.cfgGridSyncOverdueDays);
//m_gridCfgHistory->Refresh(); <- implicit in last call
cfgHistoryRemoveObsolete(cfgFilePaths); //remove non-existent items (we need this only on startup)
-
- //globalSettings.gui.cfgFileHistFirstItemPos => defer evaluation until later within MainDialog constructor
//--------------------------------------------------------------------------------
//load list of last used folders
@@ -975,11 +962,11 @@ void MainDialog::setGlobalCfgOnInit(const xmlAccess::XmlGlobalSettings& globalSe
}
-xmlAccess::XmlGlobalSettings MainDialog::getGlobalCfgBeforeExit()
+XmlGlobalSettings MainDialog::getGlobalCfgBeforeExit()
{
Freeze(); //no need to Thaw() again!!
- xmlAccess::XmlGlobalSettings globalSettings = globalCfg_;
+ XmlGlobalSettings globalSettings = globalCfg_;
globalSettings.programLanguage = getLanguage();
@@ -996,18 +983,16 @@ xmlAccess::XmlGlobalSettings MainDialog::getGlobalCfgBeforeExit()
//--------------------------------------------------------------------------------
//write list of configuration files
- std::map<int, xmlAccess::ConfigFileItem> cfgItemsSorted; //(last use index/cfg file path)
+ std::map<int, ConfigFileItem, std::greater<>> cfgItemsSorted; //sort by last use; put most recent items *first* (looks better in XML than reverted)
for (size_t i = 0; i < m_gridCfgHistory->getRowCount(); ++i)
if (const ConfigView::Details* cfg = cfggrid::getDataView(*m_gridCfgHistory).getItem(i))
- cfgItemsSorted.emplace(cfg->lastUseIndex, xmlAccess::ConfigFileItem{ cfg->filePath, cfg->lastSyncTime });
+ cfgItemsSorted.emplace(cfg->lastUseIndex, ConfigFileItem{ cfg->filePath, cfg->lastSyncTime });
else
assert(false);
- //sort by last use; put most recent items *first* (looks better in XML than reverted)
- std::vector<xmlAccess::ConfigFileItem> cfgHistory;
- std::for_each(cfgItemsSorted.crbegin(),
- cfgItemsSorted.crend(),
- [&](const auto& item) { cfgHistory.emplace_back(item.second); });
+ std::vector<ConfigFileItem> cfgHistory;
+ for (const auto& item : cfgItemsSorted)
+ cfgHistory.emplace_back(item.second);
if (cfgHistory.size() > globalSettings.gui.mainDlg.cfgHistItemsMax) //erase oldest elements
cfgHistory.resize(globalSettings.gui.mainDlg.cfgHistItemsMax);
@@ -1066,7 +1051,7 @@ void MainDialog::setSyncDirManually(const std::vector<FileSystemObject*>& select
for (FileSystemObject* fsObj : selection)
{
setSyncDirectionRec(direction, *fsObj); //set new direction (recursively)
- zen::setActiveStatus(true, *fsObj); //works recursively for directories
+ setActiveStatus(true, *fsObj); //works recursively for directories
}
updateGui();
}
@@ -1081,7 +1066,7 @@ void MainDialog::setFilterManually(const std::vector<FileSystemObject*>& selecti
if (!selection.empty())
{
for (FileSystemObject* fsObj : selection)
- zen::setActiveStatus(setIncluded, *fsObj); //works recursively for directories
+ setActiveStatus(setIncluded, *fsObj); //works recursively for directories
updateGuiDelayedIf(!m_bpButtonShowExcluded->isActive()); //show update GUI before removing rows
}
@@ -1188,8 +1173,8 @@ std::vector<FileSystemObject*> MainDialog::getTreeSelection() const
}
-void MainDialog::copyToAlternateFolder(const std::vector<zen::FileSystemObject*>& selectionLeft,
- const std::vector<zen::FileSystemObject*>& selectionRight)
+void MainDialog::copyToAlternateFolder(const std::vector<FileSystemObject*>& selectionLeft,
+ const std::vector<FileSystemObject*>& selectionRight)
{
std::vector<const FileSystemObject*> rowsLeftTmp;
std::vector<const FileSystemObject*> rowsRightTmp;
@@ -1201,13 +1186,13 @@ void MainDialog::copyToAlternateFolder(const std::vector<zen::FileSystemObject*>
FocusPreserver fp;
- if (zen::showCopyToDialog(this,
- rowsLeftTmp, rowsRightTmp,
- globalCfg_.gui.mainDlg.copyToCfg.lastUsedPath,
- globalCfg_.gui.mainDlg.copyToCfg.folderHistory,
- globalCfg_.gui.mainDlg.copyToCfg.historySizeMax,
- globalCfg_.gui.mainDlg.copyToCfg.keepRelPaths,
- globalCfg_.gui.mainDlg.copyToCfg.overwriteIfExists) != ReturnSmallDlg::BUTTON_OKAY)
+ if (showCopyToDialog(this,
+ rowsLeftTmp, rowsRightTmp,
+ globalCfg_.gui.mainDlg.copyToCfg.lastUsedPath,
+ globalCfg_.gui.mainDlg.copyToCfg.folderHistory,
+ globalCfg_.gui.mainDlg.copyToCfg.historySizeMax,
+ globalCfg_.gui.mainDlg.copyToCfg.keepRelPaths,
+ globalCfg_.gui.mainDlg.copyToCfg.overwriteIfExists) != ReturnSmallDlg::BUTTON_OKAY)
return;
disableAllElements(true); //StatusHandlerTemporaryPanel will internally process Window messages, so avoid unexpected callbacks!
@@ -1218,11 +1203,11 @@ void MainDialog::copyToAlternateFolder(const std::vector<zen::FileSystemObject*>
{
StatusHandlerTemporaryPanel statusHandler(*this); //handle status display and error messages
- zen::copyToAlternateFolder(rowsLeftTmp, rowsRightTmp,
+ fff::copyToAlternateFolder(rowsLeftTmp, rowsRightTmp,
globalCfg_.gui.mainDlg.copyToCfg.lastUsedPath,
globalCfg_.gui.mainDlg.copyToCfg.keepRelPaths,
globalCfg_.gui.mainDlg.copyToCfg.overwriteIfExists,
- globalCfg_.optDialogs,
+ globalCfg_.warnDlgs,
statusHandler);
//"clearSelection" not needed/desired
}
@@ -1245,8 +1230,8 @@ void MainDialog::deleteSelectedFiles(const std::vector<FileSystemObject*>& selec
FocusPreserver fp;
//sigh: do senseless vector<FileSystemObject*> -> vector<const FileSystemObject*> conversion:
- if (zen::showDeleteDialog(this, { rowsLeftTmp.begin(), rowsLeftTmp.end() }, { rowsRightTmp.begin(), rowsRightTmp.end() },
- moveToRecycler) != ReturnSmallDlg::BUTTON_OKAY)
+ if (showDeleteDialog(this, { rowsLeftTmp.begin(), rowsLeftTmp.end() }, { rowsRightTmp.begin(), rowsRightTmp.end() },
+ moveToRecycler) != ReturnSmallDlg::BUTTON_OKAY)
return;
disableAllElements(true); //StatusHandlerTemporaryPanel will internally process Window messages, so avoid unexpected callbacks!
@@ -1258,12 +1243,12 @@ void MainDialog::deleteSelectedFiles(const std::vector<FileSystemObject*>& selec
{
StatusHandlerTemporaryPanel statusHandler(*this); //handle status display and error messages
- zen::deleteFromGridAndHD(rowsLeftTmp, rowsRightTmp,
- folderCmp_,
- extractDirectionCfg(getConfig().mainCfg),
- moveToRecycler,
- globalCfg_.optDialogs.warnRecyclerMissing,
- statusHandler);
+ deleteFromGridAndHD(rowsLeftTmp, rowsRightTmp,
+ folderCmp_,
+ extractDirectionCfg(getConfig().mainCfg),
+ moveToRecycler,
+ globalCfg_.warnDlgs.warnRecyclerMissing,
+ statusHandler);
m_gridMainL->clearSelection(ALLOW_GRID_EVENT);
m_gridMainC->clearSelection(ALLOW_GRID_EVENT);
@@ -1369,7 +1354,7 @@ void invokeCommandLine(const Zstring& commandLinePhrase, //throw FileError
replace(command, Zstr("%local_path%"), localPath);
replace(command, Zstr("%local_path2%"), localPath2);
- shellExecute(command, selection.size() > EXT_APP_MASS_INVOKE_THRESHOLD ? EXEC_TYPE_SYNC : EXEC_TYPE_ASYNC); //throw FileError
+ shellExecute(command, selection.size() > EXT_APP_MASS_INVOKE_THRESHOLD ? ExecutionType::SYNC : ExecutionType::ASYNC); //throw FileError
}
}
}
@@ -1379,8 +1364,8 @@ void MainDialog::openExternalApplication(const Zstring& commandLinePhrase, bool
const std::vector<FileSystemObject*>& selectionLeft,
const std::vector<FileSystemObject*>& selectionRight)
{
- const xmlAccess::XmlGlobalSettings::Gui defaultCfg;
- const bool openFileBrowserRequested = !defaultCfg.externelApplications.empty() && defaultCfg.externelApplications[0].second == commandLinePhrase;
+ const XmlGlobalSettings::Gui defaultCfg;
+ const bool openFileBrowserRequested = !defaultCfg.externalApps.empty() && defaultCfg.externalApps[0].cmdLine == commandLinePhrase;
//support fallback instead of an error in this special case
if (openFileBrowserRequested)
@@ -1398,7 +1383,7 @@ void MainDialog::openExternalApplication(const Zstring& commandLinePhrase, bool
{
try
{
- shellExecute("xdg-open \"" + utfTo<Zstring>(AFS::getDisplayPath(folderPath)) + "\"", EXEC_TYPE_ASYNC); //
+ shellExecute("xdg-open \"" + utfTo<Zstring>(AFS::getDisplayPath(folderPath)) + "\"", ExecutionType::ASYNC); //
}
catch (const FileError& e) { showNotificationDialog(this, DialogInfoType::ERROR2, PopupDialogCfg().setDetailInstructions(e.toString())); }
};
@@ -1423,7 +1408,7 @@ void MainDialog::openExternalApplication(const Zstring& commandLinePhrase, bool
//regular command evaluation:
const size_t invokeCount = selectionLeft.size() + selectionRight.size();
if (invokeCount > EXT_APP_MASS_INVOKE_THRESHOLD)
- if (globalCfg_.optDialogs.confirmExternalCommandMassInvoke)
+ if (globalCfg_.confirmDlgs.confirmExternalCommandMassInvoke)
{
bool dontAskAgain = false;
switch (showConfirmationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().
@@ -1435,7 +1420,7 @@ void MainDialog::openExternalApplication(const Zstring& commandLinePhrase, bool
_("&Execute")))
{
case ConfirmationButton::ACCEPT:
- globalCfg_.optDialogs.confirmExternalCommandMassInvoke = !dontAskAgain;
+ globalCfg_.confirmDlgs.confirmExternalCommandMassInvoke = !dontAskAgain;
break;
case ConfirmationButton::CANCEL:
return;
@@ -1875,9 +1860,9 @@ void MainDialog::onGridButtonEvent(wxKeyEvent& event, Grid& grid, bool leftSide)
return static_cast<size_t>(-1);
}();
- if (extAppPos < globalCfg_.gui.externelApplications.size())
+ if (extAppPos < globalCfg_.gui.externalApps.size())
{
- openExternalApplication(globalCfg_.gui.externelApplications[extAppPos].second, leftSide, selectionLeft, selectionRight);
+ openExternalApplication(globalCfg_.gui.externalApps[extAppPos].cmdLine, leftSide, selectionLeft, selectionRight);
return;
}
@@ -2064,7 +2049,7 @@ void MainDialog::onTreeGridContext(GridClickEvent& event)
//----------------------------------------------------------------------------------------------------
if (!selection.empty())
- //std::any_of(selection.begin(), selection.end(), [](const FileSystemObject* fsObj){ return fsObj->getSyncOperation() != SO_EQUAL; })) -> doesn't consider directories
+ //std::any_of(selection.begin(), selection.end(), [](const FileSystemObject* fsObj) { return fsObj->getSyncOperation() != SO_EQUAL; })) -> doesn't consider directories
{
auto getImage = [&](SyncDirection dir, SyncOperation soDefault)
{
@@ -2156,13 +2141,13 @@ void MainDialog::onMainGridContextC(GridClickEvent& event)
menu.addItem(_("Include all"), [&]
{
- zen::setActiveStatus(true, folderCmp_);
+ setActiveStatus(true, folderCmp_);
updateGui();
}, nullptr, filegrid::getDataView(*m_gridMainC).rowsTotal() > 0);
menu.addItem(_("Exclude all"), [&]
{
- zen::setActiveStatus(false, folderCmp_);
+ setActiveStatus(false, folderCmp_);
updateGuiDelayedIf(!m_bpButtonShowExcluded->isActive()); //show update GUI before removing rows
}, nullptr, filegrid::getDataView(*m_gridMainC).rowsTotal() > 0);
@@ -2271,22 +2256,22 @@ void MainDialog::onMainGridContextRim(bool leftSide)
//----------------------------------------------------------------------------------------------------
- if (!globalCfg_.gui.externelApplications.empty())
+ if (!globalCfg_.gui.externalApps.empty())
{
menu.addSeparator();
- for (auto it = globalCfg_.gui.externelApplications.begin();
- it != globalCfg_.gui.externelApplications.end();
+ for (auto it = globalCfg_.gui.externalApps.begin();
+ it != globalCfg_.gui.externalApps.end();
++it)
{
//translate default external apps on the fly: 1. "open in explorer" 2. "start directly"
- wxString description = zen::translate(it->first);
+ wxString description = translate(it->description);
if (description.empty())
description = L" "; //wxWidgets doesn't like empty items
- auto openApp = [this, command = it->second, leftSide, &selectionLeft, &selectionRight] { openExternalApplication(command, leftSide, selectionLeft, selectionRight); };
+ auto openApp = [this, command = it->cmdLine, leftSide, &selectionLeft, &selectionRight] { openExternalApplication(command, leftSide, selectionLeft, selectionRight); };
- const size_t pos = it - globalCfg_.gui.externelApplications.begin();
+ const size_t pos = it - globalCfg_.gui.externalApps.begin();
if (pos == 0)
description += L"\tEnter, D-Click";
@@ -2489,7 +2474,7 @@ void MainDialog::onGridLabelContextRim(Grid& grid, ColumnTypeRim type, bool left
//----------------------------------------------------------------------------------------------
menu.addSeparator();
- auto setIconSize = [&](xmlAccess::FileIconSize sz, bool showIcons)
+ auto setIconSize = [&](FileIconSize sz, bool showIcons)
{
globalCfg_.gui.mainDlg.iconSize = sz;
globalCfg_.gui.mainDlg.showIcons = showIcons;
@@ -2498,7 +2483,7 @@ void MainDialog::onGridLabelContextRim(Grid& grid, ColumnTypeRim type, bool left
auto setDefault = [&]
{
- const xmlAccess::XmlGlobalSettings defaultCfg;
+ const XmlGlobalSettings defaultCfg;
grid.setColumnConfig(convertColAttributes(left ? defaultCfg.gui.mainDlg.columnAttribLeft : defaultCfg.gui.mainDlg.columnAttribRight, defaultCfg.gui.mainDlg.columnAttribLeft));
@@ -2511,13 +2496,13 @@ void MainDialog::onGridLabelContextRim(Grid& grid, ColumnTypeRim type, bool left
menu.addSeparator();
menu.addCheckBox(_("Show icons:"), [&] { setIconSize(globalCfg_.gui.mainDlg.iconSize, !globalCfg_.gui.mainDlg.showIcons); }, globalCfg_.gui.mainDlg.showIcons);
- auto addSizeEntry = [&](const wxString& label, xmlAccess::FileIconSize sz)
+ auto addSizeEntry = [&](const wxString& label, FileIconSize sz)
{
menu.addRadio(label, [sz, &setIconSize] { setIconSize(sz, true /*showIcons*/); }, globalCfg_.gui.mainDlg.iconSize == sz, globalCfg_.gui.mainDlg.showIcons);
};
- addSizeEntry(L" " + _("Small" ), xmlAccess::ICON_SIZE_SMALL );
- addSizeEntry(L" " + _("Medium"), xmlAccess::ICON_SIZE_MEDIUM);
- addSizeEntry(L" " + _("Large" ), xmlAccess::ICON_SIZE_LARGE );
+ addSizeEntry(L" " + _("Small" ), ICON_SIZE_SMALL );
+ addSizeEntry(L" " + _("Medium"), ICON_SIZE_MEDIUM);
+ addSizeEntry(L" " + _("Large" ), ICON_SIZE_LARGE );
//----------------------------------------------------------------------------------------------
// if (type == ColumnTypeRim::DATE)
{
@@ -2693,7 +2678,7 @@ void MainDialog::cfgHistoryRemoveObsolete(const std::vector<Zstring>& filePaths)
std::list<std::future<bool>> availableFiles; //check existence of all config files in parallel!
for (const Zstring& filePath : filePaths)
- availableFiles.push_back(zen::runAsync([=] { return fileAvailable(filePath); }));
+ availableFiles.push_back(runAsync([=] { return fileAvailable(filePath); }));
//potentially slow network access => limit maximum wait time!
wait_for_all_timed(availableFiles.begin(), availableFiles.end(), std::chrono::milliseconds(1000));
@@ -2746,11 +2731,11 @@ void MainDialog::updateUnsavedCfgStatus()
title += utfTo<wxString>(activeCfgFilePath);
else if (activeConfigFiles_.size() > 1)
{
- title += xmlAccess::extractJobName(activeConfigFiles_[0]);
- std::for_each(activeConfigFiles_.begin() + 1, activeConfigFiles_.end(), [&](const Zstring& filepath) { title += SPACED_DASH + xmlAccess::extractJobName(filepath); });
+ title += extractJobName(activeConfigFiles_[0]);
+ std::for_each(activeConfigFiles_.begin() + 1, activeConfigFiles_.end(), [&](const Zstring& filepath) { title += SPACED_DASH + extractJobName(filepath); });
}
else
- title += wxString(L"FreeFileSync ") + zen::ffsVersion + SPACED_DASH + _("Folder Comparison and Synchronization");
+ title += wxString(L"FreeFileSync ") + ffsVersion + SPACED_DASH + _("Folder Comparison and Synchronization");
SetTitle(title);
}
@@ -2760,8 +2745,6 @@ void MainDialog::OnConfigSave(wxCommandEvent& event)
{
const Zstring activeCfgFilePath = activeConfigFiles_.size() == 1 && !equalFilePath(activeConfigFiles_[0], lastRunConfigPath_) ? activeConfigFiles_[0] : Zstring();
- using namespace xmlAccess;
-
//if we work on a single named configuration document: save directly if changed
//else: always show file dialog
if (activeCfgFilePath.empty())
@@ -2814,16 +2797,16 @@ bool MainDialog::trySaveConfig(const Zstring* guiFilename) //return true if save
}
else
{
- Zstring defaultFileName = activeConfigFiles_.size() == 1 && !equalFilePath(activeConfigFiles_[0], lastRunConfigPath_) ? activeConfigFiles_[0] : Zstr("SyncSettings.ffs_gui");
+ Zstring defaultFilePath = activeConfigFiles_.size() == 1 && !equalFilePath(activeConfigFiles_[0], lastRunConfigPath_) ? activeConfigFiles_[0] : Zstr("SyncSettings.ffs_gui");
//attention: activeConfigFiles may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config!
- if (endsWith(defaultFileName, Zstr(".ffs_batch"), CmpFilePath()))
- defaultFileName = beforeLast(defaultFileName, Zstr("."), IF_MISSING_RETURN_NONE) + Zstr(".ffs_gui");
+ if (endsWith(defaultFilePath, Zstr(".ffs_batch"), CmpFilePath()))
+ defaultFilePath = beforeLast(defaultFilePath, Zstr("."), IF_MISSING_RETURN_NONE) + Zstr(".ffs_gui");
wxFileDialog filePicker(this, //put modal dialog on stack: creating this on freestore leads to memleak!
wxString(),
//OS X really needs dir/file separated like this:
- utfTo<wxString>(beforeLast(defaultFileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
- utfTo<wxString>(afterLast (defaultFileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)), //default file
+ utfTo<wxString>(beforeLast(defaultFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
+ utfTo<wxString>(afterLast (defaultFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)), //default file
wxString(L"FreeFileSync (*.ffs_gui)|*.ffs_gui") + L"|" +_("All files") + L" (*.*)|*",
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (filePicker.ShowModal() != wxID_OK)
@@ -2831,7 +2814,7 @@ bool MainDialog::trySaveConfig(const Zstring* guiFilename) //return true if save
targetFilename = utfTo<Zstring>(filePicker.GetPath());
}
- const xmlAccess::XmlGuiConfig guiCfg = getConfig();
+ const XmlGuiConfig guiCfg = getConfig();
try
{
@@ -2851,8 +2834,6 @@ bool MainDialog::trySaveConfig(const Zstring* guiFilename) //return true if save
bool MainDialog::trySaveBatchConfig(const Zstring* batchFileToUpdate)
{
- using namespace xmlAccess;
-
//essentially behave like trySaveConfig(): the collateral damage of not saving GUI-only settings "m_bpButtonViewTypeSyncAction" is negligible
const Zstring activeCfgFilePath = activeConfigFiles_.size() == 1 && !equalFilePath(activeConfigFiles_[0], lastRunConfigPath_) ? activeConfigFiles_[0] : Zstring();
@@ -2899,16 +2880,16 @@ bool MainDialog::trySaveBatchConfig(const Zstring* batchFileToUpdate)
return false;
updateUnsavedCfgStatus(); //nothing else to update on GUI!
- Zstring defaultFileName = !activeCfgFilePath.empty() ? activeCfgFilePath : Zstr("BatchRun.ffs_batch");
+ Zstring defaultFilePath = !activeCfgFilePath.empty() ? activeCfgFilePath : Zstr("BatchRun.ffs_batch");
//attention: activeConfigFiles may be a *.ffs_gui file! We don't want to overwrite it with a BATCH config!
- if (endsWith(defaultFileName, Zstr(".ffs_gui"), CmpFilePath()))
- defaultFileName = beforeLast(defaultFileName, Zstr("."), IF_MISSING_RETURN_NONE) + Zstr(".ffs_batch");
+ if (endsWith(defaultFilePath, Zstr(".ffs_gui"), CmpFilePath()))
+ defaultFilePath = beforeLast(defaultFilePath, Zstr("."), IF_MISSING_RETURN_NONE) + Zstr(".ffs_batch");
wxFileDialog filePicker(this, //put modal dialog on stack: creating this on freestore leads to memleak!
wxString(),
//OS X really needs dir/file separated like this:
- utfTo<wxString>(beforeLast(defaultFileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
- utfTo<wxString>(afterLast (defaultFileName, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)), //default file
+ utfTo<wxString>(beforeLast(defaultFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE)), //default dir
+ utfTo<wxString>(afterLast (defaultFilePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)), //default file
_("FreeFileSync batch") + L" (*.ffs_batch)|*.ffs_batch" + L"|" +_("All files") + L" (*.*)|*",
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (filePicker.ShowModal() != wxID_OK)
@@ -2942,7 +2923,7 @@ bool MainDialog::saveOldConfig() //return false on user abort
const Zstring activeCfgFilePath = activeConfigFiles_.size() == 1 && !equalFilePath(activeConfigFiles_[0], lastRunConfigPath_) ? activeConfigFiles_[0] : Zstring();
//notify user about changed settings
- if (globalCfg_.optDialogs.popupOnConfigChange)
+ if (globalCfg_.confirmDlgs.popupOnConfigChange)
if (!activeCfgFilePath.empty())
//only if check is active and non-default config file loaded
{
@@ -2955,8 +2936,6 @@ bool MainDialog::saveOldConfig() //return false on user abort
_("&Save"), _("Do&n't save")))
{
case QuestionButton2::YES: //save
- using namespace xmlAccess;
-
try
{
switch (getXmlType(activeCfgFilePath)) //throw FileError
@@ -2980,7 +2959,7 @@ bool MainDialog::saveOldConfig() //return false on user abort
break;
case QuestionButton2::NO: //don't save
- globalCfg_.optDialogs.popupOnConfigChange = !neverSaveChanges;
+ globalCfg_.confirmDlgs.popupOnConfigChange = !neverSaveChanges;
break;
case QuestionButton2::CANCEL:
@@ -3022,27 +3001,6 @@ void MainDialog::OnConfigLoad(wxCommandEvent& event)
}
-void MainDialog::OnConfigNew(wxCommandEvent& event)
-{
- warn_static("replace by loadConfiguration({});")
- warn_static("replace excludeFilter handling below with: cfgGrid context menu /new default configuration/")
-
- if (!saveOldConfig()) //notify user about changed settings
- return;
-
- xmlAccess::XmlGuiConfig newConfig;
-
- //add default exclusion filter: this is only ever relevant when creating new configurations!
- //a default XmlGuiConfig does not need these user-specific exclusions!
- Zstring& excludeFilter = newConfig.mainCfg.globalFilter.excludeFilter;
- if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
- excludeFilter += Zstr("\n");
- excludeFilter += globalCfg_.gui.defaultExclusionFilter;
-
- setConfig(newConfig, std::vector<Zstring>());
-}
-
-
void MainDialog::onCfgGridSelection(GridSelectEvent& event)
{
if (event.mouseSelect_ && !event.mouseSelect_->complete)
@@ -3056,15 +3014,12 @@ void MainDialog::onCfgGridSelection(GridSelectEvent& event)
filePaths.push_back(cfg->filePath);
else
assert(false);
-#if 1
+
if (!loadConfiguration(filePaths))
//user changed m_gridCfgHistory selection so it's this method's responsibility to synchronize with activeConfigFiles:
//- if user cancelled saving old config
//- there's an error loading new config
- //- filePaths is empty and user tried to unselect the current config
cfggrid::addAndSelect(*m_gridCfgHistory, activeConfigFiles_, false /*scrollToSelection*/);
-#endif
- warn_static("support the last one??? does NOT support newConfig.mainCfg.globalFilter.excludeFilter!!!")
}
@@ -3078,25 +3033,38 @@ void MainDialog::onCfgGridDoubleClick(GridClickEvent& event)
}
+void MainDialog::OnConfigNew(wxCommandEvent& event)
+{
+ loadConfiguration({});
+}
+
+
bool MainDialog::loadConfiguration(const std::vector<Zstring>& filePaths)
{
if (!saveOldConfig())
return false; //cancelled by user
- xmlAccess::XmlGuiConfig newGuiCfg; //contains default values
+ XmlGuiConfig newGuiCfg; //contains default values
+
+ //add default exclusion filter: this is only ever relevant when creating new configurations!
+ //a default XmlGuiConfig does not need these user-specific exclusions!
+ Zstring& excludeFilter = newGuiCfg.mainCfg.globalFilter.excludeFilter;
+ if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
+ excludeFilter += Zstr("\n");
+ excludeFilter += globalCfg_.gui.defaultExclusionFilter;
if (!filePaths.empty()) //empty cfg file list means "use default"
try
{
//allow reading batch configurations also
std::wstring warningMsg;
- xmlAccess::readAnyConfig(filePaths, newGuiCfg, warningMsg); //throw FileError
+ readAnyConfig(filePaths, newGuiCfg, warningMsg); //throw FileError
if (!warningMsg.empty())
{
showNotificationDialog(this, DialogInfoType::WARNING, PopupDialogCfg().setDetailInstructions(warningMsg));
setConfig(newGuiCfg, filePaths);
- setLastUsedConfig(filePaths, xmlAccess::XmlGuiConfig()); //simulate changed config due to parsing errors
+ setLastUsedConfig(filePaths, XmlGuiConfig()); //simulate changed config due to parsing errors
return true;
}
}
@@ -3207,7 +3175,7 @@ void MainDialog::onCfgGridLabelContext(GridLabelClickEvent& event)
auto setDefault = [&]
{
- const xmlAccess::XmlGlobalSettings defaultCfg;
+ const XmlGlobalSettings defaultCfg;
m_gridCfgHistory->setColumnConfig(convertColAttributes(defaultCfg.gui.mainDlg.cfgGridColumnAttribs, getCfgGridDefaultColAttribs()));
};
menu.addItem(_("&Default"), setDefault); //'&' -> reuse text from "default" buttons elsewhere
@@ -3279,7 +3247,7 @@ void MainDialog::onSetSyncDirection(SyncDirectionEvent& event)
void MainDialog::setLastUsedConfig(const std::vector<Zstring>& cfgFilePaths,
- const xmlAccess::XmlGuiConfig& guiConfig)
+ const XmlGuiConfig& guiConfig)
{
activeConfigFiles_ = cfgFilePaths;
lastSavedCfg_ = guiConfig;
@@ -3290,7 +3258,7 @@ void MainDialog::setLastUsedConfig(const std::vector<Zstring>& cfgFilePaths,
}
-void MainDialog::setConfig(const xmlAccess::XmlGuiConfig& newGuiCfg, const std::vector<Zstring>& referenceFiles)
+void MainDialog::setConfig(const XmlGuiConfig& newGuiCfg, const std::vector<Zstring>& referenceFiles)
{
currentCfg_ = newGuiCfg;
@@ -3317,9 +3285,9 @@ void MainDialog::setConfig(const xmlAccess::XmlGuiConfig& newGuiCfg, const std::
}
-xmlAccess::XmlGuiConfig MainDialog::getConfig() const
+XmlGuiConfig MainDialog::getConfig() const
{
- xmlAccess::XmlGuiConfig guiCfg = currentCfg_;
+ XmlGuiConfig guiCfg = currentCfg_;
//load settings whose ownership lies not in currentCfg:
@@ -3561,7 +3529,7 @@ inline
wxBitmap buttonReleased(const std::string& name)
{
wxImage output = getResourceImage(utfTo<wxString>(name)).ConvertToImage().ConvertToGreyscale(1.0/3, 1.0/3, 1.0/3); //treat all channels equally!
- //zen::moveImage(output, 1, 0); //move image right one pixel
+ //moveImage(output, 1, 0); //move image right one pixel
brighten(output, 80);
return mirrorIfRtl(output);
@@ -3703,13 +3671,13 @@ void MainDialog::OnCompare(wxCommandEvent& event)
//handle status display and error messages
StatusHandlerTemporaryPanel statusHandler(*this);
- const std::vector<zen::FolderPairCfg> cmpConfig = extractCompareCfg(getConfig().mainCfg);
+ const std::vector<FolderPairCfg> cmpConfig = extractCompareCfg(getConfig().mainCfg);
//GUI mode: place directory locks on directories isolated(!) during both comparison and synchronization
std::unique_ptr<LockHolder> dirLocks;
//COMPARE DIRECTORIES
- folderCmp_ = compare(globalCfg_.optDialogs,
+ folderCmp_ = compare(globalCfg_.warnDlgs,
globalCfg_.fileTimeTolerance,
true, //allowUserInteraction
globalCfg_.runWithBackgroundPriority,
@@ -3756,7 +3724,12 @@ void MainDialog::OnCompare(wxCommandEvent& event)
//prepare status information
if (allElementsEqual(folderCmp_))
+ {
flashStatusInformation(_("All files are in sync"));
+
+ //update last sync date for selected cfg files https://www.freefilesync.org/forum/viewtopic.php?t=4991
+ updateLastSyncTimesToNow();
+ }
}
@@ -3865,17 +3838,17 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
}
//show sync preview/confirmation dialog
- if (globalCfg_.optDialogs.confirmSyncStart)
+ if (globalCfg_.confirmDlgs.confirmSyncStart)
{
bool dontShowAgain = false;
- if (zen::showSyncConfirmationDlg(this,
- getConfig().mainCfg.getSyncVariantName(),
- zen::SyncStatistics(folderCmp_),
- dontShowAgain) != ReturnSmallDlg::BUTTON_OKAY)
+ if (showSyncConfirmationDlg(this,
+ getConfig().mainCfg.getSyncVariantName(),
+ SyncStatistics(folderCmp_),
+ dontShowAgain) != ReturnSmallDlg::BUTTON_OKAY)
return;
- globalCfg_.optDialogs.confirmSyncStart = !dontShowAgain;
+ globalCfg_.confirmDlgs.confirmSyncStart = !dontShowAgain;
}
bool exitAfterSync = false;
@@ -3893,15 +3866,17 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
//class handling status updates and error messages
StatusHandlerFloatingDialog statusHandler(this, //throw AbortProcess
+ syncStartTime,
globalCfg_.lastSyncsLogFileSizeMax,
currentCfg_.mainCfg.ignoreErrors,
globalCfg_.automaticRetryCount,
globalCfg_.automaticRetryDelay,
- xmlAccess::extractJobName(activeCfgFilePath),
+ extractJobName(activeCfgFilePath),
globalCfg_.soundFileSyncFinished,
guiCfg.mainCfg.postSyncCommand,
guiCfg.mainCfg.postSyncCondition,
- exitAfterSync);
+ exitAfterSync,
+ globalCfg_.autoCloseProgressDialog);
//inform about (important) non-default global settings
logNonDefaultSettings(globalCfg_, statusHandler); //let's report here rather than before comparison (user might have changed global settings in the meantime!)
@@ -3923,11 +3898,11 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
if (Opt<Zstring> nativeFolderPath = AFS::getNativeItemPath(it->getAbstractPath<RIGHT_SIDE>()))
availableDirPaths.insert(*nativeFolderPath);
}
- dirLocks = std::make_unique<LockHolder>(availableDirPaths, globalCfg_.optDialogs.warnDirectoryLockFailed, statusHandler);
+ dirLocks = std::make_unique<LockHolder>(availableDirPaths, globalCfg_.warnDlgs.warnDirectoryLockFailed, statusHandler);
}
//START SYNCHRONIZATION
- const std::vector<zen::FolderPairSyncCfg> syncProcessCfg = zen::extractSyncCfg(guiCfg.mainCfg);
+ const std::vector<FolderPairSyncCfg> syncProcessCfg = extractSyncCfg(guiCfg.mainCfg);
if (syncProcessCfg.size() != folderCmp_.size())
throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
//should never happen: sync button is deactivated if they are not in sync
@@ -3941,18 +3916,11 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
globalCfg_.folderAccessTimeout,
syncProcessCfg,
folderCmp_,
- globalCfg_.optDialogs,
+ globalCfg_.warnDlgs,
statusHandler);
//not cancelled? => update last sync date for selected cfg files
- std::vector<std::pair<Zstring, time_t>> lastSyncTimes;
- for (const Zstring& cfgPath : activeConfigFiles_)
- lastSyncTimes.emplace_back(cfgPath, std::time(nullptr));
-
- cfggrid::getDataView(*m_gridCfgHistory).setLastSyncTime(lastSyncTimes);
- //re-apply selection: sort order changed if sorted by last sync time
- cfggrid::addAndSelect(*m_gridCfgHistory, activeConfigFiles_, false /*scrollToSelection*/);
- //m_gridCfgHistory->Refresh(); <- implicit in last call
+ updateLastSyncTimesToNow();
}
catch (AbortProcess&) {}
@@ -3966,6 +3934,22 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
}
+void MainDialog::updateLastSyncTimesToNow()
+{
+ const time_t now = std::time(nullptr);
+
+ std::vector<std::pair<Zstring, time_t>> lastSyncTimes;
+ for (const Zstring& cfgPath : activeConfigFiles_)
+ lastSyncTimes.emplace_back(cfgPath, now);
+
+ cfggrid::getDataView(*m_gridCfgHistory).setLastSyncTime(lastSyncTimes);
+
+ //re-apply selection: sort order changed if sorted by last sync time
+ cfggrid::addAndSelect(*m_gridCfgHistory, activeConfigFiles_, false /*scrollToSelection*/);
+ //m_gridCfgHistory->Refresh(); <- implicit in last call
+}
+
+
void MainDialog::onGridDoubleClickL(GridClickEvent& event)
{
onGridDoubleClickRim(event.row_, true);
@@ -3980,14 +3964,14 @@ void MainDialog::onGridDoubleClickR(GridClickEvent& event)
void MainDialog::onGridDoubleClickRim(size_t row, bool leftSide)
{
- if (!globalCfg_.gui.externelApplications.empty())
+ if (!globalCfg_.gui.externalApps.empty())
{
std::vector<FileSystemObject*> selectionLeft;
std::vector<FileSystemObject*> selectionRight;
if (FileSystemObject* fsObj = filegrid::getDataView(*m_gridMainC).getObject(row)) //selection must be a list of BOUND pointers!
(leftSide ? selectionLeft : selectionRight) = { fsObj };
- openExternalApplication(globalCfg_.gui.externelApplications[0].second, leftSide, selectionLeft, selectionRight);
+ openExternalApplication(globalCfg_.gui.externalApps[0].cmdLine, leftSide, selectionLeft, selectionRight);
}
}
@@ -4069,7 +4053,7 @@ void MainDialog::OnSwapSides(wxCommandEvent& event)
try
{
- zen::swapGrids(getConfig().mainCfg, folderCmp_); //throw FileError
+ swapGrids(getConfig().mainCfg, folderCmp_); //throw FileError
}
catch (const FileError& e)
{
@@ -4243,7 +4227,7 @@ void MainDialog::applySyncConfig()
{
try
{
- zen::redetermineSyncDirection(getConfig().mainCfg, folderCmp_, nullptr /*notifyStatus*/); //throw FileError
+ redetermineSyncDirection(getConfig().mainCfg, folderCmp_, nullptr /*notifyStatus*/); //throw FileError
}
catch (const FileError& e)
{
@@ -4664,7 +4648,7 @@ void MainDialog::removeAddFolderPair(size_t pos)
}
-void MainDialog::setAddFolderPairs(const std::vector<zen::FolderPairEnh>& newPairs)
+void MainDialog::setAddFolderPairs(const std::vector<FolderPairEnh>& newPairs)
{
additionalFolderPairs_.clear();
@@ -4681,7 +4665,7 @@ void MainDialog::setAddFolderPairs(const std::vector<zen::FolderPairEnh>& newPai
//menu events
void MainDialog::OnMenuOptions(wxCommandEvent& event)
{
- zen::showOptionsDlg(this, globalCfg_);
+ showOptionsDlg(this, globalCfg_);
}
@@ -4818,13 +4802,13 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
void MainDialog::OnMenuCheckVersion(wxCommandEvent& event)
{
- zen::checkForUpdateNow(this, globalCfg_.gui.lastOnlineVersion);
+ checkForUpdateNow(this, globalCfg_.gui.lastOnlineVersion);
}
void MainDialog::OnMenuUpdateAvailable(wxCommandEvent& event)
{
- zen::checkForUpdateNow(this, globalCfg_.gui.lastOnlineVersion); //show changelog + handle Donation Edition auto-updater (including expiration)
+ checkForUpdateNow(this, globalCfg_.gui.lastOnlineVersion); //show changelog + handle Donation Edition auto-updater (including expiration)
}
@@ -4886,13 +4870,13 @@ void MainDialog::OnLayoutWindowAsync(wxIdleEvent& event)
void MainDialog::OnMenuAbout(wxCommandEvent& event)
{
- zen::showAboutDialog(this);
+ showAboutDialog(this);
}
void MainDialog::OnShowHelp(wxCommandEvent& event)
{
- zen::displayHelpEntry(L"freefilesync", this);
+ displayHelpEntry(L"freefilesync", this);
}
//#########################################################################################################
@@ -4901,7 +4885,7 @@ void MainDialog::OnShowHelp(wxCommandEvent& event)
void MainDialog::switchProgramLanguage(wxLanguage langId)
{
//create new dialog with respect to new language
- xmlAccess::XmlGlobalSettings newGlobalCfg = getGlobalCfgBeforeExit();
+ XmlGlobalSettings newGlobalCfg = getGlobalCfgBeforeExit();
newGlobalCfg.programLanguage = langId;
//show new dialog, then delete old one
diff --git a/FreeFileSync/Source/ui/main_dlg.h b/FreeFileSync/Source/ui/main_dlg.h
index ffc0ec52..646bfd58 100755
--- a/FreeFileSync/Source/ui/main_dlg.h
+++ b/FreeFileSync/Source/ui/main_dlg.h
@@ -9,7 +9,6 @@
#include <map>
#include <list>
-#include <stack>
#include <memory>
#include <wx+/async_task.h>
#include <wx+/file_drop.h>
@@ -21,9 +20,16 @@
#include "folder_history_box.h"
#include "../algorithm.h"
+
+namespace fff
+{
class FolderPairFirst;
class FolderPairPanel;
class CompareProgressDialog;
+class FolderSelectorImpl;
+template <class GuiPanel>
+class FolderPairCallback;
+class PanelMoveWindow;
class MainDialog : public MainDialogGenerated
@@ -36,8 +42,8 @@ public:
//when switching language,
//or switching from batch run to GUI on warnings
static void create(const Zstring& globalConfigFilePath,
- const xmlAccess::XmlGlobalSettings* globalSettings, //optional: take over ownership => save on exit
- const xmlAccess::XmlGuiConfig& guiCfg,
+ const XmlGlobalSettings* globalSettings, //optional: take over ownership => save on exit
+ const XmlGuiConfig& guiCfg,
const std::vector<Zstring>& referenceFiles,
bool startComparison);
@@ -48,15 +54,14 @@ public:
private:
MainDialog(const Zstring& globalConfigFilePath,
- const xmlAccess::XmlGuiConfig& guiCfg,
+ const XmlGuiConfig& guiCfg,
const std::vector<Zstring>& referenceFiles,
- const xmlAccess::XmlGlobalSettings& globalSettings, //take over ownership => save on exit
+ const XmlGlobalSettings& globalSettings, //take over ownership => save on exit
bool startComparison);
~MainDialog();
friend class StatusHandlerTemporaryPanel;
friend class StatusHandlerFloatingDialog;
- friend class ManualDeletionHandler;
friend class FolderPairFirst;
friend class FolderPairPanel;
friend class FolderSelectorImpl;
@@ -65,14 +70,14 @@ private:
friend class PanelMoveWindow;
//configuration load/save
- void setLastUsedConfig(const Zstring& cfgFilePath, const xmlAccess::XmlGuiConfig& guiConfig) { setLastUsedConfig(std::vector<Zstring>({ cfgFilePath }), guiConfig); }
- void setLastUsedConfig(const std::vector<Zstring>& cfgFilePaths, const xmlAccess::XmlGuiConfig& guiConfig);
+ void setLastUsedConfig(const Zstring& cfgFilePath, const XmlGuiConfig& guiConfig) { setLastUsedConfig(std::vector<Zstring>({ cfgFilePath }), guiConfig); }
+ void setLastUsedConfig(const std::vector<Zstring>& cfgFilePaths, const XmlGuiConfig& guiConfig);
- xmlAccess::XmlGuiConfig getConfig() const;
- void setConfig(const xmlAccess::XmlGuiConfig& newGuiCfg, const std::vector<Zstring>& referenceFiles);
+ XmlGuiConfig getConfig() const;
+ void setConfig(const XmlGuiConfig& newGuiCfg, const std::vector<Zstring>& referenceFiles);
- void setGlobalCfgOnInit(const xmlAccess::XmlGlobalSettings& globalSettings); //messes with Maximize(), window sizes, so call just once!
- xmlAccess::XmlGlobalSettings getGlobalCfgBeforeExit(); //destructive "get" thanks to "Iconize(false), Maximize(false)"
+ void setGlobalCfgOnInit(const XmlGlobalSettings& globalSettings); //messes with Maximize(), window sizes, so call just once!
+ XmlGlobalSettings getGlobalCfgBeforeExit(); //destructive "get" thanks to "Iconize(false), Maximize(false)"
bool loadConfiguration(const std::vector<Zstring>& filepaths); //return true if loaded successfully
@@ -87,10 +92,10 @@ private:
void cfgHistoryRemoveObsolete(const std::vector<Zstring>& filepaths);
- void insertAddFolderPair(const std::vector<zen::FolderPairEnh>& newPairs, size_t pos);
+ void insertAddFolderPair(const std::vector<FolderPairEnh>& newPairs, size_t pos);
void moveAddFolderPairUp(size_t pos);
void removeAddFolderPair(size_t pos);
- void setAddFolderPairs(const std::vector<zen::FolderPairEnh>& newPairs);
+ void setAddFolderPairs(const std::vector<FolderPairEnh>& newPairs);
void updateGuiForFolderPair(); //helper method: add usability by showing/hiding buttons related to folder pairs
@@ -103,22 +108,22 @@ private:
void updateUnsavedCfgStatus(); //
//context menu functions
- std::vector<zen::FileSystemObject*> getGridSelection(bool fromLeft = true, bool fromRight = true) const;
- std::vector<zen::FileSystemObject*> getTreeSelection() const;
+ std::vector<FileSystemObject*> getGridSelection(bool fromLeft = true, bool fromRight = true) const;
+ std::vector<FileSystemObject*> getTreeSelection() const;
- void setSyncDirManually(const std::vector<zen::FileSystemObject*>& selection, zen::SyncDirection direction);
- void setFilterManually(const std::vector<zen::FileSystemObject*>& selection, bool setIncluded);
+ void setSyncDirManually(const std::vector<FileSystemObject*>& selection, SyncDirection direction);
+ void setFilterManually (const std::vector<FileSystemObject*>& selection, bool setIncluded);
void copySelectionToClipboard(const std::vector<const zen::Grid*>& gridRefs);
- void copyToAlternateFolder(const std::vector<zen::FileSystemObject*>& selectionLeft,
- const std::vector<zen::FileSystemObject*>& selectionRight);
+ void copyToAlternateFolder(const std::vector<FileSystemObject*>& selectionLeft,
+ const std::vector<FileSystemObject*>& selectionRight);
- void deleteSelectedFiles(const std::vector<zen::FileSystemObject*>& selectionLeft,
- const std::vector<zen::FileSystemObject*>& selectionRight, bool moveToRecycler);
+ void deleteSelectedFiles(const std::vector<FileSystemObject*>& selectionLeft,
+ const std::vector<FileSystemObject*>& selectionRight, bool moveToRecycler);
void openExternalApplication(const Zstring& commandLinePhrase, bool leftSide,
- const std::vector<zen::FileSystemObject*>& selectionLeft,
- const std::vector<zen::FileSystemObject*>& selectionRight); //selection may be empty
+ const std::vector<FileSystemObject*>& selectionLeft,
+ const std::vector<FileSystemObject*>& selectionRight); //selection may be empty
//status bar supports one of the following two states at a time:
void setStatusBarFileStatistics(size_t filesOnLeftView, size_t foldersOnLeftView, size_t filesOnRightView, size_t foldersOnRightView, uint64_t filesizeLeftView, uint64_t filesizeRightView);
@@ -167,8 +172,8 @@ private:
void onDirSelected(wxCommandEvent& event);
void onDirManualCorrection(wxCommandEvent& event);
- void onCheckRows (zen::CheckRowsEvent& event);
- void onSetSyncDirection(zen::SyncDirectionEvent& event);
+ void onCheckRows (CheckRowsEvent& event);
+ void onSetSyncDirection(SyncDirectionEvent& event);
void onGridDoubleClickL(zen::GridClickEvent& event);
void onGridDoubleClickR(zen::GridClickEvent& event);
@@ -177,12 +182,12 @@ private:
void onGridLabelLeftClickL(zen::GridLabelClickEvent& event);
void onGridLabelLeftClickC(zen::GridLabelClickEvent& event);
void onGridLabelLeftClickR(zen::GridLabelClickEvent& event);
- void onGridLabelLeftClick(bool onLeft, zen::ColumnTypeRim type);
+ void onGridLabelLeftClick(bool onLeft, ColumnTypeRim type);
void onGridLabelContextL(zen::GridLabelClickEvent& event);
void onGridLabelContextC(zen::GridLabelClickEvent& event);
void onGridLabelContextR(zen::GridLabelClickEvent& event);
- void onGridLabelContextRim(zen::Grid& grid, zen::ColumnTypeRim type, bool left);
+ void onGridLabelContextRim(zen::Grid& grid, ColumnTypeRim type, bool left);
void OnToggleViewType (wxCommandEvent& event) override;
void OnToggleViewButton(wxCommandEvent& event) override;
@@ -214,15 +219,17 @@ private:
void OnSwapSides (wxCommandEvent& event) override;
void OnClose (wxCloseEvent& event) override;
- void OnCmpSettings (wxCommandEvent& event) override { showConfigDialog(zen::SyncConfigPanel::COMPARISON, -1); }
- void OnConfigureFilter(wxCommandEvent& event) override { showConfigDialog(zen::SyncConfigPanel::FILTER, -1); }
- void OnSyncSettings (wxCommandEvent& event) override { showConfigDialog(zen::SyncConfigPanel::SYNC, -1); }
+ void OnCmpSettings (wxCommandEvent& event) override { showConfigDialog(SyncConfigPanel::COMPARISON, -1); }
+ void OnConfigureFilter(wxCommandEvent& event) override { showConfigDialog(SyncConfigPanel::FILTER, -1); }
+ void OnSyncSettings (wxCommandEvent& event) override { showConfigDialog(SyncConfigPanel::SYNC, -1); }
+
+ void showConfigDialog(SyncConfigPanel panelToShow, int localPairIndexToShow);
- void showConfigDialog(zen::SyncConfigPanel panelToShow, int localPairIndexToShow);
+ void updateLastSyncTimesToNow();
void filterExtension(const Zstring& extension, bool include);
- void filterShortname(const zen::FileSystemObject& fsObj, bool include);
- void filterItems(const std::vector<zen::FileSystemObject*>& selection, bool include);
+ void filterShortname(const FileSystemObject& fsObj, bool include);
+ void filterItems(const std::vector<FileSystemObject*>& selection, bool include);
void addFilterPhrase(const Zstring& phrase, bool include, bool requireNewLine);
void OnTopFolderPairAdd (wxCommandEvent& event) override;
@@ -230,9 +237,9 @@ private:
void OnRemoveFolderPair (wxCommandEvent& event);
void OnShowFolderPairOptions(wxEvent& event);
- void OnTopLocalCompCfg (wxCommandEvent& event) override { showConfigDialog(zen::SyncConfigPanel::COMPARISON, 0); }
- void OnTopLocalSyncCfg (wxCommandEvent& event) override { showConfigDialog(zen::SyncConfigPanel::SYNC, 0); }
- void OnTopLocalFilterCfg(wxCommandEvent& event) override { showConfigDialog(zen::SyncConfigPanel::FILTER, 0); }
+ void OnTopLocalCompCfg (wxCommandEvent& event) override { showConfigDialog(SyncConfigPanel::COMPARISON, 0); }
+ void OnTopLocalSyncCfg (wxCommandEvent& event) override { showConfigDialog(SyncConfigPanel::SYNC, 0); }
+ void OnTopLocalFilterCfg(wxCommandEvent& event) override { showConfigDialog(SyncConfigPanel::FILTER, 0); }
void OnLocalCompCfg (wxCommandEvent& event);
void OnLocalSyncCfg (wxCommandEvent& event);
@@ -278,24 +285,24 @@ private:
//application variables are stored here:
//global settings shared by GUI and batch mode
- xmlAccess::XmlGlobalSettings globalCfg_;
+ XmlGlobalSettings globalCfg_;
const Zstring globalConfigFilePath_;
//-------------------------------------
//program configuration
- xmlAccess::XmlGuiConfig currentCfg_;
+ XmlGuiConfig currentCfg_;
//used when saving configuration
std::vector<Zstring> activeConfigFiles_; //name of currently loaded config files: NOT owned by m_gridCfgHistory, see onCfgGridSelection()
- xmlAccess::XmlGuiConfig lastSavedCfg_; //support for: "Save changed configuration?" dialog
+ XmlGuiConfig lastSavedCfg_; //support for: "Save changed configuration?" dialog
const Zstring lastRunConfigPath_; //let's not use another static...
//-------------------------------------
//the prime data structure of this tool *bling*:
- zen::FolderComparison folderCmp_; //optional!: sync button not available if empty
+ FolderComparison folderCmp_; //optional!: sync button not available if empty
//folder pairs:
std::unique_ptr<FolderPairFirst> firstFolderPair_; //always bound!!!
@@ -326,14 +333,15 @@ private:
zen::AsyncGuiQueue guiQueue_; //schedule and run long-running tasks asynchronously, but process results on GUI queue
- std::unique_ptr<zen::FilterConfig> filterCfgOnClipboard_; //copy/paste of filter config
+ std::unique_ptr<FilterConfig> filterCfgOnClipboard_; //copy/paste of filter config
wxWindow* focusWindowAfterSearch_ = nullptr; //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!!!
- zen::TempFileBuffer tempFileBuf_; //buffer temporary copies of non-native files for %local_path%
+ TempFileBuffer tempFileBuf_; //buffer temporary copies of non-native files for %local_path%
};
+}
#endif //MAIN_DLG_H_8910481324545644545
diff --git a/FreeFileSync/Source/ui/progress_indicator.cpp b/FreeFileSync/Source/ui/progress_indicator.cpp
index bd97f8d5..10e9664b 100755
--- a/FreeFileSync/Source/ui/progress_indicator.cpp
+++ b/FreeFileSync/Source/ui/progress_indicator.cpp
@@ -38,14 +38,14 @@
using namespace zen;
-using namespace xmlAccess;
+using namespace fff;
namespace
{
-//window size used for statistics in milliseconds
-const int WINDOW_REMAINING_TIME_MS = 60000; //USB memory stick scenario can have drop outs of 40 seconds => 60 sec. window size handles it
-const int WINDOW_BYTES_PER_SEC = 5000; //
+//window size used for statistics
+const std::chrono::seconds WINDOW_REMAINING_TIME(60); //USB memory stick scenario can have drop outs of 40 seconds => 60 sec. window size handles it
+const std::chrono::seconds WINDOW_BYTES_PER_SEC (5); //
inline wxColor getColorGridLine() { return { 192, 192, 192 }; } //light grey
@@ -63,12 +63,15 @@ inline wxColor getColorItemsBackgroundRim() { return { 53, 25, 255 }; } //dark
//don't use wxStopWatch for long-running measurements: internally it uses ::QueryPerformanceCounter() which can overflow after only a few days:
-// std::chrono::system_clock is not a steady clock, but at least doesn't overflow!
//https://www.freefilesync.org/forum/viewtopic.php?t=1426
+// std::chrono::system_clock is not a steady clock, but at least doesn't overflow! (wraps ::GetSystemTimePreciseAsFileTime())
+// std::chrono::steady_clock also wraps ::QueryPerformanceCounter() => same flaw like wxStopWatch???
class StopWatch
{
public:
+ bool isPaused() const { return paused_; }
+
void pause()
{
if (!paused_)
@@ -94,18 +97,17 @@ public:
elapsedUntilPause_ = std::chrono::nanoseconds::zero();
}
- int64_t timeMs() const
+ std::chrono::nanoseconds elapsed() const
{
auto elapsedTotal = elapsedUntilPause_;
if (!paused_)
elapsedTotal += std::chrono::system_clock::now() - startTime_;
-
- return std::chrono::duration_cast<std::chrono::milliseconds>(elapsedTotal).count();
+ return elapsedTotal;
}
private:
bool paused_ = false;
- std::chrono::system_clock::time_point startTime_ = std::chrono::system_clock::now(); //uses ::GetSystemTimePreciseAsFileTime()
+ std::chrono::system_clock::time_point startTime_ = std::chrono::system_clock::now();
std::chrono::nanoseconds elapsedUntilPause_{}; //std::chrono::duration is uninitialized by default! WTF! When will this stupidity end???
};
@@ -116,6 +118,9 @@ std::wstring getDialogPhaseText(const Statistics* syncStat, bool paused, SyncPro
{
if (paused)
return _("Paused");
+
+ if (syncStat->getAbortStatus())
+ return _("Stop requested...");
else
switch (syncStat->currentPhase())
{
@@ -135,7 +140,9 @@ std::wstring getDialogPhaseText(const Statistics* syncStat, bool paused, SyncPro
case SyncProgressDialog::RESULT_ABORTED:
return _("Stopped");
case SyncProgressDialog::RESULT_FINISHED_WITH_ERROR:
+ return _("Completed with errors");
case SyncProgressDialog::RESULT_FINISHED_WITH_WARNINGS:
+ return _("Completed with warnings");
case SyncProgressDialog::RESULT_FINISHED_WITH_SUCCESS:
return _("Completed");
}
@@ -209,15 +216,15 @@ private:
wxFrame& parentWindow_;
wxString parentTitleBackup_;
- StopWatch timeElapsed_;
- int64_t binCompStartMs_ = 0; //begin of binary comparison phase in [ms]
+ StopWatch stopWatch_;
+ std::chrono::nanoseconds binCompStart_{}; //begin of binary comparison phase
const Statistics* syncStat_ = nullptr; //only bound while sync is running
std::unique_ptr<Taskbar> taskbar_;
std::unique_ptr<PerfCheck> perf_; //estimate remaining time
- int64_t timeLastSpeedEstimateMs_ = -1000000; //used for calculating intervals between showing and collecting perf samples
+ std::chrono::nanoseconds timeLastSpeedEstimate_ = std::chrono::seconds(-100); //used for calculating intervals between showing and collecting perf samples
//initial value: just some big number
std::shared_ptr<CurveDataProgressBar> curveDataBytes_{ std::make_shared<CurveDataProgressBar>(true /*drawTop*/) };
@@ -268,7 +275,7 @@ void CompareProgressDialog::Impl::init(const Statistics& syncStat, bool ignoreEr
bSizerProgressGraph->Show(false);
perf_.reset();
- timeElapsed_.restart(); //measure total time
+ stopWatch_.restart(); //measure total time
//initially hide status that's relevant for comparing bytewise only
m_staticTextItemsFoundLabel->Show();
@@ -311,10 +318,10 @@ void CompareProgressDialog::Impl::initNewPhase()
case ProcessCallback::PHASE_COMPARING_CONTENT:
case ProcessCallback::PHASE_SYNCHRONIZING:
//start to measure perf
- perf_ = std::make_unique<PerfCheck>(WINDOW_REMAINING_TIME_MS, WINDOW_BYTES_PER_SEC);
- timeLastSpeedEstimateMs_ = -1000000; //some big number
+ perf_ = std::make_unique<PerfCheck>(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC);
+ timeLastSpeedEstimate_ = std::chrono::seconds(-100); //make sure estimate is updated upon next check
- binCompStartMs_ = timeElapsed_.timeMs();
+ binCompStart_ = stopWatch_.elapsed();
bSizerProgressGraph->Show(true);
@@ -355,7 +362,7 @@ void CompareProgressDialog::Impl::updateProgressGui()
};
bool layoutChanged = false; //avoid screen flicker by calling layout() only if necessary
- const int64_t timeNowMs = timeElapsed_.timeMs();
+ const std::chrono::nanoseconds timeElapsed = stopWatch_.elapsed();
//status texts
setText(*m_staticTextStatus, replaceCpy(syncStat_->currentStatusText(), L'\n', L' ')); //no layout update for status texts!
@@ -410,12 +417,12 @@ void CompareProgressDialog::Impl::updateProgressGui()
//remaining time and speed: only visible during binary comparison
assert(perf_);
if (perf_)
- if (numeric::dist(timeLastSpeedEstimateMs_, timeNowMs) >= 500)
+ if (numeric::dist(timeLastSpeedEstimate_, timeElapsed) >= std::chrono::milliseconds(500))
{
- timeLastSpeedEstimateMs_ = timeNowMs;
+ timeLastSpeedEstimate_ = timeElapsed;
- if (numeric::dist(binCompStartMs_, timeNowMs) >= 1000) //discard stats for first second: probably messy
- perf_->addSample(itemsCurrent, bytesCurrent, timeNowMs);
+ if (numeric::dist(binCompStart_, timeElapsed) >= std::chrono::seconds(1)) //discard stats for first second: probably messy
+ perf_->addSample(timeElapsed, itemsCurrent, bytesCurrent);
//current speed -> Win 7 copy uses 1 sec update interval instead
Opt<std::wstring> bps = perf_->getBytesPerSecond();
@@ -434,8 +441,8 @@ void CompareProgressDialog::Impl::updateProgressGui()
break;
}
- //time elapsed
- const int64_t timeElapSec = timeNowMs / 1000;
+ const int64_t timeElapSec = std::chrono::duration_cast<std::chrono::seconds>(timeElapsed).count();
+
setText(*m_staticTextTimeElapsed,
timeElapSec < 3600 ?
wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") :
@@ -508,7 +515,7 @@ public:
struct LogEntryView
{
time_t time = 0;
- MessageType type = TYPE_INFO;
+ MessageType type = MSG_TYPE_INFO;
MsgString messageLine;
bool firstLine = false; //if LogEntry::message spans multiple rows
};
@@ -529,7 +536,7 @@ public:
return NoValue();
}
- void updateView(int includedTypes) //TYPE_INFO | TYPE_WARNING, ect. see error_log.h
+ void updateView(int includedTypes) //MSG_TYPE_INFO | MSG_TYPE_WARNING, ect. see error_log.h
{
viewRef_.clear();
@@ -626,13 +633,13 @@ public:
if (entry->firstLine)
switch (entry->type)
{
- case TYPE_INFO:
+ case MSG_TYPE_INFO:
return _("Info");
- case TYPE_WARNING:
+ case MSG_TYPE_WARNING:
return _("Warning");
- case TYPE_ERROR:
+ case MSG_TYPE_ERROR:
return _("Error");
- case TYPE_FATAL_ERROR:
+ case MSG_TYPE_FATAL_ERROR:
return _("Serious Error");
}
break;
@@ -676,14 +683,14 @@ public:
if (entry->firstLine)
switch (entry->type)
{
- case TYPE_INFO:
+ case MSG_TYPE_INFO:
drawBitmapRtlNoMirror(dc, getResourceImage(L"msg_info_small"), rectTmp, wxALIGN_CENTER);
break;
- case TYPE_WARNING:
+ case MSG_TYPE_WARNING:
drawBitmapRtlNoMirror(dc, getResourceImage(L"msg_warning_small"), rectTmp, wxALIGN_CENTER);
break;
- case TYPE_ERROR:
- case TYPE_FATAL_ERROR:
+ case MSG_TYPE_ERROR:
+ case MSG_TYPE_FATAL_ERROR:
drawBitmapRtlNoMirror(dc, getResourceImage(L"msg_error_small"), rectTmp, wxALIGN_CENTER);
break;
}
@@ -760,9 +767,9 @@ class LogPanel : public LogPanelGenerated
public:
LogPanel(wxWindow* parent, const ErrorLog& log) : LogPanelGenerated(parent)
{
- const int errorCount = log.getItemCount(TYPE_ERROR | TYPE_FATAL_ERROR);
- const int warningCount = log.getItemCount(TYPE_WARNING);
- const int infoCount = log.getItemCount(TYPE_INFO);
+ const int errorCount = log.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR);
+ const int warningCount = log.getItemCount(MSG_TYPE_WARNING);
+ const int infoCount = log.getItemCount(MSG_TYPE_INFO);
auto initButton = [](ToggleButton& btn, const wchar_t* imgName, const wxString& tooltip)
{
@@ -840,13 +847,13 @@ private:
{
int includedTypes = 0;
if (m_bpButtonErrors->isActive())
- includedTypes |= TYPE_ERROR | TYPE_FATAL_ERROR;
+ includedTypes |= MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR;
if (m_bpButtonWarnings->isActive())
- includedTypes |= TYPE_WARNING;
+ includedTypes |= MSG_TYPE_WARNING;
if (m_bpButtonInfo->isActive())
- includedTypes |= TYPE_INFO;
+ includedTypes |= MSG_TYPE_INFO;
getDataView().updateView(includedTypes); //update MVC "model"
m_gridMessages->Refresh(); //update MVC "view"
@@ -1009,27 +1016,20 @@ class CurveDataStatistics : public SparseCurveData
public:
CurveDataStatistics() : SparseCurveData(true /*addSteps*/) {}
- void clear() { samples_.clear(); lastSample_ = std::make_pair(0, 0); }
+ void clear() { samples_.clear(); lastSample_ = {}; }
- void addRecord(int64_t timeNowMs, double value)
+ void addRecord(std::chrono::nanoseconds timeElapsed, double value)
{
- assert((!samples_.empty() || lastSample_ == std::pair<int64_t, double>(0, 0)));
-
- //samples.clear();
- //samples.emplace(-1000, 0);
- //samples.emplace(0, 0);
- //samples.emplace(1, 1);
- //samples.emplace(1000, 0);
- //return;
+ assert(!samples_.empty() || (lastSample_ == std::pair<std::chrono::nanoseconds, double>()));
- lastSample_ = std::make_pair(timeNowMs, value);
+ lastSample_ = { timeElapsed, value };
- //allow for at most one sample per 100ms (handles duplicate inserts, too!) => this is unrelated to UI_UPDATE_INTERVAL_MS!
+ //allow for at most one sample per 100ms (handles duplicate inserts, too!) => this is unrelated to UI_UPDATE_INTERVAL!
if (!samples_.empty()) //always unconditionally insert first sample!
- if (timeNowMs / 100 == samples_.rbegin()->first / 100)
+ if (numeric::dist(timeElapsed, samples_.rbegin()->first) < std::chrono::milliseconds(100))
return;
- samples_.insert(samples_.end(), std::make_pair(timeNowMs, value)); //time is "expected" to be monotonously ascending
+ samples_.insert(samples_.end(), { timeElapsed, value }); //time is "expected" to be monotonously ascending
//documentation differs about whether "hint" should be before or after the to be inserted element!
//however "std::map<>::end()" is interpreted correctly by GCC and VS2010
@@ -1041,9 +1041,9 @@ private:
std::pair<double, double> getRangeX() const override
{
if (samples_.empty())
- return std::make_pair(0.0, 0.0);
+ return {};
- const double upperEndMs = std::max(samples_.rbegin()->first, lastSample_.first);
+ const std::chrono::nanoseconds upperEnd = std::max(samples_.rbegin()->first, lastSample_.first);
/*
//report some additional width by 5% elapsed time to make graph recalibrate before hitting the right border
@@ -1052,47 +1052,49 @@ private:
upperEndMs += 0.05 *(upperEndMs - samples.begin()->first);
*/
- return { samples_.begin()->first / 1000.0, //need not start with 0, e.g. "binary comparison, graph reset, followed by sync"
- upperEndMs / 1000.0};
+ return { std::chrono::duration<double>(samples_.begin()->first).count(), //need not start with 0, e.g. "binary comparison, graph reset, followed by sync"
+ std::chrono::duration<double>(upperEnd).count() };
}
Opt<CurvePoint> getLessEq(double x) const override //x: seconds since begin
{
- const int64_t timex = std::floor(x * 1000);
+ const auto timeX = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double>(x)); //round down
+
//------ add artifical last sample value -------
if (!samples_.empty() && samples_.rbegin()->first < lastSample_.first)
- if (lastSample_.first <= timex)
- return CurvePoint(lastSample_.first / 1000.0, lastSample_.second);
+ if (lastSample_.first <= timeX)
+ return CurvePoint(std::chrono::duration<double>(lastSample_.first).count(), lastSample_.second);
//--------------------------------------------------
//find first key > x, then go one step back: => samples must be a std::map, NOT std::multimap!!!
- auto it = samples_.upper_bound(timex);
+ auto it = samples_.upper_bound(timeX);
if (it == samples_.begin())
return NoValue();
//=> samples not empty in this context
--it;
- return CurvePoint(it->first / 1000.0, it->second);
+ return CurvePoint(std::chrono::duration<double>(it->first).count(), it->second);
}
Opt<CurvePoint> getGreaterEq(double x) const override
{
- const int64_t timex = std::ceil(x * 1000);
+ const std::chrono::nanoseconds timeX(static_cast<std::chrono::nanoseconds::rep>(std::ceil(x * (1000 * 1000 * 1000)))); //round up!
+
//------ add artifical last sample value -------
if (!samples_.empty() && samples_.rbegin()->first < lastSample_.first)
- if (samples_.rbegin()->first < timex && timex <= lastSample_.first)
- return CurvePoint(lastSample_.first / 1000.0, lastSample_.second);
+ if (samples_.rbegin()->first < timeX && timeX <= lastSample_.first)
+ return CurvePoint(std::chrono::duration<double>(lastSample_.first).count(), lastSample_.second);
//--------------------------------------------------
- auto it = samples_.lower_bound(timex);
+ auto it = samples_.lower_bound(timeX);
if (it == samples_.end())
return NoValue();
- return CurvePoint(it->first / 1000.0, it->second);
+ return CurvePoint(std::chrono::duration<double>(it->first).count(), it->second);
}
static const size_t MAX_BUFFER_SIZE = 2500000; //sizeof(single node) worst case ~ 3 * 8 byte ptr + 16 byte key/value = 40 byte
- std::map <int64_t, double> samples_; //time, unit: [ms] !don't use std::multimap, see getLessEq()
- std::pair<int64_t, double> lastSample_; //artificial most current record at the end of samples to visualize current time!
+ std::map <std::chrono::nanoseconds, double> samples_; //[!] don't use std::multimap, see getLessEq()
+ std::pair<std::chrono::nanoseconds, double> lastSample_; //artificial most current record at the end of samples to visualize current time!
};
@@ -1247,10 +1249,11 @@ public:
const Statistics& syncStat,
wxFrame* parentFrame,
bool showProgress,
+ bool autoCloseDialog,
const wxString& jobName,
const Zstring& soundFileSyncComplete,
bool ignoreErrors,
- PostSyncAction postSyncAction);
+ PostSyncAction2 postSyncAction);
~SyncProgressDialogImpl() override;
//call this in StatusUpdater derived class destructor at the LATEST(!) to prevent access to currentStatusUpdater
@@ -1266,17 +1269,20 @@ public:
bool getOptionIgnoreErrors() const override { return pnl_.m_checkBoxIgnoreErrors->GetValue(); }
void setOptionIgnoreErrors(bool ignoreErrors) override { pnl_.m_checkBoxIgnoreErrors->SetValue(ignoreErrors); updateStaticGui(); }
- PostSyncAction getOptionPostSyncAction() const override { return getEnumVal(enumPostSyncAction_, *pnl_.m_choicePostSyncAction); }
+ PostSyncAction2 getOptionPostSyncAction() const override { return getEnumVal(enumPostSyncAction_, *pnl_.m_choicePostSyncAction); }
+ bool getOptionAutoCloseDialog() const override { return pnl_.m_checkBoxAutoClose->GetValue(); }
- void stopTimer() override //halt all internal counters!
+ void timerSetStatus(bool active) override
{
- //pnl.m_animCtrlSyncing->Stop();
- timeElapsed_.pause();
+ if (active)
+ stopWatch_.resume();
+ else
+ stopWatch_.pause();
}
- void resumeTimer() override
+
+ bool timerIsRunning() const override
{
- //pnl.m_animCtrlSyncing->Play();
- timeElapsed_.resume();
+ return !stopWatch_.isPaused();
}
private:
@@ -1302,7 +1308,7 @@ private:
const wxString jobName_;
const Zstring soundFileSyncComplete_;
- StopWatch timeElapsed_;
+ StopWatch stopWatch_;
wxFrame* parentFrame_; //optional
@@ -1318,10 +1324,10 @@ private:
//remaining time
std::unique_ptr<PerfCheck> perf_;
- int64_t timeLastSpeedEstimateMs_ = -1000000; //used for calculating intervals between collecting perf samples
+ std::chrono::nanoseconds timeLastSpeedEstimate_ = std::chrono::seconds(-100); //used for calculating intervals between collecting perf samples
//help calculate total speed
- int64_t phaseStartMs_ = 0; //begin of current phase in [ms]
+ std::chrono::nanoseconds phaseStart_{}; //begin of current phase
std::shared_ptr<CurveDataStatistics > curveDataBytes_ { std::make_shared<CurveDataStatistics>() };
std::shared_ptr<CurveDataStatistics > curveDataItems_ { std::make_shared<CurveDataStatistics>() };
@@ -1334,7 +1340,7 @@ private:
std::unique_ptr<FfsTrayIcon> trayIcon_; //optional: if filled all other windows should be hidden and conversely
std::unique_ptr<Taskbar> taskbar_;
- EnumDescrList<PostSyncAction> enumPostSyncAction_;
+ EnumDescrList<PostSyncAction2> enumPostSyncAction_;
};
@@ -1346,10 +1352,11 @@ SyncProgressDialogImpl<TopLevelDialog>::SyncProgressDialogImpl(long style, //wxF
const Statistics& syncStat,
wxFrame* parentFrame,
bool showProgress,
+ bool autoCloseDialog,
const wxString& jobName,
const Zstring& soundFileSyncComplete,
bool ignoreErrors,
- PostSyncAction postSyncAction) :
+ PostSyncAction2 postSyncAction) :
TopLevelDialog(parentFrame, wxID_ANY, wxString(), wxDefaultPosition, wxDefaultSize, style), //title is overwritten anyway in setExternalStatus()
pnl_(*new SyncProgressPanelGenerated(this)), //ownership passed to "this"
jobName_ (jobName),
@@ -1395,7 +1402,7 @@ SyncProgressDialogImpl<TopLevelDialog>::SyncProgressDialogImpl(long style, //wxF
//this->EnableCloseButton(false); //this is NOT honored on OS X or with ALT+F4 on Windows! -> why disable button at all??
- timeElapsed_.restart(); //measure total time
+ stopWatch_.restart(); //measure total time
if (wxFrame* frame = getTaskbarFrame(*this))
try //try to get access to Windows 7/Ubuntu taskbar
@@ -1455,14 +1462,16 @@ SyncProgressDialogImpl<TopLevelDialog>::SyncProgressDialogImpl(long style, //wxF
//allow changing a few options dynamically during sync
pnl_.m_checkBoxIgnoreErrors->SetValue(ignoreErrors);
- enumPostSyncAction_.
- add(PostSyncAction::SUMMARY, _("Show summary")).
- add(PostSyncAction::EXIT, replaceCpy(_("E&xit"), L"&", L"")). //reuse translation
- add(PostSyncAction::SLEEP, _("Sleep")).
- add(PostSyncAction::SHUTDOWN, _("Shut down"));
+ enumPostSyncAction_.add(PostSyncAction2::NONE, L"");
+ if (parentFrame_) //enable EXIT option for gui mode sync
+ enumPostSyncAction_.add(PostSyncAction2::EXIT, replaceCpy(_("E&xit"), L"&", L"")); //reuse translation
+ enumPostSyncAction_.add(PostSyncAction2::SLEEP, _("System: Sleep"));
+ enumPostSyncAction_.add(PostSyncAction2::SHUTDOWN, _("System: Shut down"));
setEnumVal(enumPostSyncAction_, *pnl_.m_choicePostSyncAction, postSyncAction);
+ pnl_.m_checkBoxAutoClose->SetValue(autoCloseDialog);
+
updateStaticGui(); //null-status will be shown while waiting for dir locks
this->GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
@@ -1553,10 +1562,10 @@ void SyncProgressDialogImpl<TopLevelDialog>::initNewPhase()
notifyProgressChange(); //make sure graphs get initial values
//start new measurement
- perf_ = std::make_unique<PerfCheck>(WINDOW_REMAINING_TIME_MS, WINDOW_BYTES_PER_SEC);
- timeLastSpeedEstimateMs_ = -1000000; //some big number
+ perf_ = std::make_unique<PerfCheck>(WINDOW_REMAINING_TIME, WINDOW_BYTES_PER_SEC);
+ timeLastSpeedEstimate_ = std::chrono::seconds(-100); //make sure estimate is updated upon next check
- phaseStartMs_ = timeElapsed_.timeMs();
+ phaseStart_ = stopWatch_.elapsed();
updateProgressGui(false /*allowYield*/);
}
@@ -1578,8 +1587,8 @@ void SyncProgressDialogImpl<TopLevelDialog>::notifyProgressChange() //noexcept!
const int64_t bytesCurrent = syncStat_->getBytesCurrent(syncStat_->currentPhase());
const int itemsCurrent = syncStat_->getItemsCurrent(syncStat_->currentPhase());
- curveDataBytes_->addRecord(timeElapsed_.timeMs(), bytesCurrent);
- curveDataItems_->addRecord(timeElapsed_.timeMs(), itemsCurrent);
+ curveDataBytes_->addRecord(stopWatch_.elapsed(), bytesCurrent);
+ curveDataItems_->addRecord(stopWatch_.elapsed(), itemsCurrent);
}
break;
}
@@ -1625,8 +1634,15 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
if (!syncStat_) //sync not running
return;
+ //normally we don't update the "static" GUI components here, but we have to make an exception
+ //if sync is cancelled (by user or error handling option)
+ if (syncStat_->getAbortStatus())
+ updateStaticGui(); //called more than once after cancel... ok
+
+
bool layoutChanged = false; //avoid screen flicker by calling layout() only if necessary
- const int64_t timeNowMs = timeElapsed_.timeMs();
+ const std::chrono::nanoseconds timeElapsed = stopWatch_.elapsed();
+ const double timeElapsedDouble = std::chrono::duration<double>(timeElapsed).count();
//sync status text
setText(*pnl_.m_staticTextStatus, replaceCpy(syncStat_->currentStatusText(), L'\n', L' ')); //no layout update for status texts!
@@ -1670,13 +1686,13 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
//progress indicators
if (trayIcon_.get()) trayIcon_->setProgress(fractionTotal);
- if (taskbar_.get()) taskbar_->setProgress(fractionTotal);
+ if (taskbar_ .get()) taskbar_ ->setProgress(fractionTotal);
- const double timeTotalSecTentative = bytesTotal == bytesCurrent ? timeNowMs / 1000.0 : std::max(curveDataBytesTotal_->getValueX(), timeNowMs / 1000.0);
+ const double timeTotalSecTentative = bytesTotal == bytesCurrent ? timeElapsedDouble : std::max(curveDataBytesTotal_->getValueX(), timeElapsedDouble);
//constant line graph
- curveDataBytesCurrent_->setValue(timeNowMs / 1000.0, timeTotalSecTentative, bytesCurrent);
- curveDataItemsCurrent_->setValue(timeNowMs / 1000.0, timeTotalSecTentative, itemsCurrent);
+ curveDataBytesCurrent_->setValue(timeElapsedDouble, timeTotalSecTentative, bytesCurrent);
+ curveDataItemsCurrent_->setValue(timeElapsedDouble, timeTotalSecTentative, itemsCurrent);
//tentatively update total time, may be improved on below:
curveDataBytesTotal_->setValue(timeTotalSecTentative, bytesTotal);
@@ -1684,8 +1700,8 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
//even though notifyProgressChange() already set the latest data, let's add another sample to have all curves consider "timeNowMs"
//no problem with adding too many records: CurveDataStatistics will remove duplicate entries!
- curveDataBytes_->addRecord(timeNowMs, bytesCurrent);
- curveDataItems_->addRecord(timeNowMs, itemsCurrent);
+ curveDataBytes_->addRecord(timeElapsed, bytesCurrent);
+ curveDataItems_->addRecord(timeElapsed, itemsCurrent);
//remaining item and byte count
setText(*pnl_.m_staticTextItemsRemaining, formatNumber(itemsTotal - itemsCurrent), &layoutChanged);
@@ -1695,12 +1711,12 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
//remaining time and speed
assert(perf_);
if (perf_)
- if (numeric::dist(timeLastSpeedEstimateMs_, timeNowMs) >= 500)
+ if (numeric::dist(timeLastSpeedEstimate_, timeElapsed) >= std::chrono::milliseconds(500))
{
- timeLastSpeedEstimateMs_ = timeNowMs;
+ timeLastSpeedEstimate_ = timeElapsed;
- if (numeric::dist(phaseStartMs_, timeNowMs) >= 1000) //discard stats for first second: probably messy
- perf_->addSample(itemsCurrent, bytesCurrent, timeNowMs);
+ if (numeric::dist(phaseStart_, timeElapsed) >= std::chrono::seconds(1)) //discard stats for first second: probably messy
+ perf_->addSample(timeElapsed, itemsCurrent, bytesCurrent);
//current speed -> Win 7 copy uses 1 sec update interval instead
Opt<std::wstring> bps = perf_->getBytesPerSecond();
@@ -1715,17 +1731,16 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
//update estimated total time marker with precision of "10% remaining time" only to avoid needless jumping around:
const double timeRemainingSec = remTimeSec ? *remTimeSec : 0;
- const double timeTotalSec = timeNowMs / 1000.0 + timeRemainingSec;
+ const double timeTotalSec = timeElapsedDouble + timeRemainingSec;
if (numeric::dist(curveDataBytesTotal_->getValueX(), timeTotalSec) > 0.1 * timeRemainingSec)
{
curveDataBytesTotal_->setValueX(timeTotalSec);
curveDataItemsTotal_->setValueX(timeTotalSec);
//don't forget to update these, too:
- curveDataBytesCurrent_->setValue(timeNowMs / 1000.0, timeTotalSec, bytesCurrent);
- curveDataItemsCurrent_->setValue(timeNowMs / 1000.0, timeTotalSec, itemsCurrent);
+ curveDataBytesCurrent_->setValue(timeElapsedDouble, timeTotalSec, bytesCurrent);
+ curveDataItemsCurrent_->setValue(timeElapsedDouble, timeTotalSec, itemsCurrent);
}
}
-
break;
}
}
@@ -1733,8 +1748,8 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
pnl_.m_panelGraphBytes->Refresh();
pnl_.m_panelGraphItems->Refresh();
- //time elapsed
- const int64_t timeElapSec = timeNowMs / 1000;
+ const int64_t timeElapSec = std::chrono::duration_cast<std::chrono::seconds>(timeElapsed).count();
+
setText(*pnl_.m_staticTextTimeElapsed,
timeElapSec < 3600 ?
wxTimeSpan::Seconds(timeElapSec).Format( L"%M:%S") :
@@ -1765,20 +1780,19 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
2. no crash on Ubuntu GCC
3. following makes GCC crash already during compilation: auto dfd = zen::makeGuard([this]{ resumeTimer(); });
*/
-
- stopTimer();
+ timerSetStatus(false /*active*/);
while (paused_)
{
wxTheApp->Yield(); //receive UI message that end pause OR forceful termination!
//*first* refresh GUI (removing flicker) before sleeping!
- std::this_thread::sleep_for(std::chrono::milliseconds(UI_UPDATE_INTERVAL_MS));
+ std::this_thread::sleep_for(UI_UPDATE_INTERVAL);
}
//after SyncProgressDialogImpl::OnClose() called wxWindow::Destroy() on OS X this instance is instantly toast!
if (wereDead_)
- return; //GTFO and don't call this->resumeTimer()
+ return; //GTFO and don't call this->timerSetStatus()
- resumeTimer();
+ timerSetStatus(true /*active*/);
}
else
/*
@@ -1796,65 +1810,64 @@ void SyncProgressDialogImpl<TopLevelDialog>::updateProgressGui(bool allowYield)
template <class TopLevelDialog>
void SyncProgressDialogImpl<TopLevelDialog>::updateStaticGui() //depends on "syncStat_, paused_, finalResult"
{
- auto setStatusBitmap = [&](const wchar_t* bmpName, const wxString& tooltip)
+ const wxString dlgPhaseTxt = getDialogPhaseText(syncStat_, paused_, finalResult_);
+
+ pnl_.m_staticTextPhase->SetLabel(dlgPhaseTxt);
+ //pnl_.m_bitmapStatus->SetToolTip(dlgPhaseTxt); -> redundant
+
+ auto setStatusBitmap = [&](const wchar_t* bmpName)
{
pnl_.m_bitmapStatus->SetBitmap(getResourceImage(bmpName));
- pnl_.m_bitmapStatus->SetToolTip(tooltip);
pnl_.m_bitmapStatus->Show();
- //pnl.m_animCtrlSyncing->Hide();
};
- const wxString dlgStatusTxt = getDialogPhaseText(syncStat_, paused_, finalResult_);
-
- pnl_.m_staticTextPhase->SetLabel(dlgStatusTxt);
-
//status bitmap
if (syncStat_) //sync running
{
if (paused_)
- setStatusBitmap(L"status_pause", dlgStatusTxt);
+ setStatusBitmap(L"status_pause");
else
- switch (syncStat_->currentPhase())
- {
- case ProcessCallback::PHASE_NONE:
- //pnl.m_animCtrlSyncing->Hide();
- pnl_.m_bitmapStatus->Hide();
- break;
+ {
+ if (syncStat_->getAbortStatus())
+ setStatusBitmap(L"status_aborted");
+ else
+ switch (syncStat_->currentPhase())
+ {
+ case ProcessCallback::PHASE_NONE:
+ pnl_.m_bitmapStatus->Hide();
+ break;
- case ProcessCallback::PHASE_SCANNING:
- setStatusBitmap(L"status_scanning", dlgStatusTxt);
- break;
+ case ProcessCallback::PHASE_SCANNING:
+ setStatusBitmap(L"status_scanning");
+ break;
- case ProcessCallback::PHASE_COMPARING_CONTENT:
- setStatusBitmap(L"status_binary_compare", dlgStatusTxt);
- break;
+ case ProcessCallback::PHASE_COMPARING_CONTENT:
+ setStatusBitmap(L"status_binary_compare");
+ break;
- case ProcessCallback::PHASE_SYNCHRONIZING:
- pnl_.m_bitmapStatus->SetBitmap(getResourceImage(L"status_syncing"));
- pnl_.m_bitmapStatus->SetToolTip(dlgStatusTxt);
- pnl_.m_bitmapStatus->Show();
- //pnl.m_animCtrlSyncing->Show();
- //pnl.m_animCtrlSyncing->SetToolTip(dlgStatusTxt);
- break;
- }
+ case ProcessCallback::PHASE_SYNCHRONIZING:
+ setStatusBitmap(L"status_syncing");
+ break;
+ }
+ }
}
else //sync finished
switch (finalResult_)
{
case RESULT_ABORTED:
- setStatusBitmap(L"status_aborted", _("Synchronization stopped"));
+ setStatusBitmap(L"status_aborted");
break;
case RESULT_FINISHED_WITH_ERROR:
- setStatusBitmap(L"status_finished_errors", _("Synchronization completed with errors"));
+ setStatusBitmap(L"status_finished_errors");
break;
case RESULT_FINISHED_WITH_WARNINGS:
- setStatusBitmap(L"status_finished_warnings", _("Synchronization completed with warnings"));
+ setStatusBitmap(L"status_finished_warnings");
break;
case RESULT_FINISHED_WITH_SUCCESS:
- setStatusBitmap(L"status_finished_success", _("Synchronization completed successfully"));
+ setStatusBitmap(L"status_finished_success");
break;
}
@@ -1960,10 +1973,11 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultId, co
assert(bytesCurrent <= bytesTotal);
//set overall speed (instead of current speed)
- const int64_t timeDelta = timeElapsed_.timeMs() - phaseStartMs_; //we need to consider "time within current phase" not total "timeElapsed"!
+ const double timeDelta = std::chrono::duration<double>(stopWatch_.elapsed() - phaseStart_).count();
+ //we need to consider "time within current phase" not total "timeElapsed"!
- const wxString overallBytesPerSecond = timeDelta == 0 ? std::wstring() : formatFilesizeShort(bytesCurrent * 1000 / timeDelta) + _("/sec");
- const wxString overallItemsPerSecond = timeDelta == 0 ? std::wstring() : replaceCpy(_("%x items/sec"), L"%x", formatThreeDigitPrecision(itemsCurrent * 1000.0 / timeDelta));
+ const wxString overallBytesPerSecond = numeric::isNull(timeDelta) ? std::wstring() : formatFilesizeShort(numeric::round(bytesCurrent / timeDelta)) + _("/sec");
+ const wxString overallItemsPerSecond = numeric::isNull(timeDelta) ? std::wstring() : replaceCpy(_("%x items/sec"), L"%x", formatThreeDigitPrecision(itemsCurrent / timeDelta));
pnl_.m_panelGraphBytes->setAttributes(pnl_.m_panelGraphBytes->getAttributes().setCornerText(overallBytesPerSecond, Graph2D::CORNER_TOP_LEFT));
pnl_.m_panelGraphItems->setAttributes(pnl_.m_panelGraphItems->getAttributes().setCornerText(overallItemsPerSecond, Graph2D::CORNER_TOP_LEFT));
@@ -2007,6 +2021,9 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultId, co
pnl_.bSizerProgressFooter->Show(false);
+ if (!parentFrame_) //hide checkbox for batch mode sync (where value won't be retrieved after close)
+ pnl_.m_checkBoxAutoClose->Hide();
+
//set std order after button visibility was set
setStandardButtonLayout(*pnl_.bSizerStdButtons, StdButtons().setAffirmative(pnl_.m_buttonClose));
@@ -2039,7 +2056,7 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultId, co
//bSizerHoldStretch->Insert(0, logPanel, 1, wxEXPAND);
//show log instead of graph if errors occurred! (not required for ignored warnings)
- if (log.getItemCount(TYPE_ERROR | TYPE_FATAL_ERROR) > 0)
+ if (log.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) > 0)
pnl_.m_notebookResult->ChangeSelection(pagePosLog);
//fill image list to cope with wxNotebook image setting design desaster...
@@ -2108,11 +2125,10 @@ void SyncProgressDialogImpl<TopLevelDialog>::OnOkay(wxCommandEvent& event)
template <class TopLevelDialog>
void SyncProgressDialogImpl<TopLevelDialog>::OnCancel(wxCommandEvent& event)
{
+ if (abortCb_) abortCb_->userRequestAbort();
+
paused_ = false;
updateStaticGui(); //update status + pause button
-
- if (abortCb_)
- abortCb_->userRequestAbort();
//no Layout() or UI-update here to avoid cascaded Yield()-call!
}
@@ -2225,15 +2241,16 @@ void SyncProgressDialogImpl<TopLevelDialog>::resumeFromSystray()
//########################################################################################
-SyncProgressDialog* createProgressDialog(zen::AbortCallback& abortCb,
- const std::function<void()>& notifyWindowTerminate, //note: user closing window cannot be prevented on OS X! (And neither on Windows during system shutdown!)
- const zen::Statistics& syncStat,
- wxFrame* parentWindow, //may be nullptr
- bool showProgress,
- const wxString& jobName,
- const Zstring& soundFileSyncComplete,
- bool ignoreErrors,
- PostSyncAction postSyncAction)
+SyncProgressDialog* fff::createProgressDialog(AbortCallback& abortCb,
+ const std::function<void()>& notifyWindowTerminate, //note: user closing window cannot be prevented on OS X! (And neither on Windows during system shutdown!)
+ const Statistics& syncStat,
+ wxFrame* parentWindow, //may be nullptr
+ bool showProgress,
+ bool autoCloseDialog,
+ const wxString& jobName,
+ const Zstring& soundFileSyncComplete,
+ bool ignoreErrors,
+ PostSyncAction2 postSyncAction)
{
if (parentWindow) //sync from GUI
{
@@ -2241,13 +2258,13 @@ SyncProgressDialog* createProgressDialog(zen::AbortCallback& abortCb,
//https://groups.google.com/forum/#!topic/wx-users/J5SjjLaBOQE
return new SyncProgressDialogImpl<wxDialog>(wxDEFAULT_DIALOG_STYLE | wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxRESIZE_BORDER,
[&](wxDialog& progDlg) { return parentWindow; },
- abortCb, notifyWindowTerminate, syncStat, parentWindow, showProgress, jobName, soundFileSyncComplete, ignoreErrors, postSyncAction);
+ abortCb, notifyWindowTerminate, syncStat, parentWindow, showProgress, autoCloseDialog, jobName, soundFileSyncComplete, ignoreErrors, postSyncAction);
}
else //FFS batch job
{
auto dlg = new SyncProgressDialogImpl<wxFrame>(wxDEFAULT_FRAME_STYLE,
[](wxFrame& progDlg) { return &progDlg; },
- abortCb, notifyWindowTerminate, syncStat, parentWindow, showProgress, jobName, soundFileSyncComplete, ignoreErrors, postSyncAction);
+ abortCb, notifyWindowTerminate, syncStat, parentWindow, showProgress, autoCloseDialog, jobName, soundFileSyncComplete, ignoreErrors, postSyncAction);
//only top level windows should have an icon:
dlg->SetIcon(getFfsIcon());
diff --git a/FreeFileSync/Source/ui/progress_indicator.h b/FreeFileSync/Source/ui/progress_indicator.h
index 4d230429..3562db96 100755
--- a/FreeFileSync/Source/ui/progress_indicator.h
+++ b/FreeFileSync/Source/ui/progress_indicator.h
@@ -15,6 +15,8 @@
#include "../lib/process_xml.h"
+namespace fff
+{
class CompareProgressDialog
{
public:
@@ -22,7 +24,7 @@ public:
wxWindow* getAsWindow(); //convenience! don't abuse!
- void init(const zen::Statistics& syncStat, bool ignoreErrors); //begin of sync: make visible, set pointer to "syncStat", initialize all status values
+ void init(const Statistics& syncStat, bool ignoreErrors); //begin of sync: make visible, set pointer to "syncStat", initialize all status values
void teardown(); //end of sync: hide again, clear pointer to "syncStat"
void initNewPhase(); //call after "StatusHandler::initNewPhase"
@@ -41,6 +43,14 @@ private:
//StatusHandlerFloatingDialog will internally process Window messages => disable GUI controls to avoid unexpected callbacks!
+enum class PostSyncAction2
+{
+ NONE,
+ EXIT,
+ SLEEP,
+ SHUTDOWN
+};
+
struct SyncProgressDialog
{
enum SyncResult
@@ -66,36 +76,39 @@ struct SyncProgressDialog
//allow changing a few options dynamically during sync
virtual bool getOptionIgnoreErrors() const = 0;
virtual void setOptionIgnoreErrors(bool ignoreError) = 0;
- virtual xmlAccess::PostSyncAction getOptionPostSyncAction() const = 0;
+ virtual PostSyncAction2 getOptionPostSyncAction() const = 0;
+ virtual bool getOptionAutoCloseDialog() const = 0;
- virtual void stopTimer () = 0; //halt all internal timers!
- virtual void resumeTimer() = 0; //
+ virtual void timerSetStatus(bool active) = 0; //start/stop all internal timers!
+ virtual bool timerIsRunning() const = 0;
protected:
~SyncProgressDialog() {}
};
-SyncProgressDialog* createProgressDialog(zen::AbortCallback& abortCb,
+SyncProgressDialog* createProgressDialog(AbortCallback& abortCb,
const std::function<void()>& notifyWindowTerminate, //note: user closing window cannot be prevented on OS X! (And neither on Windows during system shutdown!)
- const zen::Statistics& syncStat,
+ const Statistics& syncStat,
wxFrame* parentWindow, //may be nullptr
bool showProgress,
+ bool autoCloseDialog,
const wxString& jobName,
const Zstring& soundFileSyncComplete,
bool ignoreErrors,
- xmlAccess::PostSyncAction postSyncAction);
+ PostSyncAction2 postSyncAction);
//DON'T delete the pointer! it will be deleted by the user clicking "OK/Cancel"/wxWindow::Destroy() after showSummary() or closeDirectly()
class PauseTimers
{
public:
- PauseTimers(SyncProgressDialog& ss) : ss_(ss) { ss_.stopTimer(); }
- ~PauseTimers() { ss_.resumeTimer(); }
+ PauseTimers(SyncProgressDialog& ss) : ss_(ss), timerWasRunning_(ss.timerIsRunning()) { ss_.timerSetStatus(false); }
+ ~PauseTimers() { ss_.timerSetStatus(timerWasRunning_); } //restore previous state: support recursive calls
private:
SyncProgressDialog& ss_;
+ const bool timerWasRunning_;
};
-
+}
#endif //PROGRESS_INDICATOR_H_8037493452348
diff --git a/FreeFileSync/Source/ui/search.cpp b/FreeFileSync/Source/ui/search.cpp
index 6bcfed34..dd46c7f8 100755
--- a/FreeFileSync/Source/ui/search.cpp
+++ b/FreeFileSync/Source/ui/search.cpp
@@ -9,6 +9,7 @@
#include <zen/perf.h>
using namespace zen;
+using namespace fff;
namespace
@@ -72,7 +73,7 @@ ptrdiff_t findRow(const Grid& grid, //return -1 if no matching row found
}
-std::pair<const Grid*, ptrdiff_t> zen::findGridMatch(const Grid& grid1, const Grid& grid2, const std::wstring& searchString, bool respectCase, bool searchAscending)
+std::pair<const Grid*, ptrdiff_t> fff::findGridMatch(const Grid& grid1, const Grid& grid2, const std::wstring& searchString, bool respectCase, bool searchAscending)
{
//PERF_START
@@ -92,7 +93,7 @@ std::pair<const Grid*, ptrdiff_t> zen::findGridMatch(const Grid& grid1, const Gr
findRow<false>(grid, searchString, searchAscending, rowFirst, rowLast);
if (targetRow >= 0)
{
- result = std::make_pair(&grid, targetRow);
+ result = { &grid, targetRow };
return true;
}
return false;
diff --git a/FreeFileSync/Source/ui/search.h b/FreeFileSync/Source/ui/search.h
index 362460d1..81560f7c 100755
--- a/FreeFileSync/Source/ui/search.h
+++ b/FreeFileSync/Source/ui/search.h
@@ -9,9 +9,10 @@
#include <wx+/grid.h>
-namespace zen
+
+namespace fff
{
-std::pair<const Grid*, ptrdiff_t> findGridMatch(const Grid& grid1, const Grid& grid2, const std::wstring& searchString, bool respectCase, bool searchAscending);
+std::pair<const zen::Grid*, ptrdiff_t> findGridMatch(const zen::Grid& grid1, const zen::Grid& grid2, const std::wstring& searchString, bool respectCase, bool searchAscending);
//returns (grid/row) where the value was found, (nullptr, -1) if not found
}
diff --git a/FreeFileSync/Source/ui/small_dlgs.cpp b/FreeFileSync/Source/ui/small_dlgs.cpp
index 9c4b9196..c3889a94 100755
--- a/FreeFileSync/Source/ui/small_dlgs.cpp
+++ b/FreeFileSync/Source/ui/small_dlgs.cpp
@@ -5,7 +5,6 @@
// *****************************************************************************
#include "small_dlgs.h"
-//#include <chrono>
#include <zen/time.h>
#include <zen/format_unit.h>
#include <zen/build_info.h>
@@ -35,6 +34,7 @@
using namespace zen;
+using namespace fff;
class AboutDlg : public AboutDlgGenerated
@@ -106,7 +106,7 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
//generate logo: put *after* first Fit()
Layout(); //make sure m_panelLogo has final width (required by wxGTK)
- wxImage appnameImg = createImageFromText(wxString(L"FreeFileSync ") + zen::ffsVersion,
+ wxImage appnameImg = createImageFromText(wxString(L"FreeFileSync ") + ffsVersion,
wxFont(wxNORMAL_FONT->GetPointSize() * 1.8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, L"Tahoma"),
*wxBLACK); //accessibility: align foreground/background colors!
wxImage buildImg = createImageFromText(replaceCpy(_("Build: %x"), L"%x", build),
@@ -153,7 +153,7 @@ void AboutDlg::onLocalKeyEvent(wxKeyEvent& event) //process key events without e
}
-void zen::showAboutDialog(wxWindow* parent)
+void fff::showAboutDialog(wxWindow* parent)
{
AboutDlg aboutDlg(parent);
aboutDlg.ShowModal();
@@ -224,7 +224,7 @@ CopyToDialog::CopyToDialog(wxWindow* parent,
http://trac.wxwidgets.org/ticket/14823 "Menu not disabled when showing modal dialogs in wxGTK under Unity"
*/
- const std::pair<std::wstring, int> selectionInfo = zen::getSelectedItemsAsString(rowsOnLeft, rowsOnRight);
+ const std::pair<std::wstring, int> selectionInfo = getSelectedItemsAsString(rowsOnLeft, rowsOnRight);
const wxString header = _P("Copy the following item to another folder?",
"Copy the following %x items to another folder?", selectionInfo.second);
@@ -278,7 +278,7 @@ void CopyToDialog::OnOK(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showCopyToDialog(wxWindow* parent,
+ReturnSmallDlg::ButtonPressed fff::showCopyToDialog(wxWindow* parent,
const std::vector<const FileSystemObject*>& rowsOnLeft,
const std::vector<const FileSystemObject*>& rowsOnRight,
Zstring& lastUsedPath,
@@ -359,8 +359,8 @@ DeleteDialog::DeleteDialog(wxWindow* parent,
void DeleteDialog::updateGui()
{
- const std::pair<std::wstring, int> delInfo = zen::getSelectedItemsAsString(rowsToDeleteOnLeft_,
- rowsToDeleteOnRight_);
+ const std::pair<std::wstring, int> delInfo = getSelectedItemsAsString(rowsToDeleteOnLeft_,
+ rowsToDeleteOnRight_);
wxString header;
if (m_checkBoxUseRecycler->GetValue())
{
@@ -411,7 +411,7 @@ void DeleteDialog::OnOK(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showDeleteDialog(wxWindow* parent,
+ReturnSmallDlg::ButtonPressed fff::showDeleteDialog(wxWindow* parent,
const std::vector<const FileSystemObject*>& rowsOnLeft,
const std::vector<const FileSystemObject*>& rowsOnRight,
bool& useRecycleBin)
@@ -427,7 +427,7 @@ class SyncConfirmationDlg : public SyncConfirmationDlgGenerated
public:
SyncConfirmationDlg(wxWindow* parent,
const wxString& variantName,
- const zen::SyncStatistics& st,
+ const SyncStatistics& st,
bool& dontShowAgain);
private:
void OnStartSync(wxCommandEvent& event) override;
@@ -509,9 +509,9 @@ void SyncConfirmationDlg::OnStartSync(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showSyncConfirmationDlg(wxWindow* parent,
+ReturnSmallDlg::ButtonPressed fff::showSyncConfirmationDlg(wxWindow* parent,
const wxString& variantName,
- const zen::SyncStatistics& statistics,
+ const SyncStatistics& statistics,
bool& dontShowAgain)
{
SyncConfirmationDlg dlg(parent,
@@ -526,7 +526,7 @@ ReturnSmallDlg::ButtonPressed zen::showSyncConfirmationDlg(wxWindow* parent,
class OptionsDlg : public OptionsDlgGenerated
{
public:
- OptionsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSettings);
+ OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalCfg);
private:
void OnOkay (wxCommandEvent& event) override;
@@ -545,19 +545,29 @@ private:
void OnToggleAutoRetryCount(wxCommandEvent& event) override { updateGui(); }
- void setExtApp(const xmlAccess::ExternalApps& extApp);
- xmlAccess::ExternalApps getExtApp() const;
+ void setExtApp(const std::vector<ExternalApp>& extApp);
+ std::vector<ExternalApp> getExtApp() const;
std::map<std::wstring, std::wstring> descriptionTransToEng_; //"translated description" -> "english" mapping for external application config
+ //parameters NOT owned by GUI:
+ ConfirmationDialogs confirmDlgs_;
+ WarningDialogs warnDlgs_;
+ bool autoCloseProgressDialog_;
+
+ const XmlGlobalSettings defaultCfg_;
+
//output-only parameters:
- xmlAccess::XmlGlobalSettings& globalSettingsOut_;
+ XmlGlobalSettings& globalCfgOut_;
};
-OptionsDlg::OptionsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSettings) :
+OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
OptionsDlgGenerated(parent),
- globalSettingsOut_(globalSettings)
+ confirmDlgs_(globalSettings.confirmDlgs),
+ warnDlgs_ (globalSettings.warnDlgs),
+ autoCloseProgressDialog_(globalSettings.autoCloseProgressDialog),
+ globalCfgOut_(globalSettings)
{
setStandardButtonLayout(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonOkay).setCancel(m_buttonCancel));
@@ -578,7 +588,7 @@ OptionsDlg::OptionsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSet
m_spinCtrlAutoRetryCount->SetValue(globalSettings.automaticRetryCount);
m_spinCtrlAutoRetryDelay->SetValue(globalSettings.automaticRetryDelay);
- setExtApp(globalSettings.gui.externelApplications);
+ setExtApp(globalSettings.gui.externalApps);
updateGui();
@@ -631,91 +641,90 @@ void OptionsDlg::updateGui()
{
const bool autoRetryActive = m_spinCtrlAutoRetryCount->GetValue() > 0;
m_staticTextAutoRetryDelay->Enable(autoRetryActive);
- m_spinCtrlAutoRetryDelay->Enable(autoRetryActive);
+ m_spinCtrlAutoRetryDelay ->Enable(autoRetryActive);
+
+ m_buttonResetDialogs->Enable(confirmDlgs_ != defaultCfg_.confirmDlgs ||
+ warnDlgs_ != defaultCfg_.warnDlgs ||
+ autoCloseProgressDialog_ != defaultCfg_.autoCloseProgressDialog);
}
-void OptionsDlg::OnOkay(wxCommandEvent& event)
+void OptionsDlg::OnResetDialogs(wxCommandEvent& event)
{
- //write settings only when okay-button is pressed (except hidden dialog reset)!
- globalSettingsOut_.failSafeFileCopy = m_checkBoxFailSafe->GetValue();
- globalSettingsOut_.copyLockedFiles = m_checkBoxCopyLocked->GetValue();
- globalSettingsOut_.copyFilePermissions = m_checkBoxCopyPermissions->GetValue();
-
- globalSettingsOut_.automaticRetryCount = m_spinCtrlAutoRetryCount->GetValue();
- globalSettingsOut_.automaticRetryDelay = m_spinCtrlAutoRetryDelay->GetValue();
-
- globalSettingsOut_.gui.externelApplications = getExtApp();
-
- EndModal(ReturnSmallDlg::BUTTON_OKAY);
+ confirmDlgs_ = defaultCfg_.confirmDlgs;
+ warnDlgs_ = defaultCfg_.warnDlgs;
+ autoCloseProgressDialog_ = defaultCfg_.autoCloseProgressDialog;
+ updateGui();
}
-void OptionsDlg::OnResetDialogs(wxCommandEvent& event)
+void OptionsDlg::OnDefault(wxCommandEvent& event)
{
- switch (showConfirmationDialog(this, DialogInfoType::INFO,
- PopupDialogCfg().setMainInstructions(_("Show hidden dialogs and warning messages again?")),
- _("&Show")))
- {
- case ConfirmationButton::ACCEPT:
- globalSettingsOut_.optDialogs = xmlAccess::OptionalDialogs();
- break;
- case ConfirmationButton::CANCEL:
- break;
- }
+ m_checkBoxFailSafe ->SetValue(defaultCfg_.failSafeFileCopy);
+ m_checkBoxCopyLocked ->SetValue(defaultCfg_.copyLockedFiles);
+ m_checkBoxCopyPermissions->SetValue(defaultCfg_.copyFilePermissions);
+
+ m_spinCtrlAutoRetryCount->SetValue(defaultCfg_.automaticRetryCount);
+ m_spinCtrlAutoRetryDelay->SetValue(defaultCfg_.automaticRetryDelay);
+
+ setExtApp(defaultCfg_.gui.externalApps);
+ updateGui();
}
-void OptionsDlg::OnDefault(wxCommandEvent& event)
+void OptionsDlg::OnOkay(wxCommandEvent& event)
{
- const xmlAccess::XmlGlobalSettings defaultCfg;
+ //write settings only when okay-button is pressed (except hidden dialog reset)!
+ globalCfgOut_.failSafeFileCopy = m_checkBoxFailSafe->GetValue();
+ globalCfgOut_.copyLockedFiles = m_checkBoxCopyLocked->GetValue();
+ globalCfgOut_.copyFilePermissions = m_checkBoxCopyPermissions->GetValue();
- m_checkBoxFailSafe ->SetValue(defaultCfg.failSafeFileCopy);
- m_checkBoxCopyLocked ->SetValue(defaultCfg.copyLockedFiles);
- m_checkBoxCopyPermissions->SetValue(defaultCfg.copyFilePermissions);
+ globalCfgOut_.automaticRetryCount = m_spinCtrlAutoRetryCount->GetValue();
+ globalCfgOut_.automaticRetryDelay = m_spinCtrlAutoRetryDelay->GetValue();
- m_spinCtrlAutoRetryCount->SetValue(defaultCfg.automaticRetryCount);
- m_spinCtrlAutoRetryDelay->SetValue(defaultCfg.automaticRetryDelay);
+ globalCfgOut_.gui.externalApps = getExtApp();
- setExtApp(defaultCfg.gui.externelApplications);
+ globalCfgOut_.confirmDlgs = confirmDlgs_;
+ globalCfgOut_.warnDlgs = warnDlgs_;
+ globalCfgOut_.autoCloseProgressDialog = autoCloseProgressDialog_;
- updateGui();
+ EndModal(ReturnSmallDlg::BUTTON_OKAY);
}
-void OptionsDlg::setExtApp(const xmlAccess::ExternalApps& extApp)
+void OptionsDlg::setExtApp(const std::vector<ExternalApp>& extApps)
{
- auto extAppTmp = extApp;
- erase_if(extAppTmp, [](auto& entry) { return entry.first.empty() && entry.second.empty(); });
+ auto extAppsTmp = extApps;
+ erase_if(extAppsTmp, [](auto& entry) { return entry.description.empty() && entry.cmdLine.empty(); });
- extAppTmp.emplace_back(); //append empty row to facilitate insertions by user
+ extAppsTmp.emplace_back(); //append empty row to facilitate insertions by user
const int rowCount = m_gridCustomCommand->GetNumberRows();
if (rowCount > 0)
m_gridCustomCommand->DeleteRows(0, rowCount);
- m_gridCustomCommand->AppendRows(static_cast<int>(extAppTmp.size()));
- for (auto it = extAppTmp.begin(); it != extAppTmp.end(); ++it)
+ m_gridCustomCommand->AppendRows(static_cast<int>(extAppsTmp.size()));
+ for (auto it = extAppsTmp.begin(); it != extAppsTmp.end(); ++it)
{
- const int row = it - extAppTmp.begin();
+ const int row = it - extAppsTmp.begin();
- const std::wstring description = zen::translate(it->first);
- if (description != it->first) //remember english description to save in GlobalSettings.xml later rather than hard-code translation
- descriptionTransToEng_[description] = it->first;
+ const std::wstring description = zen::translate(it->description);
+ if (description != it->description) //remember english description to save in GlobalSettings.xml later rather than hard-code translation
+ descriptionTransToEng_[description] = it->description;
m_gridCustomCommand->SetCellValue(row, 0, description);
- m_gridCustomCommand->SetCellValue(row, 1, utfTo<wxString>(it->second)); //commandline
+ m_gridCustomCommand->SetCellValue(row, 1, utfTo<wxString>(it->cmdLine)); //commandline
}
}
-xmlAccess::ExternalApps OptionsDlg::getExtApp() const
+std::vector<ExternalApp> OptionsDlg::getExtApp() const
{
- xmlAccess::ExternalApps output;
+ std::vector<ExternalApp> output;
for (int i = 0; i < m_gridCustomCommand->GetNumberRows(); ++i)
{
auto description = copyStringTo<std::wstring>(m_gridCustomCommand->GetCellValue(i, 0));
- auto commandline = utfTo<Zstring> (m_gridCustomCommand->GetCellValue(i, 1));
+ auto commandline = utfTo<Zstring>(m_gridCustomCommand->GetCellValue(i, 1));
//try to undo translation of description for GlobalSettings.xml
auto it = descriptionTransToEng_.find(description);
@@ -723,7 +732,7 @@ xmlAccess::ExternalApps OptionsDlg::getExtApp() const
description = it->second;
if (!description.empty() || !commandline.empty())
- output.emplace_back(description, commandline);
+ output.push_back({ description, commandline });
}
return output;
}
@@ -754,9 +763,9 @@ void OptionsDlg::OnRemoveRow(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showOptionsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSettings)
+ReturnSmallDlg::ButtonPressed fff::showOptionsDlg(wxWindow* parent, XmlGlobalSettings& globalCfg)
{
- OptionsDlg dlg(parent, globalSettings);
+ OptionsDlg dlg(parent, globalCfg);
return static_cast<ReturnSmallDlg::ButtonPressed>(dlg.ShowModal());
}
@@ -866,7 +875,7 @@ void SelectTimespanDlg::OnOkay(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showSelectTimespanDlg(wxWindow* parent, time_t& timeFrom, time_t& timeTo)
+ReturnSmallDlg::ButtonPressed fff::showSelectTimespanDlg(wxWindow* parent, time_t& timeFrom, time_t& timeTo)
{
SelectTimespanDlg timeSpanDlg(parent, timeFrom, timeTo);
return static_cast<ReturnSmallDlg::ButtonPressed>(timeSpanDlg.ShowModal());
@@ -915,7 +924,7 @@ void CfgHighlightDlg::OnOkay(wxCommandEvent& event)
}
-ReturnSmallDlg::ButtonPressed zen::showCfgHighlightDlg(wxWindow* parent, int& cfgHistSyncOverdueDays)
+ReturnSmallDlg::ButtonPressed fff::showCfgHighlightDlg(wxWindow* parent, int& cfgHistSyncOverdueDays)
{
CfgHighlightDlg cfgHighDlg(parent, cfgHistSyncOverdueDays);
return static_cast<ReturnSmallDlg::ButtonPressed>(cfgHighDlg.ShowModal());
@@ -992,7 +1001,7 @@ void ActivationDlg::OnActivateOffline(wxCommandEvent& event)
}
-ReturnActivationDlg zen::showActivationDialog(wxWindow* parent, const std::wstring& lastErrorMsg, const std::wstring& manualActivationUrl, std::wstring& manualActivationKey)
+ReturnActivationDlg fff::showActivationDialog(wxWindow* parent, const std::wstring& lastErrorMsg, const std::wstring& manualActivationUrl, std::wstring& manualActivationKey)
{
ActivationDlg dlg(parent, lastErrorMsg, manualActivationUrl, manualActivationKey);
return static_cast<ReturnActivationDlg>(dlg.ShowModal());
@@ -1062,15 +1071,18 @@ DownloadProgressWindow::Impl::Impl(wxWindow* parent, int64_t fileSizeTotal) :
Center(); //needs to be re-applied after a dialog size change!
Show();
+ //clear gui flicker: window must be visible to make this work!
+ ::wxSafeYield(); //at least on OS X a real Yield() is required to flush pending GUI updates; Update() is not enough
+
m_buttonCancel->SetFocus();
}
-zen::DownloadProgressWindow::DownloadProgressWindow(wxWindow* parent, int64_t fileSizeTotal) :
+DownloadProgressWindow::DownloadProgressWindow(wxWindow* parent, int64_t fileSizeTotal) :
pimpl_(new DownloadProgressWindow::Impl(parent, fileSizeTotal)) {}
-zen::DownloadProgressWindow::~DownloadProgressWindow() { pimpl_->Destroy(); }
+DownloadProgressWindow::~DownloadProgressWindow() { pimpl_->Destroy(); }
-void zen::DownloadProgressWindow::notifyNewFile(const Zstring& filePath) { pimpl_->notifyNewFile(filePath); }
-void zen::DownloadProgressWindow::notifyProgress(int64_t delta) { pimpl_->notifyProgress(delta); }
-void zen::DownloadProgressWindow::requestUiRefresh() { pimpl_->requestUiRefresh(); } //throw CancelPressed
+void DownloadProgressWindow::notifyNewFile(const Zstring& filePath) { pimpl_->notifyNewFile(filePath); }
+void DownloadProgressWindow::notifyProgress(int64_t delta) { pimpl_->notifyProgress(delta); }
+void DownloadProgressWindow::requestUiRefresh() { pimpl_->requestUiRefresh(); } //throw CancelPressed
diff --git a/FreeFileSync/Source/ui/small_dlgs.h b/FreeFileSync/Source/ui/small_dlgs.h
index e6af0872..6d79b416 100755
--- a/FreeFileSync/Source/ui/small_dlgs.h
+++ b/FreeFileSync/Source/ui/small_dlgs.h
@@ -12,7 +12,7 @@
#include "../synchronization.h"
-namespace zen
+namespace fff
{
//parent window, optional: support correct dialog placement above parent on multiple monitor systems
@@ -46,7 +46,7 @@ ReturnSmallDlg::ButtonPressed showSyncConfirmationDlg(wxWindow* parent,
const SyncStatistics& statistics,
bool& dontShowAgain);
-ReturnSmallDlg::ButtonPressed showOptionsDlg(wxWindow* parent, xmlAccess::XmlGlobalSettings& globalSettings);
+ReturnSmallDlg::ButtonPressed showOptionsDlg(wxWindow* parent, XmlGlobalSettings& globalCfg);
ReturnSmallDlg::ButtonPressed showSelectTimespanDlg(wxWindow* parent, time_t& timeFrom, time_t& timeTo);
diff --git a/FreeFileSync/Source/ui/sorting.h b/FreeFileSync/Source/ui/sorting.h
index a2b598d9..8fdeca5b 100755
--- a/FreeFileSync/Source/ui/sorting.h
+++ b/FreeFileSync/Source/ui/sorting.h
@@ -11,7 +11,7 @@
#include "../file_hierarchy.h"
-namespace zen
+namespace fff
{
namespace
{
@@ -52,7 +52,7 @@ bool lessShortFileName(const FileSystemObject& a, const FileSystemObject& b)
return true;
//sort directories and files/symlinks by short name
- return makeSortDirection(LessNaturalSort() /*even on Linux*/, Int2Type<ascending>())(a.getItemName<side>(), b.getItemName<side>());
+ return makeSortDirection(LessNaturalSort() /*even on Linux*/, zen::Int2Type<ascending>())(a.getItemName<side>(), b.getItemName<side>());
}
@@ -65,9 +65,9 @@ bool lessFullPath(const FileSystemObject& a, const FileSystemObject& b)
else if (b.isEmpty<side>())
return true;
- return makeSortDirection(LessNaturalSort() /*even on Linux*/, Int2Type<ascending>())(
- utfTo<Zstring>(AFS::getDisplayPath(a.getAbstractPath<side>())),
- utfTo<Zstring>(AFS::getDisplayPath(b.getAbstractPath<side>())));
+ return makeSortDirection(LessNaturalSort() /*even on Linux*/, zen::Int2Type<ascending>())(
+ zen::utfTo<Zstring>(AFS::getDisplayPath(a.getAbstractPath<side>())),
+ zen::utfTo<Zstring>(AFS::getDisplayPath(b.getAbstractPath<side>())));
}
@@ -88,7 +88,7 @@ bool lessRelativeFolder(const FileSystemObject& a, const FileSystemObject& b)
const int rv = CmpNaturalSort()(relFolderA.c_str(), relFolderA.size(),
relFolderB.c_str(), relFolderB.size());
if (rv != 0)
- return makeSortDirection(std::less<int>(), Int2Type<ascending>())(rv, 0);
+ return makeSortDirection(std::less<int>(), zen::Int2Type<ascending>())(rv, 0);
//make directories always appear before contained files
if (isDirectoryB)
@@ -96,7 +96,7 @@ bool lessRelativeFolder(const FileSystemObject& a, const FileSystemObject& b)
else if (isDirectoryA)
return true;
- return makeSortDirection(LessNaturalSort(), Int2Type<ascending>())(a.getPairItemName(), b.getPairItemName());
+ return makeSortDirection(LessNaturalSort(), zen::Int2Type<ascending>())(a.getPairItemName(), b.getPairItemName());
}
@@ -125,7 +125,7 @@ bool lessFilesize(const FileSystemObject& a, const FileSystemObject& b)
return true;
//return list beginning with largest files first
- return makeSortDirection(std::less<>(), Int2Type<ascending>())(fileA->getFileSize<side>(), fileB->getFileSize<side>());
+ return makeSortDirection(std::less<>(), zen::Int2Type<ascending>())(fileA->getFileSize<side>(), fileB->getFileSize<side>());
}
@@ -152,7 +152,7 @@ bool lessFiletime(const FileSystemObject& a, const FileSystemObject& b)
const int64_t dateB = fileB ? fileB->getLastWriteTime<side>() : symlinkB->getLastWriteTime<side>();
//return list beginning with newest files first
- return makeSortDirection(std::less<>(), Int2Type<ascending>())(dateA, dateB);
+ return makeSortDirection(std::less<>(), zen::Int2Type<ascending>())(dateA, dateB);
}
@@ -174,7 +174,7 @@ bool lessExtension(const FileSystemObject& a, const FileSystemObject& b)
return afterLast(fsObj.getItemName<side>(), Zchar('.'), zen::IF_MISSING_RETURN_NONE);
};
- return makeSortDirection(LessNaturalSort() /*even on Linux*/, Int2Type<ascending>())(getExtension(a), getExtension(b));
+ return makeSortDirection(LessNaturalSort() /*even on Linux*/, zen::Int2Type<ascending>())(getExtension(a), getExtension(b));
}
@@ -187,14 +187,14 @@ bool lessCmpResult(const FileSystemObject& a, const FileSystemObject& b)
if (b.getCategory() == FILE_EQUAL)
return true;
- return makeSortDirection(std::less<CompareFilesResult>(), Int2Type<ascending>())(a.getCategory(), b.getCategory());
+ return makeSortDirection(std::less<CompareFilesResult>(), zen::Int2Type<ascending>())(a.getCategory(), b.getCategory());
}
template <bool ascending> inline
bool lessSyncDirection(const FileSystemObject& a, const FileSystemObject& b)
{
- return makeSortDirection(std::less<>(), Int2Type<ascending>())(a.getSyncOperation(), b.getSyncOperation());
+ return makeSortDirection(std::less<>(), zen::Int2Type<ascending>())(a.getSyncOperation(), b.getSyncOperation());
}
}
diff --git a/FreeFileSync/Source/ui/sync_cfg.cpp b/FreeFileSync/Source/ui/sync_cfg.cpp
index 887df0d6..3f73a263 100755
--- a/FreeFileSync/Source/ui/sync_cfg.cpp
+++ b/FreeFileSync/Source/ui/sync_cfg.cpp
@@ -25,7 +25,7 @@
using namespace zen;
-using namespace xmlAccess;
+using namespace fff;
namespace
@@ -1183,7 +1183,7 @@ void ConfigDialog::OnOkay(wxCommandEvent& event)
//########################################################################################
-ReturnSyncConfig::ButtonPressed zen::showSyncConfigDlg(wxWindow* parent,
+ReturnSyncConfig::ButtonPressed fff::showSyncConfigDlg(wxWindow* parent,
SyncConfigPanel panelToShow,
int localPairIndexToShow,
diff --git a/FreeFileSync/Source/ui/sync_cfg.h b/FreeFileSync/Source/ui/sync_cfg.h
index 087cbdd4..9d64ffcf 100755
--- a/FreeFileSync/Source/ui/sync_cfg.h
+++ b/FreeFileSync/Source/ui/sync_cfg.h
@@ -11,7 +11,7 @@
#include "../lib/process_xml.h"
-namespace zen
+namespace fff
{
struct ReturnSyncConfig
{
diff --git a/FreeFileSync/Source/ui/taskbar.cpp b/FreeFileSync/Source/ui/taskbar.cpp
index d5ee9b16..66125d61 100755
--- a/FreeFileSync/Source/ui/taskbar.cpp
+++ b/FreeFileSync/Source/ui/taskbar.cpp
@@ -12,6 +12,7 @@
#endif
using namespace zen;
+using namespace fff;
#if defined HAVE_UBUNTU_UNITY //Ubuntu unity
diff --git a/FreeFileSync/Source/ui/taskbar.h b/FreeFileSync/Source/ui/taskbar.h
index 81d1483b..667d8afd 100755
--- a/FreeFileSync/Source/ui/taskbar.h
+++ b/FreeFileSync/Source/ui/taskbar.h
@@ -20,7 +20,7 @@ Define HAVE_UBUNTU_UNITY and set:
Linker flag: `pkg-config --libs unity`
*/
-namespace zen
+namespace fff
{
class TaskbarNotAvailable {};
diff --git a/FreeFileSync/Source/ui/tray_icon.cpp b/FreeFileSync/Source/ui/tray_icon.cpp
index b86c7af5..98412723 100755
--- a/FreeFileSync/Source/ui/tray_icon.cpp
+++ b/FreeFileSync/Source/ui/tray_icon.cpp
@@ -14,6 +14,7 @@
#include <wx+/image_resources.h>
using namespace zen;
+using namespace fff;
namespace
@@ -79,7 +80,7 @@ wxIcon FfsTrayIcon::ProgressIconGenerator::get(double fraction)
return wxIcon();
const int pixelCount = logo_.GetWidth() * logo_.GetHeight();
- const int startFillPixel = numeric::clampCpy(numeric::round(fraction * pixelCount), 0, pixelCount);
+ const int startFillPixel = numeric::clampCpy<int>(numeric::round(fraction * pixelCount), 0, pixelCount);
if (startPixBuf_ != startFillPixel)
{
@@ -196,16 +197,16 @@ private:
FfsTrayIcon::FfsTrayIcon(const std::function<void()>& onRequestResume) :
- trayIcon(new TaskBarImpl(onRequestResume)),
- iconGenerator(std::make_unique<ProgressIconGenerator>(getResourceImage(L"FFS_tray_24x24").ConvertToImage()))
+ trayIcon_(new TaskBarImpl(onRequestResume)),
+ iconGenerator_(std::make_unique<ProgressIconGenerator>(getResourceImage(L"FFS_tray_24x24").ConvertToImage()))
{
- trayIcon->SetIcon(iconGenerator->get(activeFraction), activeToolTip);
+ trayIcon_->SetIcon(iconGenerator_->get(activeFraction_), activeToolTip_);
}
FfsTrayIcon::~FfsTrayIcon()
{
- trayIcon->dontCallbackAnymore(); //TaskBarImpl has longer lifetime than FfsTrayIcon: avoid callback!
+ trayIcon_->dontCallbackAnymore(); //TaskBarImpl has longer lifetime than FfsTrayIcon: avoid callback!
/*
This is not working correctly on OS X! It seems both wxTaskBarIcon::RemoveIcon() and ~wxTaskBarIcon() are broken and do NOT immediately
@@ -219,21 +220,21 @@ FfsTrayIcon::~FfsTrayIcon()
- if ~wxTaskBarIcon() ran from SyncProgressDialog::closeDirectly() => leaves the icon dangling until user closes this dialog and outter event loop runs!
*/
- trayIcon->RemoveIcon(); //required on Windows: unlike on OS X, wxPendingDelete does not kick in before main event loop!
+ trayIcon_->RemoveIcon(); //required on Windows: unlike on OS X, wxPendingDelete does not kick in before main event loop!
//use wxWidgets delayed destruction: delete during next idle loop iteration (handle late window messages, e.g. when double-clicking)
- wxPendingDelete.Append(trayIcon); //identical to wxTaskBarIconBase::Destroy() in wxWidgets 2.9.5
+ wxPendingDelete.Append(trayIcon_); //identical to wxTaskBarIconBase::Destroy() in wxWidgets 2.9.5
}
void FfsTrayIcon::setToolTip(const wxString& toolTip)
{
- activeToolTip = toolTip;
- trayIcon->SetIcon(iconGenerator->get(activeFraction), activeToolTip); //another wxWidgets design bug: non-orthogonal method!
+ activeToolTip_ = toolTip;
+ trayIcon_->SetIcon(iconGenerator_->get(activeFraction_), activeToolTip_); //another wxWidgets design bug: non-orthogonal method!
}
void FfsTrayIcon::setProgress(double fraction)
{
- activeFraction = fraction;
- trayIcon->SetIcon(iconGenerator->get(activeFraction), activeToolTip);
+ activeFraction_ = fraction;
+ trayIcon_->SetIcon(iconGenerator_->get(activeFraction_), activeToolTip_);
}
diff --git a/FreeFileSync/Source/ui/tray_icon.h b/FreeFileSync/Source/ui/tray_icon.h
index bb1d0175..e99d5127 100755
--- a/FreeFileSync/Source/ui/tray_icon.h
+++ b/FreeFileSync/Source/ui/tray_icon.h
@@ -11,6 +11,7 @@
#include <memory>
#include <wx/image.h>
+
/*
show tray icon with progress during lifetime of this instance
@@ -21,7 +22,8 @@ ATTENTION: wxWidgets never assumes that an object indirectly destroys itself whi
=> don't derive from wxEvtHandler or any other wxWidgets object here!!!!!!
=> use simple std::function as callback instead => instance may now be safely deleted in callback!
*/
-
+namespace fff
+{
class FfsTrayIcon
{
public:
@@ -36,13 +38,14 @@ private:
FfsTrayIcon& operator=(const FfsTrayIcon&) = delete;
class TaskBarImpl;
- TaskBarImpl* trayIcon;
+ TaskBarImpl* trayIcon_;
class ProgressIconGenerator;
- std::unique_ptr<ProgressIconGenerator> iconGenerator;
+ std::unique_ptr<ProgressIconGenerator> iconGenerator_;
- wxString activeToolTip = L"FreeFileSync";
- double activeFraction = 1;
+ wxString activeToolTip_ = L"FreeFileSync";
+ double activeFraction_ = 1;
};
+}
#endif //TRAY_ICON_H_84217830427534285
diff --git a/FreeFileSync/Source/ui/tree_grid.cpp b/FreeFileSync/Source/ui/tree_grid.cpp
index c64a52cf..b802f294 100755
--- a/FreeFileSync/Source/ui/tree_grid.cpp
+++ b/FreeFileSync/Source/ui/tree_grid.cpp
@@ -19,6 +19,7 @@
#include "../lib/icon_buffer.h"
using namespace zen;
+using namespace fff;
namespace
@@ -156,7 +157,7 @@ void calcPercentage(std::vector<std::pair<uint64_t, int*>>& workList)
}
-Zstring zen::getShortDisplayNameForFolderPair(const AbstractPath& itemPathL, const AbstractPath& itemPathR)
+Zstring fff::getShortDisplayNameForFolderPair(const AbstractPath& itemPathL, const AbstractPath& itemPathR)
{
Zstring commonTrail;
AbstractPath tmpPathL = itemPathL;
@@ -1244,7 +1245,7 @@ private:
}
-void zen::treegrid::init(Grid& grid)
+void treegrid::init(Grid& grid)
{
grid.setDataProvider(std::make_shared<GridDataTree>(grid));
grid.showRowLabel(false);
@@ -1254,7 +1255,7 @@ void zen::treegrid::init(Grid& grid)
}
-TreeView& zen::treegrid::getDataView(Grid& grid)
+TreeView& treegrid::getDataView(Grid& grid)
{
if (auto* prov = dynamic_cast<GridDataTree*>(grid.getDataProvider()))
return prov->getDataView();
@@ -1263,7 +1264,7 @@ TreeView& zen::treegrid::getDataView(Grid& grid)
}
-void zen::treegrid::setShowPercentage(Grid& grid, bool value)
+void treegrid::setShowPercentage(Grid& grid, bool value)
{
if (auto* prov = dynamic_cast<GridDataTree*>(grid.getDataProvider()))
prov->setShowPercentage(value);
@@ -1272,7 +1273,7 @@ void zen::treegrid::setShowPercentage(Grid& grid, bool value)
}
-bool zen::treegrid::getShowPercentage(const Grid& grid)
+bool treegrid::getShowPercentage(const Grid& grid)
{
if (auto* prov = dynamic_cast<const GridDataTree*>(grid.getDataProvider()))
return prov->getShowPercentage();
diff --git a/FreeFileSync/Source/ui/tree_grid.h b/FreeFileSync/Source/ui/tree_grid.h
index 0d69e820..af57070d 100755
--- a/FreeFileSync/Source/ui/tree_grid.h
+++ b/FreeFileSync/Source/ui/tree_grid.h
@@ -14,7 +14,7 @@
#include "../file_hierarchy.h"
-namespace zen
+namespace fff
{
//tree view of FolderComparison
class TreeView
@@ -99,7 +99,7 @@ public:
ptrdiff_t getParent(size_t row) const; //return < 0 if none
void setSortDirection(ColumnTypeTree colType, bool ascending); //apply permanently!
- std::pair<ColumnTypeTree, bool> getSortDirection() { return std::make_pair(sortColumn_, sortAscending_); }
+ std::pair<ColumnTypeTree, bool> getSortDirection() { return { sortColumn_, sortAscending_ }; }
private:
struct DirNodeImpl;
@@ -172,13 +172,14 @@ private:
Zstring getShortDisplayNameForFolderPair(const AbstractPath& itemPathL, const AbstractPath& itemPathR);
+
namespace treegrid
{
-void init(Grid& grid);
-TreeView& getDataView(Grid& grid);
+void init(zen::Grid& grid);
+TreeView& getDataView(zen::Grid& grid);
-void setShowPercentage(Grid& grid, bool value);
-bool getShowPercentage(const Grid& grid);
+void setShowPercentage(zen::Grid& grid, bool value);
+bool getShowPercentage(const zen::Grid& grid);
}
}
diff --git a/FreeFileSync/Source/ui/tree_grid_attr.h b/FreeFileSync/Source/ui/tree_grid_attr.h
index 0c5da30e..ce37e468 100755
--- a/FreeFileSync/Source/ui/tree_grid_attr.h
+++ b/FreeFileSync/Source/ui/tree_grid_attr.h
@@ -11,7 +11,7 @@
#include <cassert>
-namespace zen
+namespace fff
{
enum class ColumnTypeTree
{
diff --git a/FreeFileSync/Source/ui/triple_splitter.cpp b/FreeFileSync/Source/ui/triple_splitter.cpp
index 6a288ca3..0bc43101 100755
--- a/FreeFileSync/Source/ui/triple_splitter.cpp
+++ b/FreeFileSync/Source/ui/triple_splitter.cpp
@@ -9,6 +9,7 @@
#include <zen/stl_tools.h>
using namespace zen;
+using namespace fff;
namespace
@@ -52,7 +53,7 @@ TripleSplitter::~TripleSplitter() {} //make sure correct destructor gets created
void TripleSplitter::updateWindowSizes()
{
- if (windowL && windowC && windowR)
+ if (windowL_ && windowC_ && windowR_)
{
const int centerPosX = getCenterPosX();
const int centerWidth = getCenterWidth();
@@ -63,9 +64,9 @@ void TripleSplitter::updateWindowSizes()
const int windowRposX = widthL + centerWidth;
const int widthR = clientRect.width - windowRposX;
- windowL->SetSize(0, 0, widthL, clientRect.height);
- windowC->SetSize(widthL + SASH_SIZE, 0, windowC->GetSize().GetWidth(), clientRect.height);
- windowR->SetSize(windowRposX, 0, widthR, clientRect.height);
+ windowL_->SetSize(0, 0, widthL, clientRect.height);
+ windowC_->SetSize(widthL + SASH_SIZE, 0, windowC_->GetSize().GetWidth(), clientRect.height);
+ windowR_->SetSize(windowRposX, 0, widthR, clientRect.height);
wxClientDC dc(this);
drawSash(dc);
@@ -100,7 +101,7 @@ private:
inline
int TripleSplitter::getCenterWidth() const
{
- return 2 * SASH_SIZE + (windowC ? windowC->GetSize().GetWidth() : 0);
+ return 2 * SASH_SIZE + (windowC_ ? windowC_->GetSize().GetWidth() : 0);
}
@@ -124,7 +125,7 @@ int TripleSplitter::getCenterPosX() const
return centerPosXOptimal + CHILD_WINDOW_MIN_SIZE - static_cast<int>(2 * CHILD_WINDOW_MIN_SIZE * SASH_GRAVITY); //avoid rounding error
//make sure transition between conditional branches is continuous!
return std::max(CHILD_WINDOW_MIN_SIZE, //make sure centerPosXOptimal + offset is within bounds
- std::min(centerPosXOptimal + centerOffset, clientRect.width - CHILD_WINDOW_MIN_SIZE - centerWidth));
+ std::min(centerPosXOptimal + centerOffset_, clientRect.width - CHILD_WINDOW_MIN_SIZE - centerWidth));
}
@@ -168,32 +169,32 @@ bool TripleSplitter::hitOnSashLine(int posX) const
void TripleSplitter::onMouseLeftDown(wxMouseEvent& event)
{
- activeMove.reset();
+ activeMove_.reset();
const int posX = event.GetPosition().x;
if (hitOnSashLine(posX))
- activeMove = std::make_unique<SashMove>(*this, posX, centerOffset);
+ activeMove_ = std::make_unique<SashMove>(*this, posX, centerOffset_);
event.Skip();
}
void TripleSplitter::onMouseLeftUp(wxMouseEvent& event)
{
- activeMove.reset(); //nothing else to do, actual work done by onMouseMovement()
+ activeMove_.reset(); //nothing else to do, actual work done by onMouseMovement()
event.Skip();
}
void TripleSplitter::onMouseMovement(wxMouseEvent& event)
{
- if (activeMove)
+ if (activeMove_)
{
- centerOffset = activeMove->getCenterOffsetStart() + event.GetPosition().x - activeMove->getMousePosXStart();
+ centerOffset_ = activeMove_->getCenterOffsetStart() + event.GetPosition().x - activeMove_->getMousePosXStart();
//CAVEAT: function getCenterPosX() normalizes centerPosX *not* centerOffset!
//This can lead to the strange effect of window not immediately resizing when centerOffset is extremely off limits
//=> normalize centerOffset right here
- centerOffset = getCenterPosX() - getCenterPosXOptimal();
+ centerOffset_ = getCenterPosX() - getCenterPosXOptimal();
updateWindowSizes();
Update(); //no time to wait until idle event!
@@ -214,7 +215,7 @@ void TripleSplitter::onMouseMovement(wxMouseEvent& event)
void TripleSplitter::onLeaveWindow(wxMouseEvent& event)
{
//even called when moving from sash over to managed windows!
- if (!activeMove)
+ if (!activeMove_)
SetCursor(*wxSTANDARD_CURSOR);
event.Skip();
}
@@ -222,7 +223,7 @@ void TripleSplitter::onLeaveWindow(wxMouseEvent& event)
void TripleSplitter::onMouseCaptureLost(wxMouseCaptureLostEvent& event)
{
- activeMove.reset();
+ activeMove_.reset();
updateWindowSizes();
//event.Skip(); -> we DID handle it!
}
@@ -233,7 +234,7 @@ void TripleSplitter::onMouseLeftDouble(wxMouseEvent& event)
const int posX = event.GetPosition().x;
if (hitOnSashLine(posX))
{
- centerOffset = 0; //reset sash according to gravity
+ centerOffset_ = 0; //reset sash according to gravity
updateWindowSizes();
}
event.Skip();
diff --git a/FreeFileSync/Source/ui/triple_splitter.h b/FreeFileSync/Source/ui/triple_splitter.h
index c93e478e..f14e8039 100755
--- a/FreeFileSync/Source/ui/triple_splitter.h
+++ b/FreeFileSync/Source/ui/triple_splitter.h
@@ -12,7 +12,6 @@
#include <wx/window.h>
#include <wx/dcclient.h>
-//a not-so-crappy splitter window
/* manage three contained windows:
1. left and right window are stretched
@@ -24,8 +23,7 @@
| | | |
-----------------
*/
-
-namespace zen
+namespace fff
{
class TripleSplitter : public wxWindow
{
@@ -41,14 +39,14 @@ public:
void setupWindows(wxWindow* winL, wxWindow* winC, wxWindow* winR)
{
assert(winL->GetParent() == this && winC->GetParent() == this && winR->GetParent() == this && !GetSizer());
- windowL = winL;
- windowC = winC;
- windowR = winR;
+ windowL_ = winL;
+ windowC_ = winC;
+ windowR_ = winR;
updateWindowSizes();
}
- int getSashOffset() const { return centerOffset; }
- void setSashOffset(int off) { centerOffset = off; updateWindowSizes(); }
+ int getSashOffset() const { return centerOffset_; }
+ void setSashOffset(int off) { centerOffset_ = off; updateWindowSizes(); }
private:
void onEraseBackGround(wxEraseEvent& event) {}
@@ -76,13 +74,13 @@ private:
void onMouseLeftDouble(wxMouseEvent& event);
class SashMove;
- std::unique_ptr<SashMove> activeMove;
+ std::unique_ptr<SashMove> activeMove_;
- int centerOffset = 0; //offset to add after "gravity" stretching
+ int centerOffset_ = 0; //offset to add after "gravity" stretching
- wxWindow* windowL = nullptr;
- wxWindow* windowC = nullptr;
- wxWindow* windowR = nullptr;
+ wxWindow* windowL_ = nullptr;
+ wxWindow* windowC_ = nullptr;
+ wxWindow* windowR_ = nullptr;
};
}
diff --git a/FreeFileSync/Source/ui/version_check.cpp b/FreeFileSync/Source/ui/version_check.cpp
index 265b6e38..9b241c7d 100755
--- a/FreeFileSync/Source/ui/version_check.cpp
+++ b/FreeFileSync/Source/ui/version_check.cpp
@@ -22,6 +22,7 @@
using namespace zen;
+using namespace fff;
namespace
@@ -65,7 +66,7 @@ std::vector<std::pair<std::string, std::string>> geHttpPostParameters()
assert(std::this_thread::get_id() == mainThreadId); //this function is not thread-safe, e.g. consider wxWidgets usage in isPortableVersion()
std::vector<std::pair<std::string, std::string>> params;
- params.emplace_back("ffs_version", zen::ffsVersion);
+ params.emplace_back("ffs_version", ffsVersion);
params.emplace_back("installation_type", isPortableVersion() ? "Portable" : "Local");
@@ -102,10 +103,11 @@ void showUpdateAvailableDialog(wxWindow* parent, const std::string& onlineVersio
std::wstring updateDetailsMsg;
try
{
- try //harmonize with wxHTTP: get_latest_changes.php must be accessible without https!!!
+ try
{
+ //consider wxHTTP limitation: URL must be accessible without https!!!
const std::string buf = sendHttpPost(L"http://www.freefilesync.org/get_latest_changes.php", ffsUpdateCheckUserAgent,
- nullptr /*notifyUnbufferedIO*/, { { "since", zen::ffsVersion } }).readAll(); //throw SysError
+ nullptr /*notifyUnbufferedIO*/, { { "since", ffsVersion } }).readAll(); //throw SysError
updateDetailsMsg = utfTo<std::wstring>(buf);
}
catch (const zen::SysError& e) { throw FileError(_("Failed to retrieve update information."), e.toString()); }
@@ -135,7 +137,7 @@ void showUpdateAvailableDialog(wxWindow* parent, const std::string& onlineVersio
//access is thread-safe on Windows (WinInet), but not on Linux/OS X (wxWidgets)
std::string getOnlineVersion(const std::vector<std::pair<std::string, std::string>>& postParams) //throw SysError
{
- //harmonize with wxHTTP: get_latest_version_number.php must be accessible without https!!!
+ //consider wxHTTP limitation: URL must be accessible without https!!!
const std::string buffer = sendHttpPost(L"http://www.freefilesync.org/get_latest_version_number.php", ffsUpdateCheckUserAgent,
nullptr /*notifyUnbufferedIO*/, postParams).readAll(); //throw SysError
return trimCpy(buffer);
@@ -152,9 +154,9 @@ std::vector<size_t> parseVersion(const std::string& version)
}
-bool zen::haveNewerVersionOnline(const std::string& onlineVersion)
+bool fff::haveNewerVersionOnline(const std::string& onlineVersion)
{
- const std::vector<size_t> current = parseVersion(zen::ffsVersion);
+ const std::vector<size_t> current = parseVersion(ffsVersion);
const std::vector<size_t> online = parseVersion(onlineVersion);
if (online.empty() || online[0] == 0) //online version string may be "This website has been moved..." In this case better check for an update
@@ -165,19 +167,19 @@ bool zen::haveNewerVersionOnline(const std::string& onlineVersion)
}
-bool zen::updateCheckActive(time_t lastUpdateCheck)
+bool fff::updateCheckActive(time_t lastUpdateCheck)
{
return lastUpdateCheck != getVersionCheckInactiveId();
}
-void zen::disableUpdateCheck(time_t& lastUpdateCheck)
+void fff::disableUpdateCheck(time_t& lastUpdateCheck)
{
lastUpdateCheck = getVersionCheckInactiveId();
}
-void zen::checkForUpdateNow(wxWindow* parent, std::string& lastOnlineVersion)
+void fff::checkForUpdateNow(wxWindow* parent, std::string& lastOnlineVersion)
{
try
{
@@ -229,19 +231,19 @@ void zen::checkForUpdateNow(wxWindow* parent, std::string& lastOnlineVersion)
}
-struct zen::UpdateCheckResultPrep
+struct fff::UpdateCheckResultPrep
{
const std::vector<std::pair<std::string, std::string>> postParameters { geHttpPostParameters() };
};
//run on main thread:
-std::shared_ptr<UpdateCheckResultPrep> zen::automaticUpdateCheckPrepare()
+std::shared_ptr<UpdateCheckResultPrep> fff::automaticUpdateCheckPrepare()
{
return nullptr;
}
-struct zen::UpdateCheckResult
+struct fff::UpdateCheckResult
{
UpdateCheckResult() {}
UpdateCheckResult(const std::string& ver, const Opt<zen::SysError>& err, bool alive) : onlineVersion(ver), error(err), internetIsAlive(alive) {}
@@ -252,14 +254,14 @@ struct zen::UpdateCheckResult
};
//run on worker thread:
-std::shared_ptr<UpdateCheckResult> zen::automaticUpdateCheckRunAsync(const UpdateCheckResultPrep* resultPrep)
+std::shared_ptr<UpdateCheckResult> fff::automaticUpdateCheckRunAsync(const UpdateCheckResultPrep* resultPrep)
{
return nullptr;
}
//run on main thread:
-void zen::automaticUpdateCheckEval(wxWindow* parent, time_t& lastUpdateCheck, std::string& lastOnlineVersion, const UpdateCheckResult* resultAsync)
+void fff::automaticUpdateCheckEval(wxWindow* parent, time_t& lastUpdateCheck, std::string& lastOnlineVersion, const UpdateCheckResult* resultAsync)
{
UpdateCheckResult result;
try
@@ -267,7 +269,7 @@ void zen::automaticUpdateCheckEval(wxWindow* parent, time_t& lastUpdateCheck, st
result.onlineVersion = getOnlineVersion(geHttpPostParameters()); //throw SysError
result.internetIsAlive = true;
}
- catch (const SysError& e)
+ catch (const zen::SysError& e)
{
result.error = e;
result.internetIsAlive = internetIsAlive();
diff --git a/FreeFileSync/Source/ui/version_check.h b/FreeFileSync/Source/ui/version_check.h
index 2e306747..75cef84e 100755
--- a/FreeFileSync/Source/ui/version_check.h
+++ b/FreeFileSync/Source/ui/version_check.h
@@ -11,7 +11,8 @@
#include <memory>
#include <wx/window.h>
-namespace zen
+
+namespace fff
{
bool updateCheckActive (time_t lastUpdateCheck);
void disableUpdateCheck(time_t& lastUpdateCheck);
diff --git a/FreeFileSync/Source/ui/version_check_impl.h b/FreeFileSync/Source/ui/version_check_impl.h
index 5ced0190..b33bb55b 100755..100644
--- a/FreeFileSync/Source/ui/version_check_impl.h
+++ b/FreeFileSync/Source/ui/version_check_impl.h
@@ -12,7 +12,7 @@
#include "../version/version.h"
-namespace zen
+namespace fff
{
inline
time_t getVersionCheckInactiveId()
@@ -20,7 +20,7 @@ time_t getVersionCheckInactiveId()
//use current version to calculate a changing number for the inactive state near UTC begin, in order to always check for updates after installing a new version
//=> convert version into 11-based *unique* number (this breaks lexicographical version ordering, but that's irrelevant!)
int id = 0;
- const char* first = zen::ffsVersion;
+ const char* first = ffsVersion;
const char* last = first + zen::strLength(ffsVersion);
std::for_each(first, last, [&](char c)
{
diff --git a/FreeFileSync/Source/version/version.h b/FreeFileSync/Source/version/version.h
index 5fc0f704..44e25841 100755
--- a/FreeFileSync/Source/version/version.h
+++ b/FreeFileSync/Source/version/version.h
@@ -1,9 +1,9 @@
#ifndef VERSION_HEADER_434343489702544325
#define VERSION_HEADER_434343489702544325
-namespace zen
+namespace fff
{
-const char ffsVersion[] = "9.7"; //internal linkage!
+const char ffsVersion[] = "9.8"; //internal linkage!
const char FFS_VERSION_SEPARATOR = '.';
}
diff --git a/wx+/app_main.h b/wx+/app_main.h
index d9559fea..8d2a6eeb 100755
--- a/wx+/app_main.h
+++ b/wx+/app_main.h
@@ -10,6 +10,7 @@
#include <wx/window.h>
#include <wx/app.h>
+
namespace zen
{
//just some wrapper around a global variable representing the (logical) main application window
@@ -22,12 +23,16 @@ bool mainWindowWasSet();
//######################## implementation ########################
+namespace impl
+{
inline
bool& refMainWndStatus()
{
static bool status = false; //external linkage!
return status;
}
+}
+
inline
void setMainWindow(wxWindow* window)
@@ -35,10 +40,10 @@ void setMainWindow(wxWindow* window)
wxTheApp->SetTopWindow(window);
wxTheApp->SetExitOnFrameDelete(true);
- refMainWndStatus() = true;
+ impl::refMainWndStatus() = true;
}
-inline bool mainWindowWasSet() { return refMainWndStatus(); }
+inline bool mainWindowWasSet() { return impl::refMainWndStatus(); }
}
#endif //APP_MAIN_H_08215601837818347575856
diff --git a/wx+/choice_enum.h b/wx+/choice_enum.h
index a19e1457..6b2edd01 100755
--- a/wx+/choice_enum.h
+++ b/wx+/choice_enum.h
@@ -33,7 +33,6 @@ Update enum tooltips (after user changed selection):
updateTooltipEnumVal(enumDescrMap, *m_choiceHandleError);
*/
-
namespace zen
{
template <class Enum>
@@ -41,7 +40,7 @@ struct EnumDescrList
{
EnumDescrList& add(Enum value, const wxString& text, const wxString& tooltip = {})
{
- descrList.emplace_back(value, std::make_pair(text, tooltip));
+ descrList.push_back({ value, { text, tooltip } });
return *this;
}
using DescrList = std::vector<std::pair<Enum, std::pair<wxString, wxString>>>;
diff --git a/wx+/context_menu.h b/wx+/context_menu.h
index de351df4..7f459aca 100755
--- a/wx+/context_menu.h
+++ b/wx+/context_menu.h
@@ -22,7 +22,6 @@ Usage:
...
menu.popup(wnd);
*/
-
namespace zen
{
class ContextMenu : private wxEvtHandler
diff --git a/wx+/dc.h b/wx+/dc.h
index ff182b6a..55047a53 100755
--- a/wx+/dc.h
+++ b/wx+/dc.h
@@ -11,6 +11,7 @@
#include <zen/optional.h>
#include <wx/dcbuffer.h> //for macro: wxALWAYS_NATIVE_DOUBLE_BUFFER
+
namespace zen
{
/*
diff --git a/wx+/graph.cpp b/wx+/graph.cpp
index b81896b4..dbce3769 100755
--- a/wx+/graph.cpp
+++ b/wx+/graph.cpp
@@ -539,8 +539,6 @@ void Graph2D::addCurve(const std::shared_ptr<CurveData>& data, const CurveAttrib
void Graph2D::render(wxDC& dc) const
{
- using namespace numeric;
-
//set label font right at the start so that it is considered by wxDC::GetTextExtent() below!
dc.SetFont(labelFont_);
@@ -722,10 +720,10 @@ void Graph2D::render(wxDC& dc) const
const wxPoint screenCurrent = activeSel_->refCurrentPos() - graphAreaOrigin;
//normalize positions: a mouse selection is symmetric and *not* an half-open range!
- double screenFromX = clampCpy(screenStart .x, 0, graphArea.width - 1);
- double screenFromY = clampCpy(screenStart .y, 0, graphArea.height - 1);
- double screenToX = clampCpy(screenCurrent.x, 0, graphArea.width - 1);
- double screenToY = clampCpy(screenCurrent.y, 0, graphArea.height - 1);
+ double screenFromX = numeric::clampCpy(screenStart .x, 0, graphArea.width - 1);
+ double screenFromY = numeric::clampCpy(screenStart .y, 0, graphArea.height - 1);
+ double screenToX = numeric::clampCpy(screenCurrent.x, 0, graphArea.width - 1);
+ double screenToY = numeric::clampCpy(screenCurrent.y, 0, graphArea.height - 1);
widen(&screenFromX, &screenToX); //use full pixel range for selection!
widen(&screenFromY, &screenToY);
@@ -780,10 +778,10 @@ void Graph2D::render(wxDC& dc) const
shrink(&screenFromX, &screenToX);
shrink(&screenFromY, &screenToY);
- clamp(screenFromX, 0.0, graphArea.width - 1.0);
- clamp(screenFromY, 0.0, graphArea.height - 1.0);
- clamp(screenToX, 0.0, graphArea.width - 1.0);
- clamp(screenToY, 0.0, graphArea.height - 1.0);
+ numeric::clamp(screenFromX, 0.0, graphArea.width - 1.0);
+ numeric::clamp(screenFromY, 0.0, graphArea.height - 1.0);
+ numeric::clamp(screenToX, 0.0, graphArea.width - 1.0);
+ numeric::clamp(screenToY, 0.0, graphArea.height - 1.0);
const wxPoint pixelFrom = wxPoint(numeric::round(screenFromX),
numeric::round(screenFromY)) + graphAreaOrigin;
diff --git a/wx+/graph.h b/wx+/graph.h
index 5c71ed52..45129c4b 100755
--- a/wx+/graph.h
+++ b/wx+/graph.h
@@ -16,8 +16,8 @@
#include <zen/string_tools.h>
#include <zen/optional.h>
-//elegant 2D graph as wxPanel specialization
+//elegant 2D graph as wxPanel specialization
namespace zen
{
/*
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index b301bf6b..64f7f4a6 100755
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -462,8 +462,8 @@ public:
const int yFrom = refParent().CalcUnscrolledPosition(clientRect.GetTopLeft ()).y;
const int yTo = refParent().CalcUnscrolledPosition(clientRect.GetBottomRight()).y;
- return std::make_pair(std::max(yFrom / rowHeight_, 0),
- std::min<ptrdiff_t>((yTo / rowHeight_) + 1, refParent().getRowCount()));
+ return { std::max(yFrom / rowHeight_, 0),
+ std::min<ptrdiff_t>((yTo / rowHeight_) + 1, refParent().getRowCount()) };
}
private:
@@ -1269,7 +1269,7 @@ private:
ColLabelWin& colLabelWin_;
std::unique_ptr<MouseSelection> activeSelection_; //bound while user is selecting with mouse
- MouseHighlight highlight_; //current mouse highlight_ (superseeded by activeSelection_ if available)
+ MouseHighlight highlight_; //current mouse highlight_ (superseded by activeSelection_ if available)
ptrdiff_t cursorRow_ = 0;
size_t selectionAnchor_ = 0;
diff --git a/wx+/grid.h b/wx+/grid.h
index 8b916f2f..a5c1a783 100755
--- a/wx+/grid.h
+++ b/wx+/grid.h
@@ -14,8 +14,8 @@
#include <zen/basic_math.h>
#include <zen/optional.h>
-//a user-friendly, extensible and high-performance grid control
+//a user-friendly, extensible and high-performance grid control
namespace zen
{
enum class ColumnType { NONE = -1 }; //user-defiend column type
diff --git a/wx+/http.cpp b/wx+/http.cpp
index fa88bb1d..1526d30f 100755
--- a/wx+/http.cpp
+++ b/wx+/http.cpp
@@ -33,9 +33,9 @@ public:
{
ZEN_ON_SCOPE_FAIL( cleanup(); /*destructor call would lead to member double clean-up!!!*/ );
- assert(!startsWith(url, L"https:", CmpAsciiNoCase())); //not supported by wxHTTP!
- const std::wstring urlFmt = startsWith(url, L"http://", CmpAsciiNoCase()) ||
- startsWith(url, L"https://", CmpAsciiNoCase()) ? afterFirst(url, L"://", IF_MISSING_RETURN_NONE) : url;
+ //assert(!startsWith(url, L"https:", CmpAsciiNoCase())); //not supported by wxHTTP!
+
+ const std::wstring urlFmt = afterFirst(url, L"://", IF_MISSING_RETURN_NONE);
const std::wstring server = beforeFirst(urlFmt, L'/', IF_MISSING_RETURN_ALL);
const std::wstring page = L'/' + afterFirst(urlFmt, L'/', IF_MISSING_RETURN_NONE);
diff --git a/wx+/http.h b/wx+/http.h
index aba6b96d..bbfa3a74 100755
--- a/wx+/http.h
+++ b/wx+/http.h
@@ -15,7 +15,7 @@ namespace zen
/*
TREAD-SAFETY
------------
- Windows: WinInet-based => may be called from worker thread
+ Windows: WinInet-based => may be called from worker thread, supports HTTPS
Linux: wxWidgets-based => don't call from worker thread
*/
class HttpInputStream
diff --git a/wx+/image_resources.h b/wx+/image_resources.h
index 3c3bf39c..cc4ab2cc 100755
--- a/wx+/image_resources.h
+++ b/wx+/image_resources.h
@@ -11,6 +11,7 @@
#include <wx/animate.h>
#include <zen/zstring.h>
+
namespace zen
{
void initResourceImages(const Zstring& filepath); //pass resources .zip file at application startup
diff --git a/wx+/no_flicker.h b/wx+/no_flicker.h
index f9bf862b..03969c00 100755
--- a/wx+/no_flicker.h
+++ b/wx+/no_flicker.h
@@ -10,6 +10,7 @@
#include <wx/textctrl.h>
#include <wx/stattext.h>
+
namespace zen
{
inline
diff --git a/wx+/rtl.h b/wx+/rtl.h
index 1e775c79..e479c5a8 100755
--- a/wx+/rtl.h
+++ b/wx+/rtl.h
@@ -12,6 +12,7 @@
#include <wx/image.h>
#include <wx/app.h>
+
namespace zen
{
//functions supporting right-to-left GUI layout
diff --git a/wx+/toggle_button.h b/wx+/toggle_button.h
index 0172881e..f61c3857 100755
--- a/wx+/toggle_button.h
+++ b/wx+/toggle_button.h
@@ -10,6 +10,9 @@
#include <wx/bmpbuttn.h>
#include <wx+/bitmap_button.h>
+
+namespace zen
+{
class ToggleButton : public wxBitmapButton
{
public:
@@ -29,12 +32,11 @@ public:
const wxBitmap& inactiveBmp);
void setActive(bool value);
- bool isActive() const { return active; }
- void toggle() { setActive(!active); }
+ bool isActive() const { return active_; }
+ void toggle() { setActive(!active_); }
private:
- bool active = false;
-
+ bool active_ = false;
wxBitmap activeBmp_;
wxBitmap inactiveBmp_;
};
@@ -53,15 +55,16 @@ void ToggleButton::init(const wxBitmap& activeBmp,
activeBmp_ = activeBmp;
inactiveBmp_ = inactiveBmp;
- setActive(active);
+ setActive(active_);
}
inline
void ToggleButton::setActive(bool value)
{
- active = value;
- zen::setImage(*this, active ? activeBmp_ : inactiveBmp_);
+ active_ = value;
+ setImage(*this, active_ ? activeBmp_ : inactiveBmp_);
+}
}
#endif //TOGGLE_BUTTON_H_8173024810574556
diff --git a/zen/basic_math.h b/zen/basic_math.h
index 1b6b7e97..16f69bde 100755
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -31,7 +31,7 @@ template <class T> T clampCpy(T val, T minVal, T maxVal);
template <class T, class InputIterator> //precondition: range must be sorted!
auto nearMatch(const T& val, InputIterator first, InputIterator last);
-int round(double d); //"little rounding function"
+int64_t round(double d); //"little rounding function"
template <class N, class D>
auto integerDivideRoundUp(N numerator, D denominator);
@@ -182,7 +182,7 @@ std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, Input
}
}
}
- return std::make_pair(lowest, largest);
+ return { lowest, largest };
}
@@ -220,20 +220,20 @@ bool isNull(T value)
inline
-int round(double d)
+int64_t round(double d)
{
- assert(d - 0.5 >= std::numeric_limits<int>::min() && //if double is larger than what int can represent:
- d + 0.5 <= std::numeric_limits<int>::max()); //=> undefined behavior!
- return static_cast<int>(d < 0 ? d - 0.5 : d + 0.5);
+ assert(d - 0.5 >= std::numeric_limits<int64_t>::min() && //if double is larger than what int can represent:
+ d + 0.5 <= std::numeric_limits<int64_t>::max()); //=> undefined behavior!
+ return static_cast<int64_t>(d < 0 ? d - 0.5 : d + 0.5);
}
template <class N, class D> inline
auto integerDivideRoundUp(N numerator, D denominator)
{
- static_assert(std::is_integral<N>::value && std::is_unsigned<N>::value, "");
- static_assert(std::is_integral<D>::value && std::is_unsigned<D>::value, "");
- assert(denominator > 0);
+ static_assert(std::is_integral<N>::value, "");
+ static_assert(std::is_integral<D>::value, "");
+ assert(numerator > 0 && denominator > 0);
return (numerator + denominator - 1) / denominator;
}
diff --git a/zen/build_info.h b/zen/build_info.h
index 7b0aa9cf..9b8b7fc0 100755
--- a/zen/build_info.h
+++ b/zen/build_info.h
@@ -7,8 +7,6 @@
#ifndef BUILD_INFO_H_5928539285603428657
#define BUILD_INFO_H_5928539285603428657
-namespace zen
-{
//determine build info: defines ZEN_BUILD_32BIT or ZEN_BUILD_64BIT
#ifdef __LP64__
@@ -24,6 +22,5 @@ namespace zen
#ifdef ZEN_BUILD_64BIT
static_assert(sizeof(void*) == 8, "");
#endif
-}
#endif //BUILD_INFO_H_5928539285603428657
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 17f2244d..0cbde150 100755
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -30,11 +30,11 @@ struct DirWatcher::Impl
DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
- baseDirPath(dirPath),
+ baseDirPath_(dirPath),
pimpl_(std::make_unique<Impl>())
{
//get all subdirectories
- std::vector<Zstring> fullFolderList { baseDirPath };
+ std::vector<Zstring> fullFolderList { baseDirPath_ };
{
std::function<void (const Zstring& path)> traverse;
@@ -46,13 +46,13 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
[&](const std::wstring& errorMsg) { throw FileError(errorMsg); });
};
- traverse(baseDirPath);
+ traverse(baseDirPath_);
}
//init
pimpl_->notifDescr = ::inotify_init();
if (pimpl_->notifDescr == -1)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"inotify_init");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath_)), L"inotify_init");
ZEN_ON_SCOPE_FAIL( ::close(pimpl_->notifDescr); );
@@ -64,7 +64,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
initSuccess = ::fcntl(pimpl_->notifDescr, F_SETFL, flags | O_NONBLOCK) != -1;
}
if (!initSuccess)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"fcntl");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath_)), L"fcntl");
//add watches
for (const Zstring& subDirPath : fullFolderList)
@@ -101,7 +101,7 @@ DirWatcher::~DirWatcher()
}
-std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&) //throw FileError
+std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>& requestUiRefresh, std::chrono::milliseconds cbInterval) //throw FileError
{
std::vector<char> buffer(512 * (sizeof(struct ::inotify_event) + NAME_MAX + 1));
@@ -118,7 +118,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
if (errno == EAGAIN) //this error is ignored in all inotify wrappers I found
return std::vector<Entry>();
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"read");
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath_)), L"read");
}
std::vector<Entry> output;
@@ -135,19 +135,19 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
{
//Note: evt.len is NOT the size of the evt.name c-string, but the array size including all padding 0 characters!
//It may be even 0 in which case evt.name must not be used!
- const Zstring fullname = it->second + evt.name;
+ const Zstring itemPath = it->second + evt.name;
if ((evt.mask & IN_CREATE) ||
(evt.mask & IN_MOVED_TO))
- output.emplace_back(ACTION_CREATE, fullname);
+ output.push_back({ ACTION_CREATE, itemPath });
else if ((evt.mask & IN_MODIFY) ||
(evt.mask & IN_CLOSE_WRITE))
- output.emplace_back(ACTION_UPDATE, fullname);
+ output.push_back({ ACTION_UPDATE, itemPath });
else if ((evt.mask & IN_DELETE ) ||
(evt.mask & IN_DELETE_SELF) ||
(evt.mask & IN_MOVE_SELF ) ||
(evt.mask & IN_MOVED_FROM))
- output.emplace_back(ACTION_DELETE, fullname);
+ output.push_back({ ACTION_DELETE, itemPath });
}
}
bytePos += sizeof(struct ::inotify_event) + evt.len;
diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h
index 8045d184..b4796618 100755
--- a/zen/dir_watcher.h
+++ b/zen/dir_watcher.h
@@ -9,6 +9,7 @@
#include <vector>
#include <memory>
+#include <chrono>
#include <functional>
#include "file_error.h"
@@ -50,26 +51,22 @@ public:
struct Entry
{
- Entry() {}
- Entry(ActionType action, const Zstring& filepath) : action_(action), filepath_(filepath) {}
-
- ActionType action_ = ACTION_CREATE;
- Zstring filepath_;
+ ActionType action = ACTION_CREATE;
+ Zstring filePath;
};
//extract accumulated changes since last call
- std::vector<Entry> getChanges(const std::function<void()>& processGuiMessages); //throw FileError
+ std::vector<Entry> getChanges(const std::function<void()>& requestUiRefresh, std::chrono::milliseconds cbInterval); //throw FileError
private:
DirWatcher (const DirWatcher&) = delete;
DirWatcher& operator=(const DirWatcher&) = delete;
- const Zstring baseDirPath;
+ const Zstring baseDirPath_;
struct Impl;
const std::unique_ptr<Impl> pimpl_;
};
-
}
#endif
diff --git a/zen/error_log.h b/zen/error_log.h
index 1fcbdefb..b6660850 100755
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -20,18 +20,18 @@ namespace zen
{
enum MessageType
{
- TYPE_INFO = 0x1,
- TYPE_WARNING = 0x2,
- TYPE_ERROR = 0x4,
- TYPE_FATAL_ERROR = 0x8,
+ MSG_TYPE_INFO = 0x1,
+ MSG_TYPE_WARNING = 0x2,
+ MSG_TYPE_ERROR = 0x4,
+ MSG_TYPE_FATAL_ERROR = 0x8,
};
using MsgString = Zbase<wchar_t>; //std::wstring may employ small string optimization: we cannot accept bloating the "ErrorLog::entries" memory block below (think 1 million items)
struct LogEntry
{
- time_t time;
- MessageType type;
+ time_t time = 0;
+ MessageType type = MSG_TYPE_FATAL_ERROR;
MsgString message;
};
@@ -45,7 +45,7 @@ public:
template <class String> //a wchar_t-based string!
void logMsg(const String& text, MessageType type);
- int getItemCount(int typeFilter = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const;
+ int getItemCount(int typeFilter = MSG_TYPE_INFO | MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) const;
//subset of std::vector<> interface:
using const_iterator = std::vector<LogEntry>::const_iterator;
@@ -67,10 +67,9 @@ private:
//######################## implementation ##########################
template <class String> inline
-void ErrorLog::logMsg(const String& text, zen::MessageType type)
+void ErrorLog::logMsg(const String& text, MessageType type)
{
- const LogEntry newEntry = { std::time(nullptr), type, copyStringTo<MsgString>(text) };
- entries_.push_back(newEntry);
+ entries_.push_back({ std::time(nullptr), type, copyStringTo<MsgString>(text) });
}
@@ -90,13 +89,13 @@ String formatMessageImpl(const LogEntry& entry) //internal linkage
{
switch (entry.type)
{
- case TYPE_INFO:
+ case MSG_TYPE_INFO:
return _("Info");
- case TYPE_WARNING:
+ case MSG_TYPE_WARNING:
return _("Warning");
- case TYPE_ERROR:
+ case MSG_TYPE_ERROR:
return _("Error");
- case TYPE_FATAL_ERROR:
+ case MSG_TYPE_FATAL_ERROR:
return _("Serious Error");
}
assert(false);
@@ -104,7 +103,7 @@ String formatMessageImpl(const LogEntry& entry) //internal linkage
};
String formattedText = L"[" + formatTime<String>(FORMAT_TIME, getLocalTime(entry.time)) + L"] " + copyStringTo<String>(getTypeName()) + L": ";
- const size_t prefixLen = formattedText.size();
+ const size_t prefixLen = formattedText.size(); //considers UTF-16 only!
for (auto it = entry.message.begin(); it != entry.message.end(); )
if (*it == L'\n')
diff --git a/zen/file_access.h b/zen/file_access.h
index 743ad15d..c62ddc98 100755
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -13,6 +13,7 @@
#include "file_id_def.h"
#include "serialize.h"
+
namespace zen
{
//note: certain functions require COM initialization! (vista_file_op.h)
diff --git a/zen/file_error.h b/zen/file_error.h
index decc0f7e..086d0998 100755
--- a/zen/file_error.h
+++ b/zen/file_error.h
@@ -12,6 +12,7 @@
#include "utf.h"
#include "sys_error.h" //we'll need this later anyway!
+
namespace zen
{
class FileError //A high-level exception class giving detailed context information for end users
diff --git a/zen/file_id_def.h b/zen/file_id_def.h
index 7772e3e3..f58cb479 100755
--- a/zen/file_id_def.h
+++ b/zen/file_id_def.h
@@ -7,8 +7,6 @@
#ifndef FILE_ID_DEF_H_013287632486321493
#define FILE_ID_DEF_H_013287632486321493
-#include <utility>
-
#include <sys/stat.h>
diff --git a/zen/file_io.h b/zen/file_io.h
index 369cdc01..5b0b8cb0 100755
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -13,7 +13,7 @@
namespace zen
{
- const char LINE_BREAK[] = "\n"; //since OS X apple uses newline, too
+ const char LINE_BREAK[] = "\n"; //since OS X Apple uses newline, too
/*
OS-buffered file IO optimized for
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index aa4c439e..bc53f206 100755
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -55,7 +55,7 @@ void zen::traverseFolder(const Zstring& dirPath,
continue;
const Zstring& itemName = itemNameRaw;
- if (itemName.empty()) //checks result of osx::normalizeUtfForPosix, too!
+ if (itemName.empty()) //checks result of normalizeUtfForPosix, too!
throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name.");
const Zstring& itemPath = appendSeparator(dirPath) + itemName;
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index 19359148..5c1683f8 100755
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -18,8 +18,8 @@ struct FileInfo
{
Zstring itemName;
Zstring fullPath;
- uint64_t fileSize; //[bytes]
- time_t modTime; //number of seconds since Jan. 1st 1970 UTC
+ uint64_t fileSize; //[bytes]
+ time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC
};
struct FolderInfo
@@ -32,7 +32,7 @@ struct SymlinkInfo
{
Zstring itemName;
Zstring fullPath;
- time_t modTime; //number of seconds since Jan. 1st 1970 UTC
+ time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC
};
//- non-recursive
diff --git a/zen/fixed_list.h b/zen/fixed_list.h
index 535ffa31..10b66233 100755
--- a/zen/fixed_list.h
+++ b/zen/fixed_list.h
@@ -11,6 +11,7 @@
#include <iterator>
#include "stl_tools.h"
+
namespace zen
{
//std::list(C++11)-like class for inplace element construction supporting non-copyable/non-movable types
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 0f54a34b..09134c07 100755
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -5,7 +5,6 @@
// *****************************************************************************
#include "format_unit.h"
-//#include <cwchar> //swprintf
#include <ctime>
#include <cstdio>
#include "basic_math.h"
@@ -112,7 +111,7 @@ std::wstring roundToBlock(double timeInHigh,
const int blockSizeLow = granularity * timeInHigh < 1 ?
numeric::nearMatch(granularity * timeInLow, std::begin(stepsLow), std::end(stepsLow)):
numeric::nearMatch(granularity * timeInHigh, std::begin(stepsHigh), std::end(stepsHigh)) * unitLowPerHigh;
- const int roundedtimeInLow = numeric::round(timeInLow / blockSizeLow) * blockSizeLow;
+ const int roundedtimeInLow = static_cast<int>(numeric::round(timeInLow / blockSizeLow) * blockSizeLow);
std::wstring output = formatUnitTime(roundedtimeInLow / unitLowPerHigh, unitHigh);
if (unitLowPerHigh > blockSizeLow)
@@ -162,13 +161,13 @@ std::wstring zen::formatFraction(double fraction)
-std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number)
+std::wstring zen::impl::includeNumberSeparator(const std::wstring& number)
{
//we have to include thousands separator ourselves; this doesn't work for all countries (e.g india), but is better than nothing
//::setlocale (LC_ALL, ""); -> implicitly called by wxLocale
const lconv* localInfo = ::localeconv(); //always bound according to doc
- const std::wstring& thousandSep = utfTo<std::wstring>(localInfo->thousands_sep);
+ const std::wstring& thousandSep = zen::utfTo<std::wstring>(localInfo->thousands_sep);
// THOUSANDS_SEPARATOR = std::use_facet<std::numpunct<wchar_t>>(std::locale("")).thousands_sep(); - why not working?
// DECIMAL_POINT = std::use_facet<std::numpunct<wchar_t>>(std::locale("")).decimal_point();
diff --git a/zen/format_unit.h b/zen/format_unit.h
index 154ec542..9c6a4690 100755
--- a/zen/format_unit.h
+++ b/zen/format_unit.h
@@ -37,7 +37,7 @@ std::wstring formatNumber(NumberType number); //format integer number including
//--------------- inline impelementation -------------------------------------------
-namespace ffs_Impl
+namespace impl
{
std::wstring includeNumberSeparator(const std::wstring& number);
}
@@ -46,7 +46,7 @@ template <class NumberType> inline
std::wstring formatNumber(NumberType number)
{
static_assert(IsInteger<NumberType>::value, "");
- return ffs_Impl::includeNumberSeparator(zen::numberTo<std::wstring>(number));
+ return impl::includeNumberSeparator(zen::numberTo<std::wstring>(number));
}
}
diff --git a/zen/globals.h b/zen/globals.h
index 32781f2a..c57d97ff 100755
--- a/zen/globals.h
+++ b/zen/globals.h
@@ -11,6 +11,7 @@
#include <memory>
#include "scope_guard.h"
+
namespace zen
{
//solve static destruction order fiasco by providing shared ownership and serialized access to global variables
diff --git a/zen/i18n.h b/zen/i18n.h
index bb6dbac5..b67a3bb6 100755
--- a/zen/i18n.h
+++ b/zen/i18n.h
@@ -13,6 +13,7 @@
#include "string_tools.h"
#include "format_unit.h"
+
//minimal layer enabling text translation - without platform/library dependencies!
#define ZEN_TRANS_CONCAT_SUB(X, Y) X ## Y
@@ -55,7 +56,7 @@ std::shared_ptr<const TranslationHandler> getTranslator();
//######################## implementation ##############################
-namespace implementation
+namespace impl
{
inline
Global<const TranslationHandler>& refGlobalTranslationHandler()
@@ -69,14 +70,14 @@ Global<const TranslationHandler>& refGlobalTranslationHandler()
inline
std::shared_ptr<const TranslationHandler> getTranslator()
{
- return implementation::refGlobalTranslationHandler().get();
+ return impl::refGlobalTranslationHandler().get();
}
inline
void setTranslator(std::unique_ptr<const TranslationHandler>&& newHandler)
{
- implementation::refGlobalTranslationHandler().set(std::move(newHandler));
+ impl::refGlobalTranslationHandler().set(std::move(newHandler));
}
diff --git a/zen/optional.h b/zen/optional.h
index a2a1a169..0ef5f1db 100755
--- a/zen/optional.h
+++ b/zen/optional.h
@@ -10,6 +10,7 @@
#include <cassert>
#include <type_traits>
+
namespace zen
{
/*
diff --git a/zen/process_priority.h b/zen/process_priority.h
index bec8f9b5..cfadfff1 100755
--- a/zen/process_priority.h
+++ b/zen/process_priority.h
@@ -10,6 +10,7 @@
#include <memory>
#include "file_error.h"
+
namespace zen
{
//signal a "busy" state to the operating system
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index 2048af9b..6945b011 100755
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -13,7 +13,7 @@
//std::uncaught_exceptions() currently unsupported on GCC and Clang => clean up ASAP
- static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 2 || (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ <= 1))), "check std::uncaught_exceptions support");
+ static_assert(__GNUC__ < 7 || (__GNUC__ == 7 && (__GNUC_MINOR__ < 3 || (__GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ <= 0))), "check std::uncaught_exceptions support");
namespace __cxxabiv1
{
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index 18e4854b..43bede61 100755
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -17,10 +17,10 @@ namespace zen
{
//launch commandline and report errors via popup dialog
//Windows: COM needs to be initialized before calling this function!
-enum ExecutionType
+enum class ExecutionType
{
- EXEC_TYPE_SYNC,
- EXEC_TYPE_ASYNC
+ SYNC,
+ ASYNC
};
namespace
@@ -36,7 +36,7 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError
- uses a zero-sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list in Windows
*/
- if (type == EXEC_TYPE_SYNC)
+ if (type == ExecutionType::SYNC)
{
//Posix ::system() - execute a shell command
const int rv = ::system(command.c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
diff --git a/zen/shutdown.cpp b/zen/shutdown.cpp
index dd02814f..1794e4a8 100755
--- a/zen/shutdown.cpp
+++ b/zen/shutdown.cpp
@@ -18,7 +18,7 @@ void zen::shutdownSystem() //throw FileError
//https://linux.die.net/man/2/reboot => needs admin rights!
//"systemctl" should work without admin rights:
- shellExecute("sleep 1; systemctl poweroff", EXEC_TYPE_ASYNC); //throw FileError
+ shellExecute("sleep 1; systemctl poweroff", ExecutionType::ASYNC); //throw FileError
//sleep 1: give FFS some time to properly shut down!
}
@@ -27,7 +27,7 @@ void zen::shutdownSystem() //throw FileError
void zen::suspendSystem() //throw FileError
{
//"systemctl" should work without admin rights:
- shellExecute("systemctl suspend", EXEC_TYPE_ASYNC); //throw FileError
+ shellExecute("systemctl suspend", ExecutionType::ASYNC); //throw FileError
}
diff --git a/zen/shutdown.h b/zen/shutdown.h
index b9d47df6..df2314f8 100755
--- a/zen/shutdown.h
+++ b/zen/shutdown.h
@@ -9,6 +9,7 @@
#include "file_error.h"
+
namespace zen
{
void shutdownSystem(); //throw FileError
diff --git a/zen/string_base.h b/zen/string_base.h
index 30699c38..2d043d4f 100755
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -13,8 +13,8 @@
#include <atomic>
#include "string_tools.h"
-//Zbase - a policy based string class optimizing performance and flexibility
+//Zbase - a policy based string class optimizing performance and flexibility
namespace zen
{
/*
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 5058f78d..7734b6f0 100755
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -27,6 +27,7 @@ template <class Char> bool isDigit (Char c); //not exactly the same as "std:
template <class Char> bool isHexDigit (Char c);
template <class Char> bool isAsciiAlpha(Char c);
template <class Char> Char asciiToLower(Char c);
+template <class Char> Char asciiToUpper(Char c);
//case-sensitive comparison (compile-time correctness: use different number of arguments as STL comparison predicates!)
struct CmpBinary { template <class Char> int operator()(const Char* lhs, size_t lhsLen, const Char* rhs, size_t rhsLen) const; };
@@ -159,6 +160,15 @@ Char asciiToLower(Char c)
}
+template <class Char> inline
+Char asciiToUpper(Char c)
+{
+ if (static_cast<Char>('a') <= c && c <= static_cast<Char>('z'))
+ return static_cast<Char>(c - static_cast<Char>('a') + static_cast<Char>('A'));
+ return c;
+}
+
+
template <class S, class T, class Function> inline
bool startsWith(const S& str, const T& prefix, Function cmpStringFun)
{
@@ -740,7 +750,7 @@ std::pair<char, char> hexify(unsigned char c, bool upperCase)
else
return static_cast<char>('a' + (num - 10));
};
- return std::make_pair(hexifyDigit(c / 16), hexifyDigit(c % 16));
+ return { hexifyDigit(c / 16), hexifyDigit(c % 16) };
}
diff --git a/zen/string_traits.h b/zen/string_traits.h
index 502250c2..805db46d 100755
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -63,7 +63,7 @@ private:
//---------------------- implementation ----------------------
-namespace implementation
+namespace impl
{
template<class S, class Char> //test if result of S::c_str() can convert to const Char*
class HasConversion
@@ -137,13 +137,13 @@ public:
}
template <class T>
-struct IsStringLike : StaticBool<implementation::StringTraits<T>::isStringLike> {};
+struct IsStringLike : StaticBool<impl::StringTraits<T>::isStringLike> {};
template <class T>
-struct GetCharType : ResultType<typename implementation::StringTraits<T>::CharType> {};
+struct GetCharType : ResultType<typename impl::StringTraits<T>::CharType> {};
-namespace implementation
+namespace impl
{
//strlen/wcslen are vectorized since VS14 CTP3
inline size_t cStringLength(const char* str) { return std::strlen(str); }
@@ -162,7 +162,7 @@ size_t cStringLength(const C* str)
}
#endif
-template <class S, typename = typename EnableIf<implementation::StringTraits<S>::isStringClass>::Type> inline
+template <class S, typename = typename EnableIf<StringTraits<S>::isStringClass>::Type> inline
const typename GetCharType<S>::Type* strBegin(const S& str) //SFINAE: T must be a "string"
{
return str.c_str();
@@ -179,7 +179,7 @@ inline const char* strBegin(const StringRef<const char >& ref) { return ref
inline const wchar_t* strBegin(const StringRef<const wchar_t>& ref) { return ref.data(); }
-template <class S, typename = typename EnableIf<implementation::StringTraits<S>::isStringClass>::Type> inline
+template <class S, typename = typename EnableIf<StringTraits<S>::isStringClass>::Type> inline
size_t strLength(const S& str) //SFINAE: T must be a "string"
{
return str.length();
@@ -201,7 +201,7 @@ template <class S> inline
auto strBegin(S&& str) -> const typename GetCharType<S>::Type*
{
static_assert(IsStringLike<S>::value, "");
- return implementation::strBegin(std::forward<S>(str));
+ return impl::strBegin(std::forward<S>(str));
}
@@ -209,7 +209,7 @@ template <class S> inline
size_t strLength(S&& str)
{
static_assert(IsStringLike<S>::value, "");
- return implementation::strLength(std::forward<S>(str));
+ return impl::strLength(std::forward<S>(str));
}
}
diff --git a/zen/thread.h b/zen/thread.h
index 0bff5adc..bfb66c31 100755
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -73,7 +73,7 @@ std::async replacement without crappy semantics:
Example:
Zstring dirpath = ...
- auto ft = zen::runAsync([=](){ return zen::dirExists(dirpath); });
+ auto ft = zen::runAsync([=]{ return zen::dirExists(dirpath); });
if (ft.wait_for(std::chrono::milliseconds(200)) == std::future_status::ready && ft.get())
//dir exising
*/
diff --git a/zen/time.h b/zen/time.h
index 67156b9a..74898c7c 100755
--- a/zen/time.h
+++ b/zen/time.h
@@ -22,19 +22,19 @@ struct TimeComp //replaces std::tm and SYSTEMTIME
int minute = 0; //0-59
int second = 0; //0-60 (including leap second)
};
-
inline bool operator==(const TimeComp& lhs, const TimeComp& rhs)
{
return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second;
}
+inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); }
-TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components
-time_t localToTimeT(const TimeComp& comp); //convert local time components to time_t (UTC), returns -1 on error
+TimeComp getLocalTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to local time components, returns TimeComp() on error
+time_t localToTimeT(const TimeComp& tc); //convert local time components to time_t (UTC), returns -1 on error
-TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components
-time_t utcToTimeT(const TimeComp& comp); //convert UTC time components to time_t (UTC), returns -1 on error
+TimeComp getUtcTime(time_t utc = std::time(nullptr)); //convert time_t (UTC) to UTC time components, returns TimeComp() on error
+time_t utcToTimeT(const TimeComp& tc); //convert UTC time components to time_t (UTC), returns -1 on error
-TimeComp getCompileTime();
+TimeComp getCompileTime(); //returns TimeComp() on error
//----------------------------------------------------------------------------------------------------------------------------------
@@ -45,7 +45,7 @@ format (current) date and time; example:
formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
*/
template <class String, class String2>
-String formatTime(const String2& format, const TimeComp& comp = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure
+String formatTime(const String2& format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure
//the "format" parameter of formatTime() is partially specialized with the following type tags:
const struct FormatDateTag {} FORMAT_DATE = {}; //%x - locale dependent date representation: e.g. 08/23/01
@@ -58,8 +58,12 @@ const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M
//----------------------------------------------------------------------------------------------------------------------------------
+/*
+example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02");
+ parseTime(FORMAT_ISO_DATE_TIME, "2001-08-23 14:55:02");
+*/
template <class String, class String2>
-bool parseTime(const String& format, const String2& str, TimeComp& comp); //similar to ::strptime(), return true on success
+TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime()
//----------------------------------------------------------------------------------------------------------------------------------
@@ -75,29 +79,26 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp); //simi
-
-
-
//############################ implementation ##############################
-namespace implementation
+namespace impl
{
inline
-std::tm toClibTimeComponents(const TimeComp& comp)
+std::tm toClibTimeComponents(const TimeComp& tc)
{
- assert(1 <= comp.month && comp.month <= 12 &&
- 1 <= comp.day && comp.day <= 31 &&
- 0 <= comp.hour && comp.hour <= 23 &&
- 0 <= comp.minute && comp.minute <= 59 &&
- 0 <= comp.second && comp.second <= 61);
+ assert(1 <= tc.month && tc.month <= 12 &&
+ 1 <= tc.day && tc.day <= 31 &&
+ 0 <= tc.hour && tc.hour <= 23 &&
+ 0 <= tc.minute && tc.minute <= 59 &&
+ 0 <= tc.second && tc.second <= 61);
std::tm ctc = {};
- ctc.tm_year = comp.year - 1900; //years since 1900
- ctc.tm_mon = comp.month - 1; //0-11
- ctc.tm_mday = comp.day; //1-31
- ctc.tm_hour = comp.hour; //0-23
- ctc.tm_min = comp.minute; //0-59
- ctc.tm_sec = comp.second; //0-60 (including leap second)
- ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available
+ ctc.tm_year = tc.year - 1900; //years since 1900
+ ctc.tm_mon = tc.month - 1; //0-11
+ ctc.tm_mday = tc.day; //1-31
+ ctc.tm_hour = tc.hour; //0-23
+ ctc.tm_min = tc.minute; //0-59
+ ctc.tm_sec = tc.second; //0-60 (including leap second)
+ ctc.tm_isdst = -1; //> 0 if DST is active, == 0 if DST is not active, < 0 if the information is not available
//ctc.tm_wday
//ctc.tm_yday
return ctc;
@@ -106,14 +107,14 @@ std::tm toClibTimeComponents(const TimeComp& comp)
inline
TimeComp toZenTimeComponents(const std::tm& ctc)
{
- TimeComp comp;
- comp.year = ctc.tm_year + 1900;
- comp.month = ctc.tm_mon + 1;
- comp.day = ctc.tm_mday;
- comp.hour = ctc.tm_hour;
- comp.minute = ctc.tm_min;
- comp.second = ctc.tm_sec;
- return comp;
+ TimeComp tc;
+ tc.year = ctc.tm_year + 1900;
+ tc.month = ctc.tm_mon + 1;
+ tc.day = ctc.tm_mday;
+ tc.hour = ctc.tm_hour;
+ tc.minute = ctc.tm_min;
+ tc.second = ctc.tm_sec;
+ return tc;
}
@@ -206,7 +207,6 @@ bool isValid(const std::tm& t)
template <class CharType> inline
size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr)
{
-
return strftimeWrap_impl(buffer, bufferSize, format, timeptr);
}
@@ -215,10 +215,10 @@ struct UserDefinedFormatTag {};
struct PredefinedFormatTag {};
template <class String, class String2> inline
-String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure
+String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure
{
using CharType = typename GetCharType<String>::Type;
- std::tm ctc = toClibTimeComponents(comp);
+ std::tm ctc = toClibTimeComponents(tc);
std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
//note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent
@@ -227,11 +227,12 @@ String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormat
return String(buffer, charsWritten);
}
+
template <class String, class FormatType> inline
-String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag)
+String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag)
{
using CharType = typename GetCharType<String>::Type;
- return formatTime<String>(GetFormat<FormatType>().format(CharType()), comp, UserDefinedFormatTag());
+ return formatTime<String>(GetFormat<FormatType>().format(CharType()), tc, UserDefinedFormatTag());
}
}
@@ -239,37 +240,49 @@ String formatTime(FormatType, const TimeComp& comp, PredefinedFormatTag)
inline
TimeComp getLocalTime(time_t utc)
{
- std::tm comp = {};
- if (::localtime_r(&utc, &comp) == nullptr)
+ if (utc == -1) //failure code from std::time(nullptr)
+ return TimeComp();
+
+ std::tm ctc = {};
+ if (::localtime_r(&utc, &ctc) == nullptr)
return TimeComp();
- return implementation::toZenTimeComponents(comp);
+ return impl::toZenTimeComponents(ctc);
}
inline
TimeComp getUtcTime(time_t utc)
{
- std::tm comp = {};
- if (::gmtime_r(&utc, &comp) == nullptr)
+ if (utc == -1) //failure code from std::time(nullptr)
return TimeComp();
- return implementation::toZenTimeComponents(comp);
+ std::tm ctc = {};
+ if (::gmtime_r(&utc, &ctc) == nullptr)
+ return TimeComp();
+
+ return impl::toZenTimeComponents(ctc);
}
inline
-time_t localToTimeT(const TimeComp& comp) //returns -1 on error
+time_t localToTimeT(const TimeComp& tc) //returns -1 on error
{
- std::tm ctc = implementation::toClibTimeComponents(comp);
+ if (tc == TimeComp())
+ return -1;
+
+ std::tm ctc = impl::toClibTimeComponents(tc);
return std::mktime(&ctc);
}
inline
-time_t utcToTimeT(const TimeComp& comp) //returns -1 on error
+time_t utcToTimeT(const TimeComp& tc) //returns -1 on error
{
- std::tm ctc = implementation::toClibTimeComponents(comp);
+ if (tc == TimeComp())
+ return -1;
+
+ std::tm ctc = impl::toClibTimeComponents(tc);
ctc.tm_isdst = 0; //"Zero (0) to indicate that standard time is in effect" => unused by _mkgmtime, but take no chances
return ::timegm(&ctc);
}
@@ -283,39 +296,36 @@ TimeComp getCompileTime()
if (compileTime[4] == ' ') //day is space-padded, but %d expects zero-padding
compileTime[4] = '0';
- TimeComp tc = {};
- if (parseTime("%b %d %Y %H:%M:%S", compileTime, tc))
- return tc;
-
- assert(false);
- return TimeComp();
+ return parseTime("%b %d %Y %H:%M:%S", compileTime);
}
template <class String, class String2> inline
-String formatTime(const String2& format, const TimeComp& comp)
+String formatTime(const String2& format, const TimeComp& tc)
{
+ if (tc == TimeComp()) //failure code from getLocalTime()
+ return String();
+
using FormatTag = typename SelectIf<
IsSameType<String2, FormatDateTag >::value ||
IsSameType<String2, FormatTimeTag >::value ||
IsSameType<String2, FormatDateTimeTag >::value ||
IsSameType<String2, FormatIsoDateTag >::value ||
IsSameType<String2, FormatIsoTimeTag >::value ||
- IsSameType<String2, FormatIsoDateTimeTag>::value, implementation::PredefinedFormatTag, implementation::UserDefinedFormatTag>::Type;
+ IsSameType<String2, FormatIsoDateTimeTag>::value, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>::Type;
- return implementation::formatTime<String>(format, comp, FormatTag());
+ return impl::formatTime<String>(format, tc, FormatTag());
}
+namespace impl
+{
template <class String, class String2>
-bool parseTime(const String& format, const String2& str, TimeComp& comp) //return true on success
+TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag)
{
using CharType = typename GetCharType<String>::Type;
static_assert(IsSameType<CharType, typename GetCharType<String2>::Type>::value, "");
- const CharType* itFmt = strBegin(format);
- const CharType* const fmtLast = itFmt + strLength(format);
-
const CharType* itStr = strBegin(str);
const CharType* const strLast = itStr + strLength(str);
@@ -332,6 +342,11 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur
return true;
};
+ TimeComp output;
+
+ const CharType* itFmt = strBegin(format);
+ const CharType* const fmtLast = itFmt + strLength(format);
+
for (; itFmt != fmtLast; ++itFmt)
{
const CharType fmt = *itFmt;
@@ -340,22 +355,22 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur
{
++itFmt;
if (itFmt == fmtLast)
- return false;
+ return TimeComp();
switch (*itFmt)
{
case 'Y':
- if (!extractNumber(comp.year, 4))
- return false;
+ if (!extractNumber(output.year, 4))
+ return TimeComp();
break;
case 'm':
- if (!extractNumber(comp.month, 2))
- return false;
+ if (!extractNumber(output.month, 2))
+ return TimeComp();
break;
case 'b': //abbreviated month name: Jan-Dec
{
if (strLast - itStr < 3)
- return false;
+ return TimeComp();
const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name)
@@ -365,30 +380,30 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur
asciiToLower(itStr[2]) == name[2];
});
if (itMonth == std::end(months))
- return false;
+ return TimeComp();
- comp.month = 1 + static_cast<int>(itMonth - std::begin(months));
+ output.month = 1 + static_cast<int>(itMonth - std::begin(months));
itStr += 3;
}
break;
case 'd':
- if (!extractNumber(comp.day, 2))
- return false;
+ if (!extractNumber(output.day, 2))
+ return TimeComp();
break;
case 'H':
- if (!extractNumber(comp.hour, 2))
- return false;
+ if (!extractNumber(output.hour, 2))
+ return TimeComp();
break;
case 'M':
- if (!extractNumber(comp.minute, 2))
- return false;
+ if (!extractNumber(output.minute, 2))
+ return TimeComp();
break;
case 'S':
- if (!extractNumber(comp.second, 2))
- return false;
+ if (!extractNumber(output.second, 2))
+ return TimeComp();
break;
default:
- return false;
+ return TimeComp();
}
}
else if (isWhiteSpace(fmt)) //single whitespace in format => skip 0..n whitespace chars
@@ -399,12 +414,36 @@ bool parseTime(const String& format, const String2& str, TimeComp& comp) //retur
else
{
if (itStr == strLast || *itStr != fmt)
- return false;
+ return TimeComp();
++itStr;
}
}
- return itStr == strLast;
+ if (itStr != strLast)
+ return TimeComp();
+
+ return output;
+}
+
+
+template <class FormatType, class String> inline
+TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag)
+{
+ using CharType = typename GetCharType<String>::Type;
+ return parseTime(GetFormat<FormatType>().format(CharType()), str, UserDefinedFormatTag());
+}
+}
+
+
+template <class String, class String2> inline
+TimeComp parseTime(const String& format, const String2& str)
+{
+ using FormatTag = typename SelectIf<
+ IsSameType<String, FormatIsoDateTag >::value ||
+ IsSameType<String, FormatIsoTimeTag >::value ||
+ IsSameType<String, FormatIsoDateTimeTag>::value, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>::Type;
+
+ return impl::parseTime(format, str, FormatTag());
}
}
diff --git a/zen/utf.h b/zen/utf.h
index 820148c6..f8ee91d5 100755
--- a/zen/utf.h
+++ b/zen/utf.h
@@ -12,6 +12,7 @@
#include "string_tools.h" //copyStringTo
#include "optional.h"
+
namespace zen
{
//convert all(!) char- and wchar_t-based "string-like" objects applying a UTF8 conversions (but only if necessary!)
@@ -39,7 +40,7 @@ UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t u
//----------------------- implementation ----------------------------------
-namespace implementation
+namespace impl
{
using CodePoint = uint32_t;
using Char16 = uint16_t;
@@ -308,7 +309,7 @@ using UtfDecoder = UtfDecoderImpl<CharType, sizeof(CharType)>;
template <class UtfString> inline
bool isValidUtf(const UtfString& str)
{
- using namespace implementation;
+ using namespace impl;
UtfDecoder<typename GetCharType<UtfString>::Type> decoder(strBegin(str), strLength(str));
while (Opt<CodePoint> cp = decoder.getNext())
@@ -323,7 +324,7 @@ template <class UtfString> inline
size_t unicodeLength(const UtfString& str) //return number of code points (+ correctly handle broken UTF encoding)
{
size_t uniLen = 0;
- implementation::UtfDecoder<typename GetCharType<UtfString>::Type> decoder(strBegin(str), strLength(str));
+ impl::UtfDecoder<typename GetCharType<UtfString>::Type> decoder(strBegin(str), strLength(str));
while (decoder.getNext())
++uniLen;
return uniLen;
@@ -334,7 +335,7 @@ template <class UtfString> inline
UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t uniPosLast) //return position of unicode char in UTF-encoded string
{
assert(uniPosFirst <= uniPosLast && uniPosLast <= unicodeLength(str));
- using namespace implementation;
+ using namespace impl;
using CharType = typename GetCharType<UtfString>::Type;
UtfString output;
if (uniPosFirst >= uniPosLast) //optimize for empty range
@@ -353,7 +354,7 @@ UtfString getUnicodeSubstring(const UtfString& str, size_t uniPosFirst, size_t u
//-------------------------------------------------------------------------------------------
-namespace implementation
+namespace impl
{
template <class TargetString, class SourceString> inline
TargetString utfTo(const SourceString& str, FalseType)
@@ -380,7 +381,7 @@ TargetString utfTo(const SourceString& str, TrueType) { return copyStringTo<Targ
template <class TargetString, class SourceString> inline
TargetString utfTo(const SourceString& str)
{
- return implementation::utfTo<TargetString>(str, StaticBool<sizeof(typename GetCharType<SourceString>::Type) == sizeof(typename GetCharType<TargetString>::Type)>());
+ return impl::utfTo<TargetString>(str, StaticBool<sizeof(typename GetCharType<SourceString>::Type) == sizeof(typename GetCharType<TargetString>::Type)>());
}
}
diff --git a/zen/xml_io.h b/zen/xml_io.h
index 8d3346c6..a53a7edb 100755
--- a/zen/xml_io.h
+++ b/zen/xml_io.h
@@ -10,11 +10,11 @@
#include <zenxml/xml.h>
#include "file_error.h"
+
//combine zen::Xml and zen file i/o
//-> loadXmlDocument vs loadStream:
//1. better error reporting
//2. quick exit if (potentially large) input file is not an XML
-
namespace zen
{
XmlDoc loadXmlDocument(const Zstring& filePath); //throw FileError
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 2aa3b3f2..ce94fe56 100755
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -44,18 +44,17 @@ int compareNoCaseUtf8(const char* lhs, size_t lhsLen, const char* rhs, size_t rh
//- strncasecmp implements ASCII CI-comparsion only! => signature is broken for UTF8-input; toupper() similarly doesn't support Unicode
//- wcsncasecmp: https://opensource.apple.com/source/Libc/Libc-763.12/string/wcsncasecmp-fbsd.c
// => re-implement comparison based on towlower() to avoid memory allocations
- using namespace zen::implementation;
- UtfDecoder<char> decL(lhs, lhsLen);
- UtfDecoder<char> decR(rhs, rhsLen);
+ impl::UtfDecoder<char> decL(lhs, lhsLen);
+ impl::UtfDecoder<char> decR(rhs, rhsLen);
for (;;)
{
- const Opt<CodePoint> cpL = decL.getNext();
- const Opt<CodePoint> cpR = decR.getNext();
+ const Opt<impl::CodePoint> cpL = decL.getNext();
+ const Opt<impl::CodePoint> cpR = decR.getNext();
if (!cpL || !cpR)
return static_cast<int>(!cpR) - static_cast<int>(!cpL);
- static_assert(sizeof(wchar_t) == sizeof(CodePoint), "");
+ static_assert(sizeof(wchar_t) == sizeof(impl::CodePoint), "");
const wchar_t charL = ::towlower(static_cast<wchar_t>(*cpL)); //ordering: towlower() converts to higher code points than towupper()
const wchar_t charR = ::towlower(static_cast<wchar_t>(*cpR)); //uses LC_CTYPE category of current locale
if (charL != charR)
diff --git a/zenXml/zenxml/bind.h b/zenXml/zenxml/bind.h
index f3cfa398..824c6cc6 100755
--- a/zenXml/zenxml/bind.h
+++ b/zenXml/zenxml/bind.h
@@ -12,6 +12,7 @@
#include "parser.h"
#include "io.h"
+
namespace zen
{
/**
@@ -167,17 +168,17 @@ public:
in["elem3"](value3); //
\endcode
*/
- XmlIn(const XmlDoc& doc) : log(std::make_shared<ErrorLog>()) { refList.push_back(&doc.root()); }
+ XmlIn(const XmlDoc& doc) : log_(std::make_shared<ErrorLog>()) { refList_.push_back(&doc.root()); }
///Construct an input proxy for a single XML element, may be nullptr
/**
\sa XmlIn(const XmlDoc& doc)
*/
- XmlIn(const XmlElement* element) : log(std::make_shared<ErrorLog>()) { refList.push_back(element); }
+ XmlIn(const XmlElement* element) : log_(std::make_shared<ErrorLog>()) { refList_.push_back(element); }
///Construct an input proxy for a single XML element
/**
\sa XmlIn(const XmlDoc& doc)
*/
- XmlIn(const XmlElement& element) : log(std::make_shared<ErrorLog>()) { refList.push_back(&element); }
+ XmlIn(const XmlElement& element) : log_(std::make_shared<ErrorLog>()) { refList_.push_back(&element); }
///Retrieve a handle to an XML child element for reading
/**
@@ -190,14 +191,14 @@ public:
{
std::vector<const XmlElement*> childList;
- if (refIndex < refList.size())
+ if (refIndex_ < refList_.size())
{
- auto iterPair = refList[refIndex]->getChildren(name);
+ auto iterPair = refList_[refIndex_]->getChildren(name);
std::for_each(iterPair.first, iterPair.second,
[&](const XmlElement& child) { childList.push_back(&child); });
}
- return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log);
+ return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log_);
}
///Refer to next sibling element with the same name
@@ -221,7 +222,7 @@ public:
}
\endcode
*/
- void next() { ++refIndex; }
+ void next() { ++refIndex_; }
///Read user data from the underlying XML element
/**
@@ -232,16 +233,16 @@ public:
template <class T>
bool operator()(T& value) const
{
- if (refIndex < refList.size())
+ if (refIndex_ < refList_.size())
{
- bool success = readStruc(*refList[refIndex], value);
+ bool success = readStruc(*refList_[refIndex_], value);
if (!success)
- log->notifyConversionError(getNameFormatted());
+ log_->notifyConversionError(getNameFormatted());
return success;
}
else
{
- log->notifyMissingElement(getNameFormatted());
+ log_->notifyMissingElement(getNameFormatted());
return false;
}
}
@@ -267,22 +268,22 @@ public:
template <class String, class T>
bool attribute(const String& name, T& value) const
{
- if (refIndex < refList.size())
+ if (refIndex_ < refList_.size())
{
- bool success = refList[refIndex]->getAttribute(name, value);
+ bool success = refList_[refIndex_]->getAttribute(name, value);
if (!success)
- log->notifyMissingAttribute(getNameFormatted(), utfTo<std::string>(name));
+ log_->notifyMissingAttribute(getNameFormatted(), utfTo<std::string>(name));
return success;
}
else
{
- log->notifyMissingElement(getNameFormatted());
+ log_->notifyMissingElement(getNameFormatted());
return false;
}
}
///Return a pointer to the underlying Xml element, may be nullptr
- const XmlElement* get() const { return refIndex < refList.size() ? refList[refIndex] : nullptr; }
+ const XmlElement* get() const { return refIndex_ < refList_.size() ? refList_[refIndex_] : nullptr; }
///Test whether the underlying XML element exists
/**
@@ -316,7 +317,7 @@ public:
However be aware that the chain of connected proxy instances will be broken once you call XmlIn::get() to retrieve the underlying pointer.
Errors that occur when working with this pointer are not logged by the original set of related instances.
*/
- bool errorsOccured() const { return !log->elementList().empty(); }
+ bool errorsOccured() const { return !log_->elementList().empty(); }
///Get a list of XML element and attribute names which failed to convert to user data.
/**
@@ -327,14 +328,14 @@ public:
std::vector<String> getErrorsAs() const
{
std::vector<String> output;
- const auto& elements = log->elementList();
+ const auto& elements = log_->elementList();
std::transform(elements.begin(), elements.end(), std::back_inserter(output), [](const std::string& str) { return utfTo<String>(str); });
return output;
}
private:
XmlIn(const std::vector<const XmlElement*>& siblingList, const std::string& elementNameFmt, const std::shared_ptr<ErrorLog>& sharedlog) :
- refList(siblingList), formattedName(elementNameFmt), log(sharedlog)
+ refList_(siblingList), formattedName_(elementNameFmt), log_(sharedlog)
{ assert((!siblingList.empty() && elementNameFmt.empty()) || (siblingList.empty() && !elementNameFmt.empty())); }
static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>"
@@ -344,13 +345,13 @@ private:
std::string getNameFormatted() const
{
- if (refIndex < refList.size())
+ if (refIndex_ < refList_.size())
{
- assert(formattedName.empty());
- return getNameFormatted(*refList[refIndex]);
+ assert(formattedName_.empty());
+ return getNameFormatted(*refList_[refIndex_]);
}
else
- return formattedName;
+ return formattedName_;
}
std::string getChildNameFormatted(const std::string& childName) const
@@ -379,10 +380,10 @@ private:
std::set<std::string> usedElements;
};
- std::vector<const XmlElement*> refList; //all sibling elements with same name (all pointers bound!)
- size_t refIndex = 0; //this sibling's index in refList
- std::string formattedName; //contains full and formatted element name if (and only if) refList is empty
- std::shared_ptr<ErrorLog> log; //always bound
+ std::vector<const XmlElement*> refList_; //all sibling elements with same name (all pointers bound!)
+ size_t refIndex_ = 0; //this sibling's index in refList_
+ std::string formattedName_; //contains full and formatted element name if (and only if) refList_ is empty
+ std::shared_ptr<ErrorLog> log_; //always bound
};
}
diff --git a/zenXml/zenxml/cvrt_struc.h b/zenXml/zenxml/cvrt_struc.h
index 87687929..3a18ea73 100755
--- a/zenXml/zenxml/cvrt_struc.h
+++ b/zenXml/zenxml/cvrt_struc.h
@@ -9,6 +9,7 @@
#include "dom.h"
+
namespace zen
{
/**
@@ -42,11 +43,6 @@ template <class T> void writeStruc(const T& value, XmlElement& output);
-
-
-
-
-
//------------------------------ implementation -------------------------------------
namespace impl_2384343
{
@@ -140,7 +136,7 @@ struct ConvertElement<T, VALUE_TYPE_STL_CONTAINER>
value.insert(value.end(), childVal);
else
success = false;
- //should we support insertion of partially-loaded struct??
+ //should we support insertion of partially-loaded struct??
}
return success;
}
diff --git a/zenXml/zenxml/cvrt_text.h b/zenXml/zenxml/cvrt_text.h
index 6ff1ec94..17444861 100755
--- a/zenXml/zenxml/cvrt_text.h
+++ b/zenXml/zenxml/cvrt_text.h
@@ -10,6 +10,7 @@
#include <zen/utf.h>
#include <zen/string_tools.h>
+
namespace zen
{
/**
diff --git a/zenXml/zenxml/dom.h b/zenXml/zenxml/dom.h
index 09977f1d..c8959e4b 100755
--- a/zenXml/zenxml/dom.h
+++ b/zenXml/zenxml/dom.h
@@ -8,10 +8,12 @@
#define DOM_H_82085720723894567204564256
#include <string>
+#include <list>
#include <map>
#include <zen/fixed_list.h>
#include "cvrt_text.h" //"readText/writeText"
+
namespace zen
{
class XmlDoc;
@@ -20,11 +22,11 @@ class XmlDoc;
class XmlElement
{
public:
- XmlElement() : parent_(nullptr) {}
+ XmlElement() {}
//Construct an empty XML element
template <class String>
- explicit XmlElement(const String& name, XmlElement* parentElement = nullptr) : name_(utfTo<std::string>(name)), parent_(parentElement) {}
+ explicit XmlElement(const String& name, XmlElement* parent = nullptr) : name_(utfTo<std::string>(name)), parent_(parent) {}
///Retrieve the name of this XML element.
/**
@@ -60,8 +62,8 @@ public:
template <class String, class T>
bool getAttribute(const String& name, T& value) const
{
- auto it = attributes.find(utfTo<std::string>(name));
- return it == attributes.end() ? false : readText(it->second, value);
+ auto it = attributesSorted_.find(utfTo<std::string>(name));
+ return it == attributesSorted_.end() ? false : readText(it->second->value, value);
}
///Create or update an XML attribute.
@@ -74,9 +76,19 @@ public:
template <class String, class T>
void setAttribute(const String& name, const T& value)
{
+ std::string attrName = utfTo<std::string>(name);
+
std::string attrValue;
writeText(value, attrValue);
- attributes[utfTo<std::string>(name)] = attrValue;
+
+ auto it = attributesSorted_.find(attrName);
+ if (it != attributesSorted_.end())
+ it->second->value = std::move(attrValue);
+ else
+ {
+ auto itBack = attributes_.insert(attributes_.end(), { attrName, std::move(attrValue) });
+ attributesSorted_.emplace(std::move(attrName), itBack);
+ }
}
///Remove the attribute with the given name.
@@ -84,7 +96,15 @@ public:
\tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ...
*/
template <class String>
- void removeAttribute(const String& name) { attributes.erase(utfTo<std::string>(name)); }
+ void removeAttribute(const String& name)
+ {
+ auto it = attributesSorted_.find(utfTo<std::string>(name));
+ if (it != attributesSorted_.end())
+ {
+ attributes_.erase(it->second);
+ attributesSorted_.erase(it);
+ }
+ }
///Create a new child element and return a reference to it.
/**
@@ -94,10 +114,10 @@ public:
template <class String>
XmlElement& addChild(const String& name)
{
- std::string utf8Name = utfTo<std::string>(name);
- childElements.emplace_back(utf8Name, this);
- XmlElement& newElement = childElements.back();
- childElementsSorted.emplace(utf8Name, &newElement);
+ std::string elemName = utfTo<std::string>(name);
+ childElements_.emplace_back(elemName, this);
+ XmlElement& newElement = childElements_.back();
+ childElementsSorted_.emplace(std::move(elemName), &newElement);
return newElement;
}
@@ -110,8 +130,8 @@ public:
template <class String>
const XmlElement* getChild(const String& name) const
{
- auto it = childElementsSorted.find(utfTo<std::string>(name));
- return it == childElementsSorted.end() ? nullptr : it->second;
+ auto it = childElementsSorted_.find(utfTo<std::string>(name));
+ return it == childElementsSorted_.end() ? nullptr : it->second;
}
///\sa getChild
@@ -121,8 +141,8 @@ public:
return const_cast<XmlElement*>(static_cast<const XmlElement*>(this)->getChild(name));
}
- template < class IterTy, //underlying iterator type
- class T, //target object type
+ template < class IterTy, //underlying iterator type
+ class T, //target object type
class AccessPolicy > //access policy: see AccessPtrMap
class PtrIter : public std::iterator<std::input_iterator_tag, T>, private AccessPolicy //get rid of shared_ptr indirection
{
@@ -159,11 +179,11 @@ public:
\return A pair of STL begin/end iterators to access the child elements sequentially.
*/
template <class String>
- std::pair<ChildIterConst2, ChildIterConst2> getChildren(const String& name) const { return childElementsSorted.equal_range(utfTo<std::string>(name)); }
+ std::pair<ChildIterConst2, ChildIterConst2> getChildren(const String& name) const { return childElementsSorted_.equal_range(utfTo<std::string>(name)); }
///\sa getChildren
template <class String>
- std::pair<ChildIter2, ChildIter2> getChildren(const String& name) { return childElementsSorted.equal_range(utfTo<std::string>(name)); }
+ std::pair<ChildIter2, ChildIter2> getChildren(const String& name) { return childElementsSorted_.equal_range(utfTo<std::string>(name)); }
struct AccessListElement
{
@@ -183,41 +203,47 @@ public:
\endcode
\return A pair of STL begin/end iterators to access all child elements sequentially.
*/
- std::pair<ChildIterConst, ChildIterConst> getChildren() const { return std::make_pair(childElements.begin(), childElements.end()); }
+ std::pair<ChildIterConst, ChildIterConst> getChildren() const { return { childElements_.begin(), childElements_.end() }; }
///\sa getChildren
- std::pair<ChildIter, ChildIter> getChildren() { return std::make_pair(childElements.begin(), childElements.end()); }
+ std::pair<ChildIter, ChildIter> getChildren() { return { childElements_.begin(), childElements_.end() }; }
///Get parent XML element, may be nullptr for root element
XmlElement* parent() { return parent_; }
///Get parent XML element, may be nullptr for root element
const XmlElement* parent() const { return parent_; }
- using AttrIter = std::map<std::string, std::string>::const_iterator;
+ struct Attribute
+ {
+ std::string name;
+ std::string value;
+ };
+ using AttrIter = std::list<Attribute>::const_iterator;
/* -> disabled documentation extraction
\brief Get all attributes associated with the element.
\code
auto iterPair = elem.getAttributes();
for (auto it = iterPair.first; it != iterPair.second; ++it)
- std::cout << "name: " << it->first << " value: " << it->second << "\n";
+ std::cout << "name: " << it->name << " value: " << it->value << "\n";
\endcode
\return A pair of STL begin/end iterators to access all attributes sequentially as a list of name/value pairs of std::string.
*/
- std::pair<AttrIter, AttrIter> getAttributes() const { return std::make_pair(attributes.begin(), attributes.end()); }
+ 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)
{
- name_ .swap(other.name_);
- value_ .swap(other.value_);
- attributes.swap(other.attributes);
- childElements.swap(other.childElements);
- childElementsSorted.swap(other.childElementsSorted);
- //std::swap(parent_, other.parent_); -> parent is physical location; update children's parent reference instead:
- for (XmlElement& child : childElements)
+ name_ .swap(other.name_);
+ value_ .swap(other.value_);
+ attributes_ .swap(other.attributes_);
+ attributesSorted_ .swap(other.attributesSorted_);
+ childElements_ .swap(other.childElements_);
+ childElementsSorted_.swap(other.childElementsSorted_);
+
+ for (XmlElement& child : childElements_)
child.parent_ = this;
- for (XmlElement& child : other.childElements)
+ for (XmlElement& child : other.childElements_)
child.parent_ = &other;
}
@@ -227,10 +253,13 @@ private:
std::string name_;
std::string value_;
- std::map<std::string, std::string> attributes;
- FixedList<XmlElement> childElements; //all child elements in order of creation
- std::multimap<std::string, XmlElement*> childElementsSorted; //alternate key: sorted by element name
- XmlElement* parent_;
+
+ std::list<Attribute> attributes_; //attributes in order of creation
+ std::map<std::string, std::list<Attribute>::iterator> attributesSorted_; //alternate view: sorted by attribute name
+
+ FixedList<XmlElement> childElements_; //child elements in order of creation
+ std::multimap<std::string, XmlElement*> childElementsSorted_; //alternate view: sorted by element name
+ XmlElement* parent_ = nullptr;
};
@@ -247,7 +276,7 @@ class XmlDoc
{
public:
///Default constructor setting up an empty XML document with a standard declaration: <?xml version="1.0" encoding="UTF-8" ?>
- XmlDoc() : version_("1.0"), encoding_("UTF-8"), rootElement("Root") {}
+ XmlDoc() {}
XmlDoc(XmlDoc&& tmp) { swap(tmp); }
XmlDoc& operator=(XmlDoc&& tmp) { swap(tmp); return *this; }
@@ -258,12 +287,12 @@ public:
\param rootName The name of the XML document's root element.
*/
template <class String>
- XmlDoc(String rootName) : version_("1.0"), encoding_("UTF-8"), rootElement(rootName) {}
+ XmlDoc(String rootName) : root_(rootName) {}
///Get a const reference to the document's root element.
- const XmlElement& root() const { return rootElement; }
+ const XmlElement& root() const { return root_; }
///Get a reference to the document's root element.
- XmlElement& root() { return rootElement; }
+ XmlElement& root() { return root_; }
///Get the version used in the XML declaration.
/**
@@ -313,18 +342,18 @@ public:
version_ .swap(other.version_);
encoding_ .swap(other.encoding_);
standalone_.swap(other.standalone_);
- rootElement.swapSubtree(other.rootElement);
+ root_.swapSubtree(other.root_);
}
private:
XmlDoc (const XmlDoc&) = delete; //not implemented, thanks to XmlElement::parent_
XmlDoc& operator=(const XmlDoc&) = delete;
- std::string version_;
- std::string encoding_;
+ std::string version_ { "1.0" };
+ std::string encoding_{ "UTF-8" };
std::string standalone_;
- XmlElement rootElement;
+ XmlElement root_{ "Root" };
};
}
diff --git a/zenXml/zenxml/io.h b/zenXml/zenxml/io.h
index 1361d865..6d5a21d5 100755
--- a/zenXml/zenxml/io.h
+++ b/zenXml/zenxml/io.h
@@ -13,6 +13,7 @@
#include <zen/utf.h>
#include "error.h"
+
namespace zen
{
/**
diff --git a/zenXml/zenxml/parser.h b/zenXml/zenxml/parser.h
index bff2bb50..5c6a9ec2 100755
--- a/zenXml/zenxml/parser.h
+++ b/zenXml/zenxml/parser.h
@@ -73,7 +73,7 @@ XmlDoc parse(const std::string& stream); //throw XmlParsingError
//---------------------------- implementation ----------------------------
//see: http://www.w3.org/TR/xml/
-namespace implementation
+namespace impl
{
template <class Predicate> inline
std::string normalize(const std::string& str, Predicate pred) //pred: unary function taking a char, return true if value shall be encoded as hex
@@ -111,7 +111,9 @@ std::string normalize(const std::string& str, Predicate pred) //pred: unary func
inline
std::string normalizeName(const std::string& str)
{
- return normalize(str, [](char c) { return isWhiteSpace(c) || c == '=' || c == '/' || c == '\'' || c == '\"'; });
+ const std::string nameFmt = normalize(str, [](char c) { return isWhiteSpace(c) || c == '=' || c == '/' || c == '\'' || c == '\"'; });
+ assert(!nameFmt.empty());
+ return nameFmt;
}
inline
@@ -201,12 +203,12 @@ void serialize(const XmlElement& element, std::string& stream,
auto attr = element.getAttributes();
for (auto it = attr.first; it != attr.second; ++it)
- stream += ' ' + normalizeName(it->first) + "=\"" + normalizeAttribValue(it->second) + '\"';
+ stream += ' ' + normalizeName(it->name) + "=\"" + normalizeAttribValue(it->value) + '\"';
- //no support for mixed-mode content
auto iterPair = element.getChildren();
if (iterPair.first != iterPair.second) //structured element
{
+ //no support for mixed-mode content
stream += '>' + lineBreak;
std::for_each(iterPair.first, iterPair.second,
@@ -254,7 +256,7 @@ std::string serialize(const XmlDoc& doc,
inline
std::string serialize(const XmlDoc& doc,
const std::string& lineBreak,
- const std::string& indent) { return implementation::serialize(doc, lineBreak, indent); }
+ const std::string& indent) { return impl::serialize(doc, lineBreak, indent); }
/*
Grammar for XML parser
@@ -280,7 +282,7 @@ pm-expression:
element-list-expression
*/
-namespace implementation
+namespace impl
{
struct Token
{
@@ -355,7 +357,7 @@ public:
{
std::string name(&*pos, nameEnd - pos);
pos = nameEnd;
- return implementation::denormalize(name);
+ return denormalize(name);
}
//unknown token
@@ -371,7 +373,7 @@ public:
});
std::string output(pos, it);
pos = it;
- return implementation::denormalize(output);
+ return denormalize(output);
}
std::string extractAttributeValue()
@@ -385,7 +387,7 @@ public:
});
std::string output(pos, it);
pos = it;
- return implementation::denormalize(output);
+ return denormalize(output);
}
size_t posRow() const //current row beginning with 0
@@ -575,7 +577,7 @@ private:
inline
XmlDoc parse(const std::string& stream) //throw XmlParsingError
{
- return implementation::XmlParser(stream).parse(); //throw XmlParsingError
+ return impl::XmlParser(stream).parse(); //throw XmlParsingError
}
}
diff --git a/zenXml/zenxml/xml.h b/zenXml/zenxml/xml.h
index e0035c2b..9510645a 100755
--- a/zenXml/zenxml/xml.h
+++ b/zenXml/zenxml/xml.h
@@ -9,6 +9,7 @@
#include "bind.h"
+
/// The zen::Xml namespace
namespace zen {}
bgstack15