summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:20:29 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:20:29 +0200
commitb8f13e45be884dc12884ebe8f3dcd9eecb23a106 (patch)
tree22a6d8b96815d626061ff3e2d432c13078fca5c4
parent5.4 (diff)
downloadFreeFileSync-b8f13e45be884dc12884ebe8f3dcd9eecb23a106.tar.gz
FreeFileSync-b8f13e45be884dc12884ebe8f3dcd9eecb23a106.tar.bz2
FreeFileSync-b8f13e45be884dc12884ebe8f3dcd9eecb23a106.zip
5.5
-rw-r--r--Application.cpp43
-rw-r--r--BUILD/Changelog.txt22
-rw-r--r--BUILD/FreeFileSync.chmbin667858 -> 667844 bytes
-rw-r--r--BUILD/Help/Table of Contents.hhc2
-rw-r--r--BUILD/Help/html/Compare by File Size.html4
-rw-r--r--BUILD/Languages/chinese_simple.lng209
-rw-r--r--BUILD/Languages/chinese_traditional.lng217
-rw-r--r--BUILD/Languages/croatian.lng211
-rw-r--r--BUILD/Languages/czech.lng180
-rw-r--r--BUILD/Languages/danish.lng217
-rw-r--r--BUILD/Languages/dutch.lng176
-rw-r--r--BUILD/Languages/english_uk.lng192
-rw-r--r--BUILD/Languages/finnish.lng191
-rw-r--r--BUILD/Languages/french.lng194
-rw-r--r--BUILD/Languages/german.lng176
-rw-r--r--BUILD/Languages/greek.lng188
-rw-r--r--BUILD/Languages/hebrew.lng218
-rw-r--r--BUILD/Languages/hungarian.lng182
-rw-r--r--BUILD/Languages/italian.lng206
-rw-r--r--BUILD/Languages/japanese.lng192
-rw-r--r--BUILD/Languages/korean.lng202
-rw-r--r--BUILD/Languages/lithuanian.lng192
-rw-r--r--BUILD/Languages/norwegian.lng184
-rw-r--r--BUILD/Languages/polish.lng257
-rw-r--r--BUILD/Languages/portuguese.lng192
-rw-r--r--BUILD/Languages/portuguese_br.lng221
-rw-r--r--BUILD/Languages/romanian.lng184
-rw-r--r--BUILD/Languages/russian.lng197
-rw-r--r--BUILD/Languages/slovenian.lng192
-rw-r--r--BUILD/Languages/spanish.lng213
-rw-r--r--BUILD/Languages/swedish.lng192
-rw-r--r--BUILD/Languages/turkish.lng192
-rw-r--r--BUILD/Languages/ukrainian.lng202
-rw-r--r--BUILD/Resources.zipbin268638 -> 263865 bytes
-rw-r--r--FreeFileSync.cbp32
-rw-r--r--FreeFileSync.vcxproj33
-rw-r--r--Makefile5
-rw-r--r--RealtimeSync/RealtimeSync.cbp16
-rw-r--r--RealtimeSync/RealtimeSync.vcxproj30
-rw-r--r--RealtimeSync/application.cpp38
-rw-r--r--RealtimeSync/gui_generated.cpp10
-rw-r--r--RealtimeSync/gui_generated.h4
-rw-r--r--RealtimeSync/main_dlg.cpp4
-rw-r--r--RealtimeSync/main_dlg.h4
-rw-r--r--RealtimeSync/makefile4
-rw-r--r--RealtimeSync/resource.rc11
-rw-r--r--RealtimeSync/tray_menu.cpp2
-rw-r--r--RealtimeSync/watcher.cpp2
-rw-r--r--algorithm.cpp637
-rw-r--r--comparison.cpp111
-rw-r--r--file_hierarchy.h41
-rw-r--r--lib/cmp_filetime.h9
-rw-r--r--lib/db_file.cpp994
-rw-r--r--lib/db_file.h68
-rw-r--r--lib/dir_lock.cpp77
-rw-r--r--lib/ffs_paths.h4
-rw-r--r--lib/generate_logfile.h138
-rw-r--r--lib/hard_filter.cpp92
-rw-r--r--lib/hard_filter.h98
-rw-r--r--lib/icon_buffer.cpp38
-rw-r--r--lib/localization.cpp3
-rw-r--r--lib/parallel_scan.cpp27
-rw-r--r--lib/process_xml.cpp40
-rw-r--r--lib/resolve_path.cpp7
-rw-r--r--lib/resources.cpp2
-rw-r--r--lib/xml_base.cpp2
-rw-r--r--resource.rc10
-rw-r--r--structures.h6
-rw-r--r--synchronization.cpp522
-rw-r--r--synchronization.h9
-rw-r--r--ui/batch_config.cpp5
-rw-r--r--ui/batch_status_handler.cpp192
-rw-r--r--ui/batch_status_handler.h7
-rw-r--r--ui/check_version.cpp56
-rw-r--r--ui/custom_grid.cpp12
-rw-r--r--ui/dir_name.cpp2
-rw-r--r--ui/folder_history_box.cpp1
-rw-r--r--ui/folder_history_box.h1
-rw-r--r--ui/folder_pair.h1
-rw-r--r--ui/grid_view.h8
-rw-r--r--ui/gui_generated.cpp484
-rw-r--r--ui/gui_generated.h114
-rw-r--r--ui/gui_status_handler.cpp66
-rw-r--r--ui/gui_status_handler.h5
-rw-r--r--ui/main_dlg.cpp385
-rw-r--r--ui/main_dlg.h13
-rw-r--r--ui/msg_popup.cpp225
-rw-r--r--ui/msg_popup.h23
-rw-r--r--ui/small_dlgs.cpp37
-rw-r--r--ui/sync_cfg.cpp5
-rw-r--r--version/version.h2
-rw-r--r--version/version.rc4
-rw-r--r--wx+/button.cpp15
-rw-r--r--wx+/create_pch.cpp8
-rw-r--r--wx+/dir_picker.h8
-rw-r--r--wx+/serialize.h322
-rw-r--r--wx+/zlib_wrap.cpp54
-rw-r--r--wx+/zlib_wrap.h115
-rw-r--r--zen/FindFilePlus/find_file_plus.cpp2
-rw-r--r--zen/error_log.h10
-rw-r--r--zen/file_handling.cpp238
-rw-r--r--zen/file_handling.h10
-rw-r--r--zen/file_io.cpp2
-rw-r--r--zen/file_io.h10
-rw-r--r--zen/file_traverser.cpp71
-rw-r--r--zen/file_update_handle.h70
-rw-r--r--zen/fixed_list.h53
-rw-r--r--zen/long_path_prefix.h2
-rw-r--r--zen/optional.h15
-rw-r--r--zen/read_txt.cpp12
-rw-r--r--zen/recycler.cpp68
-rw-r--r--zen/recycler.h4
-rw-r--r--zen/stl_tools.h17
-rw-r--r--zen/string_base.h8
-rw-r--r--zen/string_tools.h6
-rw-r--r--zen/string_traits.h5
-rw-r--r--zen/symlink_target.h2
-rw-r--r--zen/thread.h15
118 files changed, 6295 insertions, 5265 deletions
diff --git a/Application.cpp b/Application.cpp
index 21fe958e..6f16f004 100644
--- a/Application.cpp
+++ b/Application.cpp
@@ -5,24 +5,24 @@
// **************************************************************************
#include "application.h"
+#include <memory>
#include "ui/main_dlg.h"
#include <wx/msgdlg.h>
+#include <wx/sound.h>
+#include <wx/tooltip.h> //wxWidgets v2.9
+#include <wx/log.h>
+#include <zen/file_io.h>
+#include <zen/file_handling.h>
+#include <wx+/serialize.h>
+#include <wx+/app_main.h>
#include "comparison.h"
#include "algorithm.h"
#include "synchronization.h"
-#include <memory>
#include "ui/batch_status_handler.h"
#include "ui/check_version.h"
-#include <wx/file.h>
-#include "lib/resources.h"
#include "ui/switch_to_gui.h"
+#include "lib/resources.h"
#include "lib/ffs_paths.h"
-#include <wx+/app_main.h>
-#include <wx/sound.h>
-#include <zen/file_handling.h>
-#include <wx+/string_conv.h>
-#include <wx/log.h>
-#include <wx/tooltip.h> //wxWidgets v2.9
#include "lib/lock_holder.h"
#ifdef FFS_LINUX
@@ -275,27 +275,30 @@ bool Application::OnExceptionInMainLoop()
int Application::OnRun()
{
+ auto processException = [](const std::wstring& msg)
+ {
+ //it's not always possible to display a message box, e.g. corrupted stack, however low-level file output works!
+ try
+ {
+ saveBinStream(getConfigDir() + Zstr("LastError.txt"), utfCvrtTo<std::string>(msg)); //throw FileError
+ }
+ catch (const FileError&) {}
+
+ wxSafeShowMessage(_("An exception occurred!") + L" - FFS", msg);
+ };
+
try
{
wxApp::OnRun();
}
catch (const std::exception& e) //catch all STL exceptions
{
- //it's not always possible to display a message box, e.g. corrupted stack, however (non-stream) file output works!
- wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write);
- safeOutput.Write(utfCvrtTo<wxString>(e.what()));
-
- wxSafeShowMessage(_("An exception occurred!") + L" - FFS", utfCvrtTo<wxString>(e.what()));
+ processException(utfCvrtTo<std::wstring>(e.what()));
return FFS_RC_EXCEPTION;
}
catch (...) //catch the rest
{
- const wxString& msg = L"Unknown error.";
-
- wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write);
- safeOutput.Write(msg);
-
- wxSafeShowMessage(_("An exception occurred!"), msg);
+ processException(L"Unknown error.");
return FFS_RC_EXCEPTION;
}
diff --git a/BUILD/Changelog.txt b/BUILD/Changelog.txt
index 2591ad63..122f17fa 100644
--- a/BUILD/Changelog.txt
+++ b/BUILD/Changelog.txt
@@ -2,6 +2,28 @@
|FreeFileSync|
--------------
+Changelog v5.5
+--------------
+New database format for <automatic> variant: old database files are converted automatically
+Tuned performance for <automatic> variant when saving database for millions of files: > 95% faster
+Support partial database updates for <automatic> variant respecting current filter
+Reduced size of database files by 30%
+Fine-tuned <automatic> algorithm to avoid certain conflicts after changing comparison settings
+Lower peak memory consumption when reading database participating in multiple sync jobs
+Refined symlink categorization and <automatic> variant handling
+Always save log of last syncs to %appdata%\FreeFileSynce\LastSyncs.log (128 kB limit)
+"Save" and "Save As" menu options
+Properly show status message after save configuration
+Avoid issues applying file modification time on certain NAS
+Refined last-used configuration handling
+Avoid race-condition: database file is only read if directory is existing
+Protect against temporary network drop between comparison and synchronization
+Rearranged statistics panel to save vertical space when vertically aligned
+Removed limitation for number of conflicts shown in the warning message and log
+Consider both global and local filter when estimating whether folder could contain matches
+Updated translation files
+
+
Changelog v5.4
--------------
Copy all NTFS extended attributes
diff --git a/BUILD/FreeFileSync.chm b/BUILD/FreeFileSync.chm
index 09d8adab..94ea4923 100644
--- a/BUILD/FreeFileSync.chm
+++ b/BUILD/FreeFileSync.chm
Binary files differ
diff --git a/BUILD/Help/Table of Contents.hhc b/BUILD/Help/Table of Contents.hhc
index acee8f36..2995a868 100644
--- a/BUILD/Help/Table of Contents.hhc
+++ b/BUILD/Help/Table of Contents.hhc
@@ -28,7 +28,7 @@
<param name="Local" value="html\Batch Scripting.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
- <param name="Name" value="Compare by file size">
+ <param name="Name" value="Compare by file size only">
<param name="Local" value="html\Compare by File Size.html">
</OBJECT>
<LI> <OBJECT type="text/sitemap">
diff --git a/BUILD/Help/html/Compare by File Size.html b/BUILD/Help/html/Compare by File Size.html
index 81e4ab62..0dbb4fb8 100644
--- a/BUILD/Help/html/Compare by File Size.html
+++ b/BUILD/Help/html/Compare by File Size.html
@@ -5,7 +5,7 @@
<TITLE></TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
<META NAME="CREATED" CONTENT="20091206;16574000">
- <META NAME="CHANGED" CONTENT="20120511;23114500">
+ <META NAME="CHANGED" CONTENT="20120619;12310700">
<META NAME="Info 1" CONTENT="">
<META NAME="Info 2" CONTENT="">
<META NAME="Info 3" CONTENT="">
@@ -22,7 +22,7 @@
</HEAD>
<BODY LANG="en-US" DIR="LTR">
<H2 CLASS="western"><FONT FACE="Tahoma, sans-serif"><FONT SIZE=4 STYLE="font-size: 15pt">Compare
-by file size</FONT></FONT></H2>
+by file size only</FONT></FONT></H2>
<P STYLE="margin-bottom: 0cm"><BR>
</P>
<P STYLE="margin-bottom: 0cm"><FONT FACE="Tahoma, sans-serif">Sometimes
diff --git a/BUILD/Languages/chinese_simple.lng b/BUILD/Languages/chinese_simple.lng
index acd8a931..dbf75eac 100644
--- a/BUILD/Languages/chinese_simple.lng
+++ b/BUILD/Languages/chinese_simple.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>正在搜索文件夹 %x...</target>
+<source>Batch execution</source>
+<target>批处理执行</target>
+
+<source>Items processed:</source>
+<target>已处理的项目:</target>
+
+<source>Items remaining:</source>
+<target>剩余的项目:</target>
+
+<source>Total time:</source>
+<target>总共时间:</target>
+
<source>Show in Explorer</source>
<target>在Explorer中显示</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>关于</target>
-<source>Warning</source>
-<target>警告</target>
-
-<source>Question</source>
-<target>问题</target>
-
<source>Confirm</source>
<target>确认</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>信息</target>
+<source>Warning</source>
+<target>警告</target>
+
<source>Fatal Error</source>
<target>致命错误</target>
@@ -138,12 +147,6 @@
<pluralform>%x 字节</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>无法读取文件 %x .</target>
-
-<source>Cannot write file %x.</source>
-<target>无法写入文件 %x .</target>
-
<source>Database file %x is incompatible.</source>
<target>数据库文件 %x 不兼容.</target>
@@ -153,9 +156,18 @@
<source>Database file %x does not yet exist.</source>
<target>数据库文件 %x 还未存在.</target>
+<source>Database file is corrupt:</source>
+<target>数据库文件已损坏:</target>
+
<source>Out of memory!</source>
<target>内存不足!</target>
+<source>Cannot write file %x.</source>
+<target>无法写入文件 %x .</target>
+
+<source>Cannot read file %x.</source>
+<target>无法读取文件 %x .</target>
+
<source>Database files do not share a common session.</source>
<target>数据库文件并未共享一个公共会话.</target>
@@ -202,6 +214,9 @@
<source>/sec</source>
<target>/秒</target>
+<source>Cannot find file %x.</source>
+<target>无法找到文件 %x .</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>文件 %x 并未包含合法的配置.</target>
@@ -226,14 +241,11 @@
<source>Cannot read the following XML elements:</source>
<target>无法读取如下XML元素:</target>
-<source>Cannot find file %x.</source>
-<target>无法找到文件 %x .</target>
-
<source>&Open...</source>
<target>打开(&O)...</target>
-<source>&Save...</source>
-<target>保存(&S)...</target>
+<source>Save &As...</source>
+<target>另存为(&A)...</target>
<source>&Quit</source>
<target>退出(&Q)</target>
@@ -309,8 +321,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(Build: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>实时同步配置</target>
+<source>All files</source>
+<target>所有文件</target>
<source>&Restore</source>
<target>恢复(&R)</target>
@@ -324,8 +336,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>正在等待丢失的目录...</target>
-<source>An input folder name is empty.</source>
-<target>有一个输入的文件夹名为空.</target>
+<source>A folder input field is empty.</source>
+<target>有一个文件夹输入框为空.</target>
<source>Logging</source>
<target>记录</target>
@@ -348,26 +360,8 @@ The command is triggered if:
<source>Custom</source>
<target>自定义</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync 批处理文件</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync 配置</target>
-
-<source>Batch execution</source>
-<target>批处理执行</target>
-
-<source>Items processed:</source>
-<target>已处理的项目:</target>
-
-<source>Items remaining:</source>
-<target>剩余的项目:</target>
-
-<source>Total time:</source>
-<target>总共时间:</target>
-
-<source>Stop</source>
-<target>停止</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync批处理文件</target>
<source>Synchronization aborted!</source>
<target>同步已被中止!</target>
@@ -390,8 +384,8 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>无法链接到 Sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>FreeFileSync 有新版可用:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>已经有新版本的FreeFileSync可用:</target>
<source>Download now?</source>
<target>立即下载?</target>
@@ -435,6 +429,12 @@ The command is triggered if:
<source>Extension</source>
<target>扩展名</target>
+<source>Size:</source>
+<target>大小:</target>
+
+<source>Date:</source>
+<target>日期:</target>
+
<source>Action</source>
<target>动作</target>
@@ -468,6 +468,9 @@ The command is triggered if:
<source>&New</source>
<target>新建(&N)</target>
+<source>&Save</source>
+<target>保存(&S)</target>
+
<source>&Language</source>
<target>切换语言(&L)</target>
@@ -534,11 +537,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>将被删除的文件和文件夹数</target>
-<source>Total amount of data that will be transferred</source>
-<target>将被传输的数据总量</target>
-
-<source>Operation:</source>
-<target>操作:</target>
+<source>Total bytes to copy</source>
+<target>要复制的总字节数</target>
<source>Items found:</source>
<target>已找到的项目:</target>
@@ -546,10 +546,10 @@ The command is triggered if:
<source>Speed:</source>
<target>速度:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>剩余时间:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>已用时间:</target>
<source>Batch job</source>
@@ -672,6 +672,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>源代码用如下C++工具写成:</target>
+<source>If you like FreeFileSync</source>
+<target>如果你喜欢 FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>通过PayPal捐赠</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>非常感谢以下本地化 FreeFileSync 的工作人员:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>欢迎反馈意见和提出建议</target>
@@ -684,39 +693,9 @@ is the same
<source>Email</source>
<target>邮箱</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>非常感谢以下本地化 FreeFileSync 的工作人员:</target>
-
-<source>If you like FreeFileSync</source>
-<target>如果你喜欢 FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>通过PayPal捐赠</target>
-
<source>Published under the GNU General Public License</source>
<target>在GNU通用公共许可下发布</target>
-<source>Ignore further errors</source>
-<target>忽略之后出现的错误</target>
-
-<source>Hide further error messages during the current process</source>
-<target>在当前进程中隐藏进一步的错误信息</target>
-
-<source>&Ignore</source>
-<target>忽略(&I)</target>
-
-<source>Do not show this dialog again</source>
-<target>不要再显示此对话框</target>
-
-<source>&Switch</source>
-<target>切换(&S)</target>
-
-<source>&Yes</source>
-<target>是(&Y)</target>
-
-<source>&No</source>
-<target>否(&N)</target>
-
<source>Use Recycle Bin</source>
<target>使用回收站</target>
@@ -789,6 +768,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>统计</target>
+<source>Do not show this dialog again</source>
+<target>不要再显示此对话框</target>
+
<source>Find what:</source>
<target>要查找什么:</target>
@@ -867,8 +849,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>永不保存更改</target>
-<source>Save changes to current configuration?</source>
-<target>保存更改到当前配置?</target>
+<source>Do you want to save changes to %x?</source>
+<target>是否要保存修改到 %x ?</target>
+
+<source>Save</source>
+<target>保存</target>
+
+<source>Don't Save</source>
+<target>不保存</target>
<source>Configuration loaded!</source>
<target>配置已加载!</target>
@@ -963,9 +951,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>所有目录已同步!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>同步之前请先进行对比</target>
-
<source>Comma separated list</source>
<target>逗号分隔的列表</target>
@@ -1007,6 +992,24 @@ Note: File names must be relative to base directories!
<pluralform>%y 中的 %x 行可见</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>忽略之后出现的错误</target>
+
+<source>&Ignore</source>
+<target>忽略(&I)</target>
+
+<source>&Switch</source>
+<target>切换(&S)</target>
+
+<source>Question</source>
+<target>问题</target>
+
+<source>&Yes</source>
+<target>是(&Y)</target>
+
+<source>&No</source>
+<target>否(&N)</target>
+
<source>Scanning...</source>
<target>正扫描...</target>
@@ -1182,6 +1185,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>无法删除目录 %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>无法写入 %x 的文件属性.</target>
+
<source>Cannot write modification time of %x.</source>
<target>无法写入 %x 的最后修改时间.</target>
@@ -1206,9 +1212,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>无法复制符号连接 %x 到 %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>无法写入 %x 的文件属性.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>无法复制文件 %x 到 %y.</target>
@@ -1233,11 +1236,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>自从最后一次同步以来没有变动!</target>
-<source>Filter settings have changed!</source>
-<target>过滤设置已改变!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>此文件在最后一次同步中未被处理!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>根据当前设置相关的数据库入口并未同步.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>设置默认的同步方向:旧文件会被新文件覆盖.</target>
@@ -1365,14 +1365,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>更新 %x 的属性</target>
-<source>Target folder name must not be empty.</source>
-<target>目标文件夹名必须不是空的.</target>
+<source>Target folder input field must not be empty.</source>
+<target>目标文件夹输入框必须不为空.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>存放历史版本的文件夹名必须不是空的.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>用于存放历史版本的文件夹输入框必须不为空.</target>
-<source>Source directory %x not found.</source>
-<target>来源目录 %x 无法找到.</target>
+<source>Source folder %x not found.</source>
+<target>无法找到源文件夹 %x.</target>
<source>Unresolved conflicts existing!</source>
<target>存在不可解决的冲突!</target>
@@ -1389,11 +1389,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>没有足够的可用磁盘空间用于:</target>
-<source>Free disk space required:</source>
-<target>需要可用的磁盘空间:</target>
+<source>Required:</source>
+<target>必需:</target>
-<source>Free disk space available:</source>
-<target>可用磁盘空间:</target>
+<source>Available:</source>
+<target>可用:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>如下路径的回收站不可用! 文件会被永久删除:</target>
@@ -1404,6 +1404,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>正在处理成对文件夹:</target>
+<source>Target folder %x already existing.</source>
+<target>目标文件夹 %x 已经存在.</target>
+
<source>Generating database...</source>
<target>正在生成数据库...</target>
diff --git a/BUILD/Languages/chinese_traditional.lng b/BUILD/Languages/chinese_traditional.lng
index 72e3cfe2..ab6f6be8 100644
--- a/BUILD/Languages/chinese_traditional.lng
+++ b/BUILD/Languages/chinese_traditional.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>正在搜尋資料夾 %x...</target>
+<source>Batch execution</source>
+<target>批次處理執行</target>
+
+<source>Items processed:</source>
+<target>已處理項目:</target>
+
+<source>Items remaining:</source>
+<target>剩餘項目:</target>
+
+<source>Total time:</source>
+<target>全部時間:</target>
+
<source>Show in Explorer</source>
<target>在資源管理器中顯示</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>關於</target>
-<source>Warning</source>
-<target>警告</target>
-
-<source>Question</source>
-<target>問題</target>
-
<source>Confirm</source>
<target>確認</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>訊息</target>
+<source>Warning</source>
+<target>警告</target>
+
<source>Fatal Error</source>
<target>嚴重錯誤</target>
@@ -138,12 +147,6 @@
<pluralform>%x 位元組</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>無法讀取檔案 %X。</target>
-
-<source>Cannot write file %x.</source>
-<target>無法寫入檔案 %X。</target>
-
<source>Database file %x is incompatible.</source>
<target>資料庫檔案 %x 是不相容的。</target>
@@ -153,9 +156,18 @@
<source>Database file %x does not yet exist.</source>
<target>資料庫檔案 %x 並不存在。</target>
+<source>Database file is corrupt:</source>
+<target>資料庫檔案已損毀:</target>
+
<source>Out of memory!</source>
<target>記憶體不足!</target>
+<source>Cannot write file %x.</source>
+<target>無法寫入檔案 %X。</target>
+
+<source>Cannot read file %x.</source>
+<target>無法讀取檔案 %X。</target>
+
<source>Database files do not share a common session.</source>
<target>資料庫檔案不會共享一個共同的連線。</target>
@@ -202,6 +214,9 @@
<source>/sec</source>
<target>/秒</target>
+<source>Cannot find file %x.</source>
+<target>找不到檔案 %x。</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>檔案 %x 不包含一個有效的配置。</target>
@@ -226,14 +241,11 @@
<source>Cannot read the following XML elements:</source>
<target>無法讀取下列XML元素:</target>
-<source>Cannot find file %x.</source>
-<target>找不到檔案 %x。</target>
-
<source>&Open...</source>
<target>開啟(&O)...</target>
-<source>&Save...</source>
-<target>儲存(&S)...</target>
+<source>Save &As...</source>
+<target>另存新檔(&A)...</target>
<source>&Quit</source>
<target>離開(&Q)</target>
@@ -309,8 +321,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(建立:%x)</target>
-<source>RealtimeSync configuration</source>
-<target>即時同步配置</target>
+<source>All files</source>
+<target>所有檔案</target>
<source>&Restore</source>
<target>還原(&R)</target>
@@ -324,8 +336,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>等待缺少的目錄...</target>
-<source>An input folder name is empty.</source>
-<target>輸入的資料夾名稱為空。</target>
+<source>A folder input field is empty.</source>
+<target>資料夾輸入欄位是空的。</target>
<source>Logging</source>
<target>日誌記錄</target>
@@ -348,26 +360,8 @@ The command is triggered if:
<source>Custom</source>
<target>自訂</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync批次檔</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync配置</target>
-
-<source>Batch execution</source>
-<target>批次處理執行</target>
-
-<source>Items processed:</source>
-<target>已處理項目:</target>
-
-<source>Items remaining:</source>
-<target>剩餘項目:</target>
-
-<source>Total time:</source>
-<target>全部時間:</target>
-
-<source>Stop</source>
-<target>停止</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync批次處理</target>
<source>Synchronization aborted!</source>
<target>同步已中止!</target>
@@ -390,18 +384,18 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>無法連接到sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>有較新版本的FreeFileSync可用:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>FreeFileSync有新版本可用:</target>
<source>Download now?</source>
<target>要立即下載嗎?</target>
-<source>Information</source>
-<target>訊息</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync已經是最新版本!</target>
+<source>Information</source>
+<target>訊息</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>要每週自動檢查更新FreeFileSync嗎?</target>
@@ -435,6 +429,12 @@ The command is triggered if:
<source>Extension</source>
<target>擴展</target>
+<source>Size:</source>
+<target>大小:</target>
+
+<source>Date:</source>
+<target>資料:</target>
+
<source>Action</source>
<target>動作</target>
@@ -468,6 +468,9 @@ The command is triggered if:
<source>&New</source>
<target>新增專案(&N)</target>
+<source>&Save</source>
+<target>儲存(&S)</target>
+
<source>&Language</source>
<target>語言(&L)</target>
@@ -534,11 +537,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>將被刪除的檔案和資料夾數量</target>
-<source>Total amount of data that will be transferred</source>
-<target>將被傳輸的總資料量</target>
-
-<source>Operation:</source>
-<target>操作:</target>
+<source>Total bytes to copy</source>
+<target>要複製的位元組總數</target>
<source>Items found:</source>
<target>尋找項目:</target>
@@ -546,10 +546,10 @@ The command is triggered if:
<source>Speed:</source>
<target>速度:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>剩餘時間:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>經過時間:</target>
<source>Batch job</source>
@@ -663,6 +663,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>使用C++編寫的原始碼</target>
+<source>If you like FreeFileSync</source>
+<target>如果你喜歡FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>使用PayPal捐款</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>非常感謝FreeFileSync當地語系化的工作人員:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>歡迎反饋意見和建議</target>
@@ -675,39 +684,9 @@ is the same
<source>Email</source>
<target>信箱</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>非常感謝FreeFileSync當地語系化的工作人員:</target>
-
-<source>If you like FreeFileSync</source>
-<target>如果你喜歡FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>使用PayPal捐款</target>
-
<source>Published under the GNU General Public License</source>
<target>在GNU通用公共許可證下發佈</target>
-<source>Ignore further errors</source>
-<target>忽略進一步錯誤</target>
-
-<source>Hide further error messages during the current process</source>
-<target>在目前進程中隱藏進一步的錯誤訊息</target>
-
-<source>&Ignore</source>
-<target>忽略(&I)</target>
-
-<source>Do not show this dialog again</source>
-<target>不要再顯示此對話框</target>
-
-<source>&Switch</source>
-<target>切換(&S)</target>
-
-<source>&Yes</source>
-<target>是(&Y)</target>
-
-<source>&No</source>
-<target>否(&N)</target>
-
<source>Use Recycle Bin</source>
<target>使用資源回收筒</target>
@@ -780,6 +759,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>統計</target>
+<source>Do not show this dialog again</source>
+<target>不要再顯示此對話框</target>
+
<source>Find what:</source>
<target>尋找內容:</target>
@@ -856,10 +838,16 @@ Note: File names must be relative to base directories!
<target>配置已儲存!</target>
<source>Never save changes</source>
-<target>從不儲存更改</target>
+<target>從不更改儲存</target>
+
+<source>Do you want to save changes to %x?</source>
+<target>是否要更改儲存到 %x?</target>
-<source>Save changes to current configuration?</source>
-<target>要儲存目前配置的更改嗎?</target>
+<source>Save</source>
+<target>儲存</target>
+
+<source>Don't Save</source>
+<target>不要儲存</target>
<source>Configuration loaded!</source>
<target>配置已載入!</target>
@@ -954,9 +942,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>同步所有目錄!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>執行同步前請先比對!</target>
-
<source>Comma separated list</source>
<target>逗號分隔清單</target>
@@ -998,6 +983,24 @@ Note: File names must be relative to base directories!
<pluralform>顯示 %y 之 %x 行</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>忽略進一步錯誤</target>
+
+<source>&Ignore</source>
+<target>忽略(&I)</target>
+
+<source>&Switch</source>
+<target>切換(&S)</target>
+
+<source>Question</source>
+<target>問題</target>
+
+<source>&Yes</source>
+<target>是(&Y)</target>
+
+<source>&No</source>
+<target>否(&N)</target>
+
<source>Scanning...</source>
<target>正在掃瞄...</target>
@@ -1173,6 +1176,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>無法刪除目錄 %x。</target>
+<source>Cannot write file attributes of %x.</source>
+<target>無法寫入 %x 的檔案屬性。</target>
+
<source>Cannot write modification time of %x.</source>
<target>無法寫入 %x 的修改時間。</target>
@@ -1197,9 +1203,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>無法複製符號連結 %x 到 %y。</target>
-<source>Cannot write file attributes of %x.</source>
-<target>無法寫入 %x 的檔案屬性。</target>
-
<source>Cannot copy file %x to %y.</source>
<target>無法複製檔案 %x 到 %y。</target>
@@ -1224,11 +1227,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>自上次同步以來都沒有更改!</target>
-<source>Filter settings have changed!</source>
-<target>篩選器設定已更改!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>上次同步時該檔案未被處理!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>相應的資料庫條目在同步時,不考慮到目前的設定。</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>設定預設同步方向:舊檔案會被較新的檔案覆蓋。</target>
@@ -1356,14 +1356,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>正在更新 %x 個屬性</target>
-<source>Target folder name must not be empty.</source>
-<target>目的資料夾名稱不能為空。</target>
+<source>Target folder input field must not be empty.</source>
+<target>目標資料夾輸入欄位不能為空。</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>檔案版本控制資料夾的名稱不能為空。</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>版本控制資料夾輸入欄位不能為空。</target>
-<source>Source directory %x not found.</source>
-<target>來源目錄 %x 找不到。</target>
+<source>Source folder %x not found.</source>
+<target>來源資料夾 %x 找不到。</target>
<source>Unresolved conflicts existing!</source>
<target>存在未解決的衝突!</target>
@@ -1380,11 +1380,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>沒有足夠的可用空間:</target>
-<source>Free disk space required:</source>
-<target>所需要的可用磁碟空間:</target>
+<source>Required:</source>
+<target>必要:</target>
-<source>Free disk space available:</source>
-<target>可用磁碟空間:</target>
+<source>Available:</source>
+<target>可用:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>資源回收筒不可用於以下路徑!相反的,檔案將永遠被刪除:</target>
@@ -1395,6 +1395,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>處理一對資料夾:</target>
+<source>Target folder %x already existing.</source>
+<target>目標資料夾 %x 已存在。</target>
+
<source>Generating database...</source>
<target>正在產生資料庫...</target>
diff --git a/BUILD/Languages/croatian.lng b/BUILD/Languages/croatian.lng
index bad3c10d..6a07aff7 100644
--- a/BUILD/Languages/croatian.lng
+++ b/BUILD/Languages/croatian.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Tražim mapu %x...</target>
+<source>Batch execution</source>
+<target>Slijedno izvršavanje</target>
+
+<source>Items processed:</source>
+<target>Obrađeni elementi:</target>
+
+<source>Items remaining:</source>
+<target>Preostale stavke:</target>
+
+<source>Total time:</source>
+<target>Ukupno vrijeme:</target>
+
<source>Show in Explorer</source>
<target>Prikaži u Exploreru</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>O programu</target>
-<source>Warning</source>
-<target>Oprez</target>
-
-<source>Question</source>
-<target>Pitanje</target>
-
<source>Confirm</source>
<target>Potvrdi</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Oprez</target>
+
<source>Fatal Error</source>
<target>Kritična greška</target>
@@ -140,12 +149,6 @@
<pluralform>%x Bajtova</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Ne mogu čitati datoteku</target>
-
-<source>Cannot write file %x.</source>
-<target>Ne mogu zapisati datoteku</target>
-
<source>Database file %x is incompatible.</source>
<target>Datoteka baze %x je nekompatibilna</target>
@@ -155,9 +158,18 @@
<source>Database file %x does not yet exist.</source>
<target>Datoteka baze %x još ne postoji</target>
+<source>Database file is corrupt:</source>
+<target>Baza je oštećena:</target>
+
<source>Out of memory!</source>
<target>Nedostatak memorije</target>
+<source>Cannot write file %x.</source>
+<target>Ne mogu zapisati datoteku</target>
+
+<source>Cannot read file %x.</source>
+<target>Ne mogu čitati datoteku</target>
+
<source>Database files do not share a common session.</source>
<target>Datoteke baze ne dijele zajednički protokol</target>
@@ -208,6 +220,9 @@
<source>/sec</source>
<target>/sek</target>
+<source>Cannot find file %x.</source>
+<target>Ne mogu pronaći datoteku %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Datoteka %x ne sadrži valjanu konfiguraciju</target>
@@ -232,14 +247,11 @@
<source>Cannot read the following XML elements:</source>
<target>Ne mogu čitati slijedeće XML elemente</target>
-<source>Cannot find file %x.</source>
-<target>Ne mogu pronaći datoteku %x.</target>
-
<source>&Open...</source>
<target>&Otvori...</target>
-<source>&Save...</source>
-<target>&Spremi...</target>
+<source>Save &As...</source>
+<target>Spremi kao...</target>
<source>&Quit</source>
<target>&Izlaz</target>
@@ -315,8 +327,8 @@ Naredba će biti pokrenuta ako se:
<source>(Build: %x)</source>
<target>(Inačnica: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync postavke</target>
+<source>All files</source>
+<target>Sve datoteke</target>
<source>&Restore</source>
<target>&Vrati</target>
@@ -330,8 +342,8 @@ Naredba će biti pokrenuta ako se:
<source>Waiting for missing directories...</source>
<target>Čekam nedostajuće direktorije...</target>
-<source>An input folder name is empty.</source>
-<target>Ime ulazne mape je prazno.</target>
+<source>A folder input field is empty.</source>
+<target>Polje za odabir foldera je prazno.</target>
<source>Logging</source>
<target>Zapisivanje</target>
@@ -354,26 +366,8 @@ Naredba će biti pokrenuta ako se:
<source>Custom</source>
<target>Uobičajeno</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync slijedna datoteka</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync postavke</target>
-
-<source>Batch execution</source>
-<target>Slijedno izvršavanje</target>
-
-<source>Items processed:</source>
-<target>Obrađeni elementi:</target>
-
-<source>Items remaining:</source>
-<target>Preostale stavke:</target>
-
-<source>Total time:</source>
-<target>Ukupno vrijeme:</target>
-
-<source>Stop</source>
-<target>Zaustavi</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync slijedni zadatak</target>
<source>Synchronization aborted!</source>
<target>Sinkronizacija prekinuta!</target>
@@ -396,8 +390,8 @@ Naredba će biti pokrenuta ako se:
<source>Unable to connect to sourceforge.net!</source>
<target>Ne mogu se povezati na sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Dostupna je nova verzija FreeFileSync:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Nova verzija FreeFileSync je dostupna:</target>
<source>Download now?</source>
<target>Preuzeti sada?</target>
@@ -441,6 +435,12 @@ Naredba će biti pokrenuta ako se:
<source>Extension</source>
<target>Ekstenzija</target>
+<source>Size:</source>
+<target>Veličina:</target>
+
+<source>Date:</source>
+<target>Datum:</target>
+
<source>Action</source>
<target>Radnja</target>
@@ -474,6 +474,9 @@ Naredba će biti pokrenuta ako se:
<source>&New</source>
<target>&Novo</target>
+<source>&Save</source>
+<target>&Spremi</target>
+
<source>&Language</source>
<target>&Jezik</target>
@@ -540,11 +543,8 @@ Naredba će biti pokrenuta ako se:
<source>Number of files and folders that will be deleted</source>
<target>Broj datoteka i mapa koje će se izbrisati</target>
-<source>Total amount of data that will be transferred</source>
-<target>Ukupna količina podataka koja će biti prebečana</target>
-
-<source>Operation:</source>
-<target>Operacija:</target>
+<source>Total bytes to copy</source>
+<target>Ukupno bajta za kopirati</target>
<source>Items found:</source>
<target>Pronađene stavke:</target>
@@ -552,11 +552,11 @@ Naredba će biti pokrenuta ako se:
<source>Speed:</source>
<target>Brzina:</target>
-<source>Remaining time:</source>
-<target>Vremena preostalo:</target>
+<source>Time remaining:</source>
+<target>Preostalo vremena:</target>
-<source>Elapsed time:</source>
-<target>Vremena prošlo:</target>
+<source>Time elapsed:</source>
+<target>Proteklo vremena:</target>
<source>Batch job</source>
<target>Slijedni zadatak</target>
@@ -678,6 +678,15 @@ jednak
<source>Source code written in C++ utilizing:</source>
<target>Izvorni kod napisan u C++ uz korištenje:</target>
+<source>If you like FreeFileSync</source>
+<target>Ako volite FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Doniraj s PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Zahvale za prijevod FreeFileSync idu:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Povratne informacije i prijedlozi su dobrodošli</target>
@@ -690,39 +699,9 @@ jednak
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Zahvale za prijevod FreeFileSync idu:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Ako volite FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Doniraj s PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Objavljeno pod licencom GNU General Public</target>
-<source>Ignore further errors</source>
-<target>Zanemari buduće greške</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Sakrij iduće poruke grešaka tokom slijedećeg procesa</target>
-
-<source>&Ignore</source>
-<target>&Ignoriraj</target>
-
-<source>Do not show this dialog again</source>
-<target>Ne prikazuj ovaj prozor ponovno</target>
-
-<source>&Switch</source>
-<target>&Zamjeni</target>
-
-<source>&Yes</source>
-<target>&Da</target>
-
-<source>&No</source>
-<target>&Ne</target>
-
<source>Use Recycle Bin</source>
<target>Uporabi Koš za smeće</target>
@@ -795,6 +774,9 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Statistics</source>
<target>Statistika</target>
+<source>Do not show this dialog again</source>
+<target>Ne prikazuj ovaj prozor ponovno</target>
+
<source>Find what:</source>
<target>Nađi što</target>
@@ -873,8 +855,14 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Never save changes</source>
<target>Nikad ne spremaj promjene</target>
-<source>Save changes to current configuration?</source>
-<target>Spremiti promjene na trenutne postavke?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Da li želite spremiti izmjene za %x?</target>
+
+<source>Save</source>
+<target>Spremiti</target>
+
+<source>Don't Save</source>
+<target>Nemoj spremati</target>
<source>Configuration loaded!</source>
<target>Postavke učitane!</target>
@@ -969,9 +957,6 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>All directories in sync!</source>
<target>Svi direktoriji su sinkronizirani!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Molmo pokrenite Usporedbu prije sinkronizacije!</target>
-
<source>Comma separated list</source>
<target>Zarezom odvojene liste</target>
@@ -1021,6 +1006,24 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<pluralform>%x od %y redova u prikazu</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Zanemari buduće greške</target>
+
+<source>&Ignore</source>
+<target>&Ignoriraj</target>
+
+<source>&Switch</source>
+<target>&Zamjeni</target>
+
+<source>Question</source>
+<target>Pitanje</target>
+
+<source>&Yes</source>
+<target>&Da</target>
+
+<source>&No</source>
+<target>&Ne</target>
+
<source>Scanning...</source>
<target>Pregledajem...</target>
@@ -1206,6 +1209,9 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Cannot delete directory %x.</source>
<target>Ne mogu izbrisati mapu %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Ne mogu zapisati svojstva od %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Ne mogu zapisati vrijeme izmjene %x.</target>
@@ -1230,9 +1236,6 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Ne mogu kopirati simboličnu poveznicu %x na %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Ne mogu zapisati svojstva od %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Ne mogu kopirati datoteku %x na %y.</target>
@@ -1257,11 +1260,8 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>No change since last synchronization!</source>
<target>Nema promjena od zadnje sinkronizacije!</target>
-<source>Filter settings have changed!</source>
-<target>Filterske postavke su promjenjene!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Datoteka nije procesirana tokom prošle sinkronizacije !</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Spomenuti unosi baze nisu u sinkronizaciji gledajući trenutne postavke.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Postavljam zadani sinkronizacijski smijer: Stare datoteke će biti prepisane novim datotekama.</target>
@@ -1389,13 +1389,13 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Updating attributes of %x</source>
<target>Obnavljam atribute od %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Naziv odredišne mape ne može biti prazan.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Odredišna mapa ne može biti prazna</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Naziv mape za datotečni raspored ne može biti prazan</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Mapa unosa ne smije biti prazan</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>Izvorna mapa %x nije pronađena</target>
<source>Unresolved conflicts existing!</source>
@@ -1413,11 +1413,11 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Not enough free disk space available in:</source>
<target>Nedovoljno prostora na disku:</target>
-<source>Free disk space required:</source>
-<target>Potreban prostor na disku:</target>
+<source>Required:</source>
+<target>Potrebno:</target>
-<source>Free disk space available:</source>
-<target>Prostor na disku dostupan:</target>
+<source>Available:</source>
+<target>Dostupno:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Koš za smeće nije dostupan za navedene putanje! Umjesto toga datoteke će biti trajno izbrisane:</target>
@@ -1428,6 +1428,9 @@ Napomena: Imena datoteka moraju biti srodni s glavnim mapama!
<source>Processing folder pair:</source>
<target>Obrađujem parove mapa:</target>
+<source>Target folder %x already existing.</source>
+<target>Odredišna mapa %x već postoji.</target>
+
<source>Generating database...</source>
<target>Izrađujem bazu podataka...</target>
diff --git a/BUILD/Languages/czech.lng b/BUILD/Languages/czech.lng
index bfc42fc0..a294e21c 100644
--- a/BUILD/Languages/czech.lng
+++ b/BUILD/Languages/czech.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>O Programu</target>
-<source>Warning</source>
-<target>Varování</target>
-
-<source>Question</source>
-<target>Dotaz</target>
-
<source>Confirm</source>
<target>Potvrdit</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Varování</target>
+
<source>Fatal Error</source>
<target>Závažná chyba</target>
@@ -140,12 +137,6 @@
<pluralform>%x B</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Nelze číst soubor %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Nelze zapsat soubor %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Chybný formát databáze %x.</target>
@@ -155,9 +146,18 @@
<source>Database file %x does not yet exist.</source>
<target>Databázový soubor %x neexistuje.</target>
+<source>Database file is corrupt:</source>
+<target>Databáze je poškozená:</target>
+
<source>Out of memory!</source>
<target>Nedostatek pracovní paměti!</target>
+<source>Cannot write file %x.</source>
+<target>Nelze zapsat soubor %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Nelze číst soubor %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Databázové soubory nejsou navzájem komplementární.</target>
@@ -208,6 +208,9 @@
<source>/sec</source>
<target>/s</target>
+<source>Cannot find file %x.</source>
+<target>Nelze najít soubor %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Soubor %x neobsahuje platnou konfiguraci.</target>
@@ -229,17 +232,14 @@
<source>Volume name %x not part of file name %y!</source>
<target>Disk %x není součástí jména souboru %y!</target>
-<source>Cannot find file %x.</source>
-<target>Nalze najít soubor %x.</target>
-
<source>Cannot read the following XML elements:</source>
<target>Nelze načíst následující XML elementy:</target>
<source>&Open...</source>
<target>&Otevřít...</target>
-<source>&Save...</source>
-<target>&Uložit</target>
+<source>Save &As...</source>
+<target>Uložit &jako...</target>
<source>&Quit</source>
<target>U&končit</target>
@@ -315,8 +315,8 @@ Příkaz je spuštěn když:
<source>(Build: %x)</source>
<target>(Build: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Konfigurace RealtimeSync</target>
+<source>All files</source>
+<target>Všechny soubory</target>
<source>&Restore</source>
<target>&Obnovit</target>
@@ -330,7 +330,7 @@ Příkaz je spuštěn když:
<source>Waiting for missing directories...</source>
<target>Čekání na nedostupné adresáře...</target>
-<source>An input folder name is empty.</source>
+<source>A folder input field is empty.</source>
<target>Není zadána vstupní složka.</target>
<source>Logging</source>
@@ -354,11 +354,8 @@ Příkaz je spuštěn když:
<source>Custom</source>
<target>Vlastní</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync dávkový soubor</target>
-
-<source>FreeFileSync configuration</source>
-<target>Konfigurace FreeFileSync</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync dávka</target>
<source>Batch execution</source>
<target>Spuštění dávky</target>
@@ -396,18 +393,18 @@ Příkaz je spuštěn když:
<source>Unable to connect to sourceforge.net!</source>
<target>Není možné se připojit k sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Je dostupná novější verze FreeFileSync:</target>
<source>Download now?</source>
<target>Stáhnout nyní?</target>
-<source>Information</source>
-<target>Informace</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync je aktuální!</target>
+<source>Information</source>
+<target>Informace</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Chcete aby FreeFileSync automaticky zjišťoval aktualizace každý týden?</target>
@@ -441,6 +438,12 @@ Příkaz je spuštěn když:
<source>Extension</source>
<target>Přípona</target>
+<source>Size:</source>
+<target>Velikost:</target>
+
+<source>Date:</source>
+<target>Čas:</target>
+
<source>Action</source>
<target>Akce</target>
@@ -474,6 +477,9 @@ Příkaz je spuštěn když:
<source>&New</source>
<target>&Nový</target>
+<source>&Save</source>
+<target>&Uložit</target>
+
<source>&Language</source>
<target>&Jazyk</target>
@@ -540,11 +546,8 @@ Příkaz je spuštěn když:
<source>Number of files and folders that will be deleted</source>
<target>Počet souborů a složek ke smazání</target>
-<source>Total amount of data that will be transferred</source>
-<target>Celkový objem dat, který bude přenesen</target>
-
-<source>Operation:</source>
-<target>Operace:</target>
+<source>Total bytes to copy</source>
+<target>Celkový objem dat</target>
<source>Items found:</source>
<target>Nalezeno položek:</target>
@@ -552,10 +555,10 @@ Příkaz je spuštěn když:
<source>Speed:</source>
<target>Rychlost:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Zbývající čas:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Uplynulý čas:</target>
<source>Batch job</source>
@@ -678,6 +681,15 @@ je stejný
<source>Source code written in C++ utilizing:</source>
<target>Zdrojový kód byl napsán kompletně v C++ s pomocí:</target>
+<source>If you like FreeFileSync</source>
+<target>Pokud se Vám FreeFileSync líbí</target>
+
+<source>Donate with PayPal</source>
+<target>Přispět pomocí PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Poděkování za překlad FreeFileSync:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Komentáře a náměty jsou vždy vítány</target>
@@ -690,39 +702,9 @@ je stejný
<source>Email</source>
<target>Napište</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Poděkování za překlad FreeFileSync:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Pokud se Vám FreeFileSync líbí</target>
-
-<source>Donate with PayPal</source>
-<target>Přispět pomocí PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Vydáno pod GNU General Public License (GPL)</target>
-<source>Ignore further errors</source>
-<target>Přeskočit další chyby</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Nezobrazovat další chybová hlášení během zpracování</target>
-
-<source>&Ignore</source>
-<target>&Pokračovat</target>
-
-<source>Do not show this dialog again</source>
-<target>Tento dialog již nezobrazovat</target>
-
-<source>&Switch</source>
-<target>&Přepnout</target>
-
-<source>&Yes</source>
-<target>&Ano</target>
-
-<source>&No</source>
-<target>&Ne</target>
-
<source>Use Recycle Bin</source>
<target>Použít Koš</target>
@@ -795,6 +777,9 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Statistics</source>
<target>Statistika</target>
+<source>Do not show this dialog again</source>
+<target>Tento dialog již nezobrazovat</target>
+
<source>Find what:</source>
<target>Najít:</target>
@@ -873,8 +858,14 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Never save changes</source>
<target>Nikdy neukládat změny</target>
-<source>Save changes to current configuration?</source>
-<target>Uložit změny do aktuální konfigurace?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Uložit změny do %x?</target>
+
+<source>Save</source>
+<target>Uložit></target>
+
+<source>Don't Save</source>
+<target>Neukládat</target>
<source>Configuration loaded!</source>
<target>Konfigurace načtena.</target>
@@ -969,9 +960,6 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>All directories in sync!</source>
<target>Všechny adresáře jsou synchronizovány!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Prosím proveďte nejdřív porovnání před synchronizací!</target>
-
<source>Comma separated list</source>
<target>Text oddělený čárkami</target>
@@ -1021,6 +1009,24 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<pluralform>%x z %y řádků</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Přeskočit další chyby</target>
+
+<source>&Ignore</source>
+<target>&Pokračovat</target>
+
+<source>&Switch</source>
+<target>&Přepnout</target>
+
+<source>Question</source>
+<target>Dotaz</target>
+
+<source>&Yes</source>
+<target>&Ano</target>
+
+<source>&No</source>
+<target>&Ne</target>
+
<source>Scanning...</source>
<target>Zpracovávání...</target>
@@ -1206,6 +1212,9 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Cannot delete directory %x.</source>
<target>Nelze smazat adresář %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nelze zapsat atributy souboru %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Nelze nastavit atribut času změny pro %x.</target>
@@ -1230,9 +1239,6 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Cannot copy symbolic link %x to %y.</source>
<target>Nelze kopítovat zástupce %x do %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Nelze zapsat atributy souboru %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Nelze kopírovat soubor %x do %y.</target>
@@ -1257,11 +1263,8 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>No change since last synchronization!</source>
<target>Žádné změny od poslední synchronizace!</target>
-<source>Filter settings have changed!</source>
-<target>Nastavení filtru bylo změněno!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Soubor nebyl poslední synchronizací zpracován!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Databázové položky nejsou podle aktuální konfigurace synchronní.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Nastaven výchozí způsob synchronizace: Staré soubory budou nahrazeny novými.</target>
@@ -1389,14 +1392,14 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Updating attributes of %x</source>
<target>Aktualizace atributů souboru %x</target>
-<source>Target folder name must not be empty.</source>
+<source>Target folder input field must not be empty.</source>
<target>Cílová složka nesmí být prázdná.</target>
-<source>Folder name for file versioning must not be empty.</source>
+<source>Folder input field for versioning must not be empty.</source>
<target>Složka pro verzování souborů nesmí být prázdná.</target>
-<source>Source directory %x not found.</source>
-<target>Zdrojový adresář %x nelze najít.</target>
+<source>Source folder %x not found.</source>
+<target>Zdrojovou složku %x nelze najít.</target>
<source>Unresolved conflicts existing!</source>
<target>Nevyřešené konflikty!</target>
@@ -1413,11 +1416,11 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Not enough free disk space available in:</source>
<target>Nedostatek místa na disku:</target>
-<source>Free disk space required:</source>
-<target>Požadované volné místo na disku:</target>
+<source>Required:</source>
+<target>Požadováno</target>
-<source>Free disk space available:</source>
-<target>Volné místo k dispozici:</target>
+<source>Available:</source>
+<target>K dispozici</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Nelze použít Koš pro následující umístění! Soubory budou odstraněny trvale:</target>
@@ -1428,6 +1431,9 @@ Poznámka: Filtr je aplikován relativně k základním adresářům.
<source>Processing folder pair:</source>
<target>Zpracovávání adresářové páru:</target>
+<source>Target folder %x already existing.</source>
+<target>Cílova složka %x již existuje.</target>
+
<source>Generating database...</source>
<target>Vytváření databáze...</target>
diff --git a/BUILD/Languages/danish.lng b/BUILD/Languages/danish.lng
index 4c9c2cac..4ebecf69 100644
--- a/BUILD/Languages/danish.lng
+++ b/BUILD/Languages/danish.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Søger efter mappen %x...</target>
+<source>Batch execution</source>
+<target>Batch afvikling</target>
+
+<source>Items processed:</source>
+<target>Enheder behandlet:</target>
+
+<source>Items remaining:</source>
+<target>Enheder tilbage:</target>
+
+<source>Total time:</source>
+<target>Samlet tid:</target>
+
<source>Show in Explorer</source>
<target>Vis i Explorer</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>Om</target>
-<source>Warning</source>
-<target>Advarsel</target>
-
-<source>Question</source>
-<target>Spørgsmål</target>
-
<source>Confirm</source>
<target>Bekræft</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Advarsel</target>
+
<source>Fatal Error</source>
<target>Uoprettelig Fejl</target>
@@ -139,12 +148,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Kan ikke læse filen %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Kan ikke skrive filen %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Database filen %x er ikke kompatibel.</target>
@@ -154,9 +157,18 @@
<source>Database file %x does not yet exist.</source>
<target>Database filen %x findes ikke.</target>
+<source>Database file is corrupt:</source>
+<target>Database filen er ødelagt:</target>
+
<source>Out of memory!</source>
<target>Ude af hukommelse!</target>
+<source>Cannot write file %x.</source>
+<target>Kan ikke skrive filen %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Kan ikke læse filen %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Database filen kan ikke deles.</target>
@@ -205,6 +217,9 @@
<source>/sec</source>
<target>/sek</target>
+<source>Cannot find file %x.</source>
+<target>Kan ikke finde filen %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>%x indeholder ikke en gyldig konfiguration.</target>
@@ -229,14 +244,11 @@
<source>Cannot read the following XML elements:</source>
<target>Kan ikke læse følgende XML emner:</target>
-<source>Cannot find file %x.</source>
-<target>Kan ikke finde filen %x.</target>
-
<source>&Open...</source>
<target>&Åben...</target>
-<source>&Save...</source>
-<target>&Gem...</target>
+<source>Save &As...</source>
+<target>Gem &Som...</target>
<source>&Quit</source>
<target>&Afslut</target>
@@ -312,8 +324,8 @@ Kommandoen udføres hvis:
<source>(Build: %x)</source>
<target>(Build: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSynk konfiguration</target>
+<source>All files</source>
+<target>Alle filer</target>
<source>&Restore</source>
<target>&Gendan</target>
@@ -327,8 +339,8 @@ Kommandoen udføres hvis:
<source>Waiting for missing directories...</source>
<target>Venter på manglende biblioteker...</target>
-<source>An input folder name is empty.</source>
-<target>Et mappe navn er blankt.</target>
+<source>A folder input field is empty.</source>
+<target>Et mappe felt er tomt.</target>
<source>Logging</source>
<target>Logger</target>
@@ -351,26 +363,8 @@ Kommandoen udføres hvis:
<source>Custom</source>
<target>Brugerdefineret</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync batch fil</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync konfiguration</target>
-
-<source>Batch execution</source>
-<target>Batch afvikling</target>
-
-<source>Items processed:</source>
-<target>Enheder behandlet:</target>
-
-<source>Items remaining:</source>
-<target>Enheder tilbage:</target>
-
-<source>Total time:</source>
-<target>Samlet tid:</target>
-
-<source>Stop</source>
-<target>Stop</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync batch</target>
<source>Synchronization aborted!</source>
<target>Synkronisering afbrudt!</target>
@@ -393,18 +387,18 @@ Kommandoen udføres hvis:
<source>Unable to connect to sourceforge.net!</source>
<target>Kan ikke forbinde til sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>En nyere version af FreeFileSync er tilgængelig:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>En ny version af FreeFilesyns er tilgængelig:</target>
<source>Download now?</source>
<target>Download nu?</target>
-<source>Information</source>
-<target>Information</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync er opdateret!</target>
+<source>Information</source>
+<target>Information</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Skal FreeFileSync automatisk checke efter opdateringer hver uge?</target>
@@ -438,6 +432,12 @@ Kommandoen udføres hvis:
<source>Extension</source>
<target>Udvidelse</target>
+<source>Size:</source>
+<target>Størelse:</target>
+
+<source>Date:</source>
+<target>Dato:</target>
+
<source>Action</source>
<target>Handling</target>
@@ -471,6 +471,9 @@ Kommandoen udføres hvis:
<source>&New</source>
<target>&Ny</target>
+<source>&Save</source>
+<target>&Gem</target>
+
<source>&Language</source>
<target>&Sprog</target>
@@ -537,11 +540,8 @@ Kommandoen udføres hvis:
<source>Number of files and folders that will be deleted</source>
<target>Antal filer og mapper der vil blive slettet</target>
-<source>Total amount of data that will be transferred</source>
-<target>Samlet antal data der vil blive overført</target>
-
-<source>Operation:</source>
-<target>Igang:</target>
+<source>Total bytes to copy</source>
+<target>Samlet antal bytes der skal kopieres</target>
<source>Items found:</source>
<target>Enheder fundet:</target>
@@ -549,11 +549,11 @@ Kommandoen udføres hvis:
<source>Speed:</source>
<target>Hastighed:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Tid tilbage:</target>
-<source>Elapsed time:</source>
-<target>Tid gået:</target>
+<source>Time elapsed:</source>
+<target>Tid forbrugt:</target>
<source>Batch job</source>
<target>Batch job</target>
@@ -675,6 +675,15 @@ er det samme
<source>Source code written in C++ utilizing:</source>
<target>Source code skrevet i C++:</target>
+<source>If you like FreeFileSync</source>
+<target>Hvis du kan lide FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Doner med PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Stor tak for lokalisering af FreeFileSync går til:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Feedback og forslag er velkomne</target>
@@ -687,39 +696,9 @@ er det samme
<source>Email</source>
<target>E-mail</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Stor tak for lokalisering af FreeFileSync går til:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Hvis du kan lide FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Doner med PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Udgivet under GNU General Public Licence</target>
-<source>Ignore further errors</source>
-<target>Ignorer fremtidige fejl</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Skjul yderligere fejl beskeder under nuværende opgave</target>
-
-<source>&Ignore</source>
-<target>&Ignorer</target>
-
-<source>Do not show this dialog again</source>
-<target>Vis ikke denne dialog igen</target>
-
-<source>&Switch</source>
-<target>&Skift</target>
-
-<source>&Yes</source>
-<target>&Ja</target>
-
-<source>&No</source>
-<target>&Nej</target>
-
<source>Use Recycle Bin</source>
<target>Brug skraldespanden</target>
@@ -792,6 +771,9 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Statistics</source>
<target>Statestik</target>
+<source>Do not show this dialog again</source>
+<target>Vis ikke denne dialog igen</target>
+
<source>Find what:</source>
<target>Find:</target>
@@ -870,8 +852,14 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Never save changes</source>
<target>Gem aldrig ændringer</target>
-<source>Save changes to current configuration?</source>
-<target>Gem ændringer til nuværende konfiguration?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Ønsker du at gemme ændringerne til %x?</target>
+
+<source>Save</source>
+<target>Gem</target>
+
+<source>Don't Save</source>
+<target>Gem Ikke</target>
<source>Configuration loaded!</source>
<target>Konfiguration hentet!</target>
@@ -966,9 +954,6 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>All directories in sync!</source>
<target>Alle biblioteker er synkroniseret!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Kør venligst en sammenligning inden synkronisering!</target>
-
<source>Comma separated list</source>
<target>Komma separeret list</target>
@@ -1014,6 +999,24 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<pluralform>%x af %y rækker</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorer fremtidige fejl</target>
+
+<source>&Ignore</source>
+<target>&Ignorer</target>
+
+<source>&Switch</source>
+<target>&Skift</target>
+
+<source>Question</source>
+<target>Spørgsmål</target>
+
+<source>&Yes</source>
+<target>&Ja</target>
+
+<source>&No</source>
+<target>&Nej</target>
+
<source>Scanning...</source>
<target>Skanner...</target>
@@ -1194,6 +1197,9 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Cannot delete directory %x.</source>
<target>Kan ikke slette biblioteket %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Kan ikke skrive fil attributter til %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Kan ikke opdatere ændringstiden på %x.</target>
@@ -1218,9 +1224,6 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Kan ikke kopiere linket %x til %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Kan ikke skrive fil attributter til %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Kan ikke kopiere filen %x til %y.</target>
@@ -1245,11 +1248,8 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>No change since last synchronization!</source>
<target>Ingen ændringer siden sidste synkronisering!</target>
-<source>Filter settings have changed!</source>
-<target>Filter indstillinger er ændret!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>filen blev ikke behandlet ved sidste synkronisering!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Databasen er ikke synkroniseret i forhold til nuværende indstillinger.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Sætter standard synkroniseringsvej: Gamle filer bliver overskrevet med nyere.</target>
@@ -1377,14 +1377,14 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Updating attributes of %x</source>
<target>Opdaterer attributter af %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Destinations makken må ikke være tom.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Destinations mappe feltet må ikke være tomt.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Mappe navnet for fil versionering må ikke være tomt.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Mappe input feltet for versionering må ikke være tomt.</target>
-<source>Source directory %x not found.</source>
-<target>Kildebiblioteket %x blev ikke fundet.</target>
+<source>Source folder %x not found.</source>
+<target>Kilde mappen %x blev ikke fundet.</target>
<source>Unresolved conflicts existing!</source>
<target>Er er uløste konflikter!</target>
@@ -1401,11 +1401,11 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Not enough free disk space available in:</source>
<target>Ikke nok ledig diskplads på:</target>
-<source>Free disk space required:</source>
-<target>Krævet ledig diskplads:</target>
+<source>Required:</source>
+<target>Krævet:</target>
-<source>Free disk space available:</source>
-<target>Ledig diskplads tilgængelig:</target>
+<source>Available:</source>
+<target>Tilgængeligt:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Papirkurven kan ikke bruges på følgende stier! Filerne vil blive slettet permanent i stedet for:</target>
@@ -1416,6 +1416,9 @@ Note: Fil navne må skal passe til grund bibliotekerne!
<source>Processing folder pair:</source>
<target>Behandler mappe par:</target>
+<source>Target folder %x already existing.</source>
+<target>Destinations mappen %x eksisterer allerede.</target>
+
<source>Generating database...</source>
<target>Opretter database...</target>
diff --git a/BUILD/Languages/dutch.lng b/BUILD/Languages/dutch.lng
index 08f738aa..7c79112d 100644
--- a/BUILD/Languages/dutch.lng
+++ b/BUILD/Languages/dutch.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Informatie</target>
-<source>Warning</source>
-<target>Waarschuwing</target>
-
-<source>Question</source>
-<target>Vraag</target>
-
<source>Confirm</source>
<target>Bevestig</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Waarschuwing</target>
+
<source>Fatal Error</source>
<target>Fatale fout</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Kan bestand %x niet vinden.</target>
-
-<source>Cannot write file %x.</source>
-<target>Kan bestand %x niet schrijven.</target>
-
<source>Database file %x is incompatible.</source>
<target>Database bestand %x is niet compatibel.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Database bestand %x bestaat nog niet.</target>
+<source>Database file is corrupt:</source>
+<target></target>
+
<source>Out of memory!</source>
<target>Onvoldoende geheugen!</target>
+<source>Cannot write file %x.</source>
+<target>Kan bestand %x niet schrijven.</target>
+
+<source>Cannot read file %x.</source>
+<target>Kan bestand %x niet vinden.</target>
+
<source>Database files do not share a common session.</source>
<target>Database bestanden delen geen gezamelijke sessie.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/sec</target>
+<source>Cannot find file %x.</source>
+<target>Kan bestand %x niet vinden.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Bestand %x bevat geen valide configuratie.</target>
@@ -229,14 +232,11 @@
<source>Cannot read the following XML elements:</source>
<target>Kan de volgende XML elementen niet lezen:</target>
-<source>Cannot find file %x.</source>
-<target>Kan bestand %x niet vinden.</target>
-
<source>&Open...</source>
<target>&Open...</target>
-<source>&Save...</source>
-<target>&Opslaan...</target>
+<source>Save &As...</source>
+<target></target>
<source>&Quit</source>
<target>&Afsluiten</target>
@@ -327,8 +327,8 @@ De opdracht word geactiveerd als>:
<source>Waiting for missing directories...</source>
<target>Wacht op missende mappen...</target>
-<source>An input folder name is empty.</source>
-<target>Een input map naam is leeg.</target>
+<source>A folder input field is empty.</source>
+<target></target>
<source>Logging</source>
<target>Loggen</target>
@@ -351,8 +351,8 @@ De opdracht word geactiveerd als>:
<source>Custom</source>
<target>Aangepast</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync taakbestand</target>
+<source>FreeFileSync batch</source>
+<target></target>
<source>Batch execution</source>
<target>Taak uitvoeren</target>
@@ -390,8 +390,8 @@ De opdracht word geactiveerd als>:
<source>Unable to connect to sourceforge.net!</source>
<target>Niet in staat verbinding te maken met sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Een nieuwe versie van FreeFileSync is beschikbaar:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target></target>
<source>Download now?</source>
<target>Nu downloaden?</target>
@@ -435,6 +435,12 @@ De opdracht word geactiveerd als>:
<source>Extension</source>
<target>Extensie</target>
+<source>Size:</source>
+<target></target>
+
+<source>Date:</source>
+<target></target>
+
<source>Action</source>
<target>Actie</target>
@@ -468,6 +474,9 @@ De opdracht word geactiveerd als>:
<source>&New</source>
<target>&Nieuw</target>
+<source>&Save</source>
+<target></target>
+
<source>&Language</source>
<target>&Taal</target>
@@ -534,8 +543,8 @@ De opdracht word geactiveerd als>:
<source>Number of files and folders that will be deleted</source>
<target>Aantal bestanden en mappen die verwijderd zullen worden</target>
-<source>Total amount of data that will be transferred</source>
-<target>Totale hoeveelheid data die verplaatst wordt</target>
+<source>Total bytes to copy</source>
+<target></target>
<source>Items found:</source>
<target>Onderdelen gevonden:</target>
@@ -543,11 +552,11 @@ De opdracht word geactiveerd als>:
<source>Speed:</source>
<target>Snelheid:</target>
-<source>Remaining time:</source>
-<target>Benodigde tijd:</target>
+<source>Time remaining:</source>
+<target></target>
-<source>Elapsed time:</source>
-<target>Verstreken tijd:</target>
+<source>Time elapsed:</source>
+<target></target>
<source>Batch job</source>
<target>Taaklijst</target>
@@ -669,6 +678,15 @@ overeenkomt
<source>Source code written in C++ utilizing:</source>
<target>Broncode geschreven in C++ met behulp van:</target>
+<source>If you like FreeFileSync</source>
+<target>Indien FreeFileSync u bevalt</target>
+
+<source>Donate with PayPal</source>
+<target>Doneer met PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Extra dank voor het vertalen van FreeFileSync gaat naar:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Feedback en suggesties zijn welkom</target>
@@ -681,39 +699,9 @@ overeenkomt
<source>Email</source>
<target>E-mail</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Extra dank voor het vertalen van FreeFileSync gaat naar:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Indien FreeFileSync u bevalt</target>
-
-<source>Donate with PayPal</source>
-<target>Doneer met PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Gepubliceerd onder de GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Negeer verdere foutmeldingen</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Verberg eventuele foutmeldingen gedurende de huidige bewerking</target>
-
-<source>&Ignore</source>
-<target>&Negeren</target>
-
-<source>Do not show this dialog again</source>
-<target>Toon deze melding niet meer</target>
-
-<source>&Switch</source>
-<target>&Omschakelen</target>
-
-<source>&Yes</source>
-<target>&Ja</target>
-
-<source>&No</source>
-<target>&Nee</target>
-
<source>Use Recycle Bin</source>
<target>Gebruik de prullenbak</target>
@@ -786,6 +774,9 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Statistics</source>
<target>Statistieken</target>
+<source>Do not show this dialog again</source>
+<target>Toon deze melding niet meer</target>
+
<source>Find what:</source>
<target>Vind wat:</target>
@@ -864,8 +855,14 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Never save changes</source>
<target>Veranderingen nooit opslaan</target>
-<source>Save changes to current configuration?</source>
-<target>Veranderingen opslaan in de huidige configuratie?</target>
+<source>Do you want to save changes to %x?</source>
+<target></target>
+
+<source>Save</source>
+<target></target>
+
+<source>Don't Save</source>
+<target></target>
<source>Configuration loaded!</source>
<target>Configuratie geladen!</target>
@@ -960,9 +957,6 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>All directories in sync!</source>
<target>Alle mappen zijn gesynchroniseerd!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Voer alstublieft eerst een Vergelijking uit voordat u synchroniseert.</target>
-
<source>Comma separated list</source>
<target>Komma gescheiden lijst</target>
@@ -1008,6 +1002,24 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<pluralform>%x van %y rijen in het overzicht</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Negeer verdere foutmeldingen</target>
+
+<source>&Ignore</source>
+<target>&Negeren</target>
+
+<source>&Switch</source>
+<target>&Omschakelen</target>
+
+<source>Question</source>
+<target>Vraag</target>
+
+<source>&Yes</source>
+<target>&Ja</target>
+
+<source>&No</source>
+<target>&Nee</target>
+
<source>Scanning...</source>
<target>Doorzoekt...</target>
@@ -1188,12 +1200,12 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Cannot delete directory %x.</source>
<target>Kan bestand %x niet verwijderen.</target>
-<source>Cannot write modification time of %x.</source>
-<target>Kan wijzigings tijd van %x niet toevoegen.</target>
-
<source>Cannot write file attributes of %x.</source>
<target>Kan bestandskenmerken van %x niet schrijven.</target>
+<source>Cannot write modification time of %x.</source>
+<target>Kan wijzigings tijd van %x niet toevoegen.</target>
+
<source>Cannot find system function %x.</source>
<target>Kan systeemfunctie %x niet vinden.</target>
@@ -1239,11 +1251,8 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>No change since last synchronization!</source>
<target>Geen veranderingen sinds de laatste synchronisatie!</target>
-<source>Filter settings have changed!</source>
-<target>Filter instellingen zijn veranderd!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Het bestand werd niet verwerkt tijdens de laatste synchronisatie!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target></target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Stel standaard synchronisatie richtingen in: Oude bestanden worden door nieuwere bestanden overschreven.</target>
@@ -1371,14 +1380,14 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Updating attributes of %x</source>
<target>Attributen bijwerken van %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Doelmap mag geen lege naam hebben.</target>
+<source>Target folder input field must not be empty.</source>
+<target></target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Mapnaam voor bestandsversies mag niet leeg zijn.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target></target>
-<source>Source directory %x not found.</source>
-<target>Bronmap %x niet gevonden.</target>
+<source>Source folder %x not found.</source>
+<target></target>
<source>Unresolved conflicts existing!</source>
<target>Er bestaan onopgeloste conflicten!</target>
@@ -1395,11 +1404,11 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Not enough free disk space available in:</source>
<target>Niet genoeg vrije schijfruimte beschikbaar op:</target>
-<source>Free disk space required:</source>
-<target>Vrije ruimte op harde schrijf nodig:</target>
+<source>Required:</source>
+<target></target>
-<source>Free disk space available:</source>
-<target>Beschikbare vrije schijfruimte :</target>
+<source>Available:</source>
+<target></target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Prullenbak is niet beschikbaar voor de volgende locaties! De bestanden worden permanent verwijderd:</target>
@@ -1410,6 +1419,9 @@ Opmerking: Bestandsnamen moeten relatief zijn aan de basis mappen!
<source>Processing folder pair:</source>
<target>Verwerking van gekoppelde mappen:</target>
+<source>Target folder %x already existing.</source>
+<target></target>
+
<source>Generating database...</source>
<target>Genereren van database...</target>
diff --git a/BUILD/Languages/english_uk.lng b/BUILD/Languages/english_uk.lng
index 751cf0be..bd0cd650 100644
--- a/BUILD/Languages/english_uk.lng
+++ b/BUILD/Languages/english_uk.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>About</target>
-<source>Warning</source>
-<target>Warning</target>
-
-<source>Question</source>
-<target>Question</target>
-
<source>Confirm</source>
<target>Confirm</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Warning</target>
+
<source>Fatal Error</source>
<target>Fatal Error</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Cannot read file %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Cannot write file %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Database file %x is incompatible.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Database file %x does not yet exist.</target>
+<source>Database file is corrupt:</source>
+<target>Database file is corrupt:</target>
+
<source>Out of memory!</source>
<target>Out of memory!</target>
+<source>Cannot write file %x.</source>
+<target>Cannot write file %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Cannot read file %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Database files do not share a common session.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/sec</target>
+<source>Cannot find file %x.</source>
+<target>Cannot find file %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>File %x does not contain a valid configuration.</target>
@@ -226,17 +229,14 @@
<source>Volume name %x not part of file name %y!</source>
<target>Volume name %x not part of file name %y!</target>
-<source>Cannot find file %x.</source>
-<target>Cannot find file %x.</target>
-
<source>Cannot read the following XML elements:</source>
<target>Cannot read the following XML elements:</target>
<source>&Open...</source>
<target>&Open...</target>
-<source>&Save...</source>
-<target>&Save...</target>
+<source>Save &As...</source>
+<target>Save &As...</target>
<source>&Quit</source>
<target>&Quit</target>
@@ -312,8 +312,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(Build: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync configuration</target>
+<source>All files</source>
+<target>All files</target>
<source>&Restore</source>
<target>&Restore</target>
@@ -327,8 +327,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>Waiting for missing directories...</target>
-<source>An input folder name is empty.</source>
-<target>An input folder name is empty.</target>
+<source>A folder input field is empty.</source>
+<target>A folder input field is empty.</target>
<source>Logging</source>
<target>Logging</target>
@@ -351,11 +351,8 @@ The command is triggered if:
<source>Custom</source>
<target>Custom</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync batch file</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync configuration</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync batch</target>
<source>Batch execution</source>
<target>Batch execution</target>
@@ -393,18 +390,18 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Unable to connect to sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>A newer version of FreeFileSync is available:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>A new version of FreeFileSync is available:</target>
<source>Download now?</source>
<target>Download now?</target>
-<source>Information</source>
-<target>Information</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync is up to date!</target>
+<source>Information</source>
+<target>Information</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Do you want FreeFileSync to automatically check for updates every week?</target>
@@ -438,6 +435,12 @@ The command is triggered if:
<source>Extension</source>
<target>Extension</target>
+<source>Size:</source>
+<target>Size:</target>
+
+<source>Date:</source>
+<target>Date:</target>
+
<source>Action</source>
<target>Action</target>
@@ -471,6 +474,9 @@ The command is triggered if:
<source>&New</source>
<target>&New</target>
+<source>&Save</source>
+<target>&Save</target>
+
<source>&Language</source>
<target>&Language</target>
@@ -537,11 +543,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>Number of files and folders that will be deleted</target>
-<source>Total amount of data that will be transferred</source>
-<target>Total amount of data that will be transferred</target>
-
-<source>Operation:</source>
-<target>Operation:</target>
+<source>Total bytes to copy</source>
+<target>Total bytes to copy</target>
<source>Items found:</source>
<target>Elements found:</target>
@@ -549,11 +552,11 @@ The command is triggered if:
<source>Speed:</source>
<target>Speed:</target>
-<source>Remaining time:</source>
-<target>Remaining time:</target>
+<source>Time remaining:</source>
+<target>Time remaining:</target>
-<source>Elapsed time:</source>
-<target>Elapsed time:</target>
+<source>Time elapsed:</source>
+<target>Time elapsed:</target>
<source>Batch job</source>
<target>Batch job</target>
@@ -675,6 +678,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>Source code written in C++ utilising:</target>
+<source>If you like FreeFileSync</source>
+<target>If you like FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Donate with PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Big thanks for localising FreeFileSync goes out to:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Feedback and suggestions are welcome</target>
@@ -687,39 +699,9 @@ is the same
<source>Email</source>
<target>E-mail</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Big thanks for localising FreeFileSync goes out to:</target>
-
-<source>If you like FreeFileSync</source>
-<target>If you like FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Donate with PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Published under the GNU General Public Licence</target>
-<source>Ignore further errors</source>
-<target>Ignore further errors</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Hide further error messages during the current process</target>
-
-<source>&Ignore</source>
-<target>&Ignore</target>
-
-<source>Do not show this dialog again</source>
-<target>Do not show this dialogue again</target>
-
-<source>&Switch</source>
-<target>&Switch</target>
-
-<source>&Yes</source>
-<target>&Yes</target>
-
-<source>&No</source>
-<target>&No</target>
-
<source>Use Recycle Bin</source>
<target>Use Recycle Bin</target>
@@ -792,6 +774,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>Statistics</target>
+<source>Do not show this dialog again</source>
+<target>Do not show this dialogue again</target>
+
<source>Find what:</source>
<target>Find what:</target>
@@ -870,8 +855,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>Never save changes</target>
-<source>Save changes to current configuration?</source>
-<target>Save changes to current configuration?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Do you want to save changes to %x?</target>
+
+<source>Save</source>
+<target>Save</target>
+
+<source>Don't Save</source>
+<target>Don't Save</target>
<source>Configuration loaded!</source>
<target>Configuration loaded!</target>
@@ -966,9 +957,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>All directories in sync!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Please run a Compare first before synchronising!</target>
-
<source>Comma separated list</source>
<target>Comma separated list</target>
@@ -1014,6 +1002,24 @@ Note: File names must be relative to base directories!
<pluralform>%x of %y rows in view</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignore further errors</target>
+
+<source>&Ignore</source>
+<target>&Ignore</target>
+
+<source>&Switch</source>
+<target>&Switch</target>
+
+<source>Question</source>
+<target>Question</target>
+
+<source>&Yes</source>
+<target>&Yes</target>
+
+<source>&No</source>
+<target>&No</target>
+
<source>Scanning...</source>
<target>Scanning...</target>
@@ -1194,6 +1200,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>Cannot delete directory %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Cannot write file attributes of %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Cannot write modification time of %x.</target>
@@ -1218,9 +1227,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Cannot copy symbolic link %x to %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Cannot write file attributes of %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Cannot copy file %x to %y.</target>
@@ -1245,11 +1251,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>No change since last synchronisation!</target>
-<source>Filter settings have changed!</source>
-<target>Filter settings have changed!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>The file was not processed by last synchronisation!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>The corresponding database entries are not in sync considering current settings.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Setting default synchronisation directions: Old files will be overwritten with newer files.</target>
@@ -1377,14 +1380,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>Updating attributes of %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Target folder name must not be empty.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Target folder input field must not be empty.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Folder name for file versioning must not be empty.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Folder input field for versioning must not be empty.</target>
-<source>Source directory %x not found.</source>
-<target>Source directory %x not found.</target>
+<source>Source folder %x not found.</source>
+<target>Source folder %x not found.</target>
<source>Unresolved conflicts existing!</source>
<target>Unresolved conflicts existing!</target>
@@ -1401,11 +1404,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>Not enough free disk space available in:</target>
-<source>Free disk space required:</source>
-<target>Free disk space required:</target>
+<source>Required:</source>
+<target>Required:</target>
-<source>Free disk space available:</source>
-<target>Free disk space available:</target>
+<source>Available:</source>
+<target>Available:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</target>
@@ -1416,6 +1419,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>Processing folder pair:</target>
+<source>Target folder %x already existing.</source>
+<target>Target folder %x already existing.</target>
+
<source>Generating database...</source>
<target>Generating database...</target>
diff --git a/BUILD/Languages/finnish.lng b/BUILD/Languages/finnish.lng
index 8ccf5448..f67326e5 100644
--- a/BUILD/Languages/finnish.lng
+++ b/BUILD/Languages/finnish.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Ohje</target>
-<source>Warning</source>
-<target>Varoitus</target>
-
-<source>Question</source>
-<target>Kysymys</target>
-
<source>Confirm</source>
<target>Vahvista</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Varoitus</target>
+
<source>Fatal Error</source>
<target>Kohtalokas virhe</target>
@@ -139,12 +136,6 @@
<pluralform>%x tavua</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Lukeminen ei onnistu %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Kirjoittaminen ei onnistu %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Tietokanta %x vierasta muotoa.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Tietokanta %x on vielä luomatta.</target>
+<source>Database file is corrupt:</source>
+<target>Tietokanta viottunut:</target>
+
<source>Out of memory!</source>
<target>Muisti loppui!</target>
+<source>Cannot write file %x.</source>
+<target>Kirjoittaminen ei onnistu %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Lukeminen ei onnistu %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Tietokannan tiedostot eri sessioista.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/s</target>
+<source>Cannot find file %x.</source>
+<target>Tiedosto %x ei löydy.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Tiedosto %x ei sisällä kelvollista kokoonpanoa.</target>
@@ -229,14 +232,11 @@
<source>Cannot read the following XML elements:</source>
<target>XML elementit lukukelvottimia:</target>
-<source>Cannot find file %x.</source>
-<target>Tiedosto %x ei löydy.</target>
-
<source>&Open...</source>
<target>&Avaa...</target>
-<source>&Save...</source>
-<target>&Avaa...</target>
+<source>Save &As...</source>
+<target>Tallenna n&imellä...</target>
<source>&Quit</source>
<target>&Lopeta</target>
@@ -312,8 +312,8 @@ Käsky suoritetaan jos:
<source>(Build: %x)</source>
<target>(Versio: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync Asetukset</target>
+<source>All files</source>
+<target>Kaikki tiedostot</target>
<source>&Restore</source>
<target>&Palauta</target>
@@ -327,8 +327,8 @@ Käsky suoritetaan jos:
<source>Waiting for missing directories...</source>
<target>Odottaa puuttuvia hakemistoja...</target>
-<source>An input folder name is empty.</source>
-<target>Tulohakemiston nimi on tyhjä.</target>
+<source>A folder input field is empty.</source>
+<target>Hakemiston syöte on tyhjä.</target>
<source>Logging</source>
<target>Kirjaa</target>
@@ -351,11 +351,8 @@ Käsky suoritetaan jos:
<source>Custom</source>
<target>Oma määritelmä</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync eräajotiedosto</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync asetukset</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync eräajo</target>
<source>Batch execution</source>
<target>Eräajon suoritus</target>
@@ -369,9 +366,6 @@ Käsky suoritetaan jos:
<source>Total time:</source>
<target>Kokonaisaika:</target>
-<source>Stop</source>
-<target>Seis</target>
-
<source>Synchronization aborted!</source>
<target>Täsmäytys lopetettiin!</target>
@@ -393,18 +387,18 @@ Käsky suoritetaan jos:
<source>Unable to connect to sourceforge.net!</source>
<target>Yhteys sourceforge.net:n ei onnistu!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>FreeFileSync:n uusi versio on saatavilla:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>FreeFileSync:n uusi verio on saatavilla:</target>
<source>Download now?</source>
<target>Lataa nyt?</target>
-<source>Information</source>
-<target>Tietoja</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync on ajan tasalla!</target>
+<source>Information</source>
+<target>Tietoja</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Haluatko että FreeFileSync hakee päivityksiä automaattisesti viikoittain?</target>
@@ -438,6 +432,12 @@ Käsky suoritetaan jos:
<source>Extension</source>
<target>Laajennus</target>
+<source>Size:</source>
+<target>Koko:</target>
+
+<source>Date:</source>
+<target>Pvm:</target>
+
<source>Action</source>
<target>Suorita</target>
@@ -471,6 +471,9 @@ Käsky suoritetaan jos:
<source>&New</source>
<target>&Uusi</target>
+<source>&Save</source>
+<target>Tallenna</target>
+
<source>&Language</source>
<target>&Kieli</target>
@@ -537,11 +540,8 @@ Käsky suoritetaan jos:
<source>Number of files and folders that will be deleted</source>
<target>Poistettavien tiedostojen ja hakemistojen määrä</target>
-<source>Total amount of data that will be transferred</source>
-<target>Siirrettävän datan määrä</target>
-
-<source>Operation:</source>
-<target>Toiminto:</target>
+<source>Total bytes to copy</source>
+<target>Kopioitava määrä tavuja</target>
<source>Items found:</source>
<target>Osia löytyi:</target>
@@ -549,11 +549,11 @@ Käsky suoritetaan jos:
<source>Speed:</source>
<target>Nopeus:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Aikaa jäljellä:</target>
-<source>Elapsed time:</source>
-<target>Kulunut aika:</target>
+<source>Time elapsed:</source>
+<target>Aikaa kulunut:</target>
<source>Batch job</source>
<target>Eräajo</target>
@@ -675,6 +675,15 @@ on sama
<source>Source code written in C++ utilizing:</source>
<target>Koodikieli on C++ käyttäen:</target>
+<source>If you like FreeFileSync</source>
+<target>Jos pidät FreeFileSync:tä</target>
+
+<source>Donate with PayPal</source>
+<target>Lahjoita PayPal:lla</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Suuret kiitokset FreeFileSync:n paikallistamisesta:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Palaute ja uudet ideat ovat tervetulleita</target>
@@ -687,39 +696,9 @@ on sama
<source>Email</source>
<target>S-posti</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Suuret kiitokset FreeFileSync:n paikallistamisesta:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Jos pidät FreeFileSync:tä</target>
-
-<source>Donate with PayPal</source>
-<target>Lahjoita PayPal:lla</target>
-
<source>Published under the GNU General Public License</source>
<target>Julkaistu lisenssillä GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Hylkää toistuvat virheviestit</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Piilota toistuvat virheet tässä suorituksessa</target>
-
-<source>&Ignore</source>
-<target>&Unohda</target>
-
-<source>Do not show this dialog again</source>
-<target>Älä enää näytä valintaikkunaa</target>
-
-<source>&Switch</source>
-<target>&Vaihda</target>
-
-<source>&Yes</source>
-<target>&Kyllä</target>
-
-<source>&No</source>
-<target>&Ei</target>
-
<source>Use Recycle Bin</source>
<target>Käytä Roskakoria</target>
@@ -792,6 +771,9 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Statistics</source>
<target>Tilastot</target>
+<source>Do not show this dialog again</source>
+<target>Älä enää näytä valintaikkunaa</target>
+
<source>Find what:</source>
<target>Etsi:</target>
@@ -870,8 +852,14 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Never save changes</source>
<target>Älä tallenna muutoksia</target>
-<source>Save changes to current configuration?</source>
-<target>Tallenna asetuksiin tehdyt muutokset?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Haluatko tallentaa muutokset: %x?</target>
+
+<source>Save</source>
+<target>Tallenna</target>
+
+<source>Don't Save</source>
+<target>Älä tallenna</target>
<source>Configuration loaded!</source>
<target>Asetukset ladattu!</target>
@@ -966,9 +954,6 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>All directories in sync!</source>
<target>Kaikki hakemistot täsmäävät!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Suorita Vertaile ennen täsmäystä.</target>
-
<source>Comma separated list</source>
<target>CSV-muotoinen lista</target>
@@ -1014,6 +999,24 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<pluralform>%x / %y:tä rivistä näytössä</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Hylkää toistuvat virheviestit</target>
+
+<source>&Ignore</source>
+<target>&Unohda</target>
+
+<source>&Switch</source>
+<target>&Vaihda</target>
+
+<source>Question</source>
+<target>Kysymys</target>
+
+<source>&Yes</source>
+<target>&Kyllä</target>
+
+<source>&No</source>
+<target>&Ei</target>
+
<source>Scanning...</source>
<target>Tiedostoja haetaan...</target>
@@ -1194,6 +1197,9 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Cannot delete directory %x.</source>
<target>Hakemistoa %x ei voida poistaa.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Tiedoston %x ominaisuuksia ei voitu tallentaa.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Tiedoston %x muutosaikaa ei voida kirjoittaa.</target>
@@ -1218,9 +1224,6 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Pikakuviketta %x ei voida kopioida kohtaan %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Tiedoston %x ominaisuuksia ei voitu tallentaa.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Tiedostoa %x ei voida kopioida kohtaan %y.</target>
@@ -1245,11 +1248,8 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>No change since last synchronization!</source>
<target>Ei muutoksia edellisen täsmäyksen jälkeen!</target>
-<source>Filter settings have changed!</source>
-<target>Suodinasetukset muutettu!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Tiedostoa ei käsitelty viime täsmäyksessä!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Käytetyn tietokannan tiedot eivät täsmää nykyisiin asetuksiin.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Aseta oletussuunta täsmäykselle: Vanhat tiedostot korvataan uudemilla tiedostoilla.</target>
@@ -1377,13 +1377,13 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Updating attributes of %x</source>
<target>Päivitän %x:n ominaisuudet</target>
-<source>Target folder name must not be empty.</source>
-<target>Kohdehakemistolla on oltava nimi.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Kohde hakemiston kenttä on annettava.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Versioinnin kohdehakemistolla on oltava nimi.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Kohde hakemiston version syötettävä.</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>Lähdehakemisto %x ei löydy.</target>
<source>Unresolved conflicts existing!</source>
@@ -1401,11 +1401,11 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Not enough free disk space available in:</source>
<target>Vapaa levytila ei riitä:</target>
-<source>Free disk space required:</source>
-<target>Tarvittava vapaa levytila:</target>
+<source>Required:</source>
+<target>Vaadittu:</target>
-<source>Free disk space available:</source>
-<target>Levytilaa jäljellä:</target>
+<source>Available:</source>
+<target>Saatavilla:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Roskakori puuttuu näistä polusta! Tiedostot poistetaan pysyvästi:</target>
@@ -1416,6 +1416,9 @@ Huom: Tiedostojen nimet täytyy olla suhteessa pää hakemistoihin!
<source>Processing folder pair:</source>
<target>Käsitellään hakemistoparia:</target>
+<source>Target folder %x already existing.</source>
+<target>Kohdehakemisto %x on olemassa.</target>
+
<source>Generating database...</source>
<target>
Tietokanta luodaan.
diff --git a/BUILD/Languages/french.lng b/BUILD/Languages/french.lng
index 65759025..6db32565 100644
--- a/BUILD/Languages/french.lng
+++ b/BUILD/Languages/french.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>A propos de</target>
-<source>Warning</source>
-<target>Attention</target>
-
-<source>Question</source>
-<target>Question</target>
-
<source>Confirm</source>
<target>Confirmation</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Attention</target>
+
<source>Fatal Error</source>
<target>Erreur Fatale</target>
@@ -139,12 +136,6 @@
<pluralform>%x octets</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Impossible de lire le fichier %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Impossible d'écrire le fichier %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>La base de données %x n'est pas compatible.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>La base de données %x n'existe plus.</target>
+<source>Database file is corrupt:</source>
+<target>Le fichier Base de données est endommagé :</target>
+
<source>Out of memory!</source>
<target>Mémoire insuffisante !</target>
+<source>Cannot write file %x.</source>
+<target>Impossible d'écrire le fichier %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Impossible de lire le fichier %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Les fichiers de la base de données ne font pas partie de la même session.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/sec</target>
+<source>Cannot find file %x.</source>
+<target>Impossible de trouver le fichier %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Le fichier %x ne contient pas une configuration valide.</target>
@@ -229,26 +232,23 @@
<source>Cannot read the following XML elements:</source>
<target>Impossible de lire les données XML suivantes :</target>
-<source>Cannot find file %x.</source>
-<target>Impossible de trouver le fichier %x.</target>
-
<source>&Open...</source>
<target>&Ouvrir...</target>
-<source>&Save...</source>
-<target>&Sauvegarder...</target>
+<source>Save &As...</source>
+<target>&Enregistrer sous ...</target>
<source>&Quit</source>
<target>&Quitter</target>
<source>&Program</source>
-<target>&Actions</target>
+<target>&Tâche</target>
<source>&Content</source>
<target>&Contenu</target>
<source>&About</source>
-<target>&A propos de</target>
+<target>A &Propos de</target>
<source>&Help</source>
<target>&Aide</target>
@@ -312,8 +312,8 @@ La commande est déclenchée si :
<source>(Build: %x)</source>
<target>(Généré : %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Configuration RealtimeSync</target>
+<source>All files</source>
+<target>Tous les fichiers</target>
<source>&Restore</source>
<target>&Restaurer</target>
@@ -327,8 +327,8 @@ La commande est déclenchée si :
<source>Waiting for missing directories...</source>
<target>En attente des répertoires absents ...</target>
-<source>An input folder name is empty.</source>
-<target>Le nom d'un dossier entré est vide.</target>
+<source>A folder input field is empty.</source>
+<target>Une entrée dossier est vide.</target>
<source>Logging</source>
<target>Connexion</target>
@@ -351,11 +351,8 @@ La commande est déclenchée si :
<source>Custom</source>
<target>Personnaliser</target>
-<source>FreeFileSync batch file</source>
-<target>fichier batch FreeFileSync</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync configuration</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync batch</target>
<source>Batch execution</source>
<target>Exécution du traitement batch</target>
@@ -393,18 +390,18 @@ La commande est déclenchée si :
<source>Unable to connect to sourceforge.net!</source>
<target>Impossible de se connecter à sourceforge.net !</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Une version plus récente de FreeFileSync est disponible :</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Une nouvelle version de FreeFileSync est disponible</target>
<source>Download now?</source>
<target>Télécharger maintenant ?</target>
-<source>Information</source>
-<target>Information</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync est à jour !</target>
+<source>Information</source>
+<target>Information</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Voulez-vous que FreeFileSync recherche automatiquement une nouvelle version chaque semaine ?</target>
@@ -438,6 +435,12 @@ La commande est déclenchée si :
<source>Extension</source>
<target>Extension</target>
+<source>Size:</source>
+<target>Taille :</target>
+
+<source>Date:</source>
+<target>Date :</target>
+
<source>Action</source>
<target>Action</target>
@@ -471,6 +474,9 @@ La commande est déclenchée si :
<source>&New</source>
<target>&Nouveau</target>
+<source>&Save</source>
+<target>&Sauvegarder</target>
+
<source>&Language</source>
<target>&Langue</target>
@@ -537,11 +543,8 @@ La commande est déclenchée si :
<source>Number of files and folders that will be deleted</source>
<target>Nombre de fichiers et de dossiers qui seront supprimés</target>
-<source>Total amount of data that will be transferred</source>
-<target>Volume de données à transférer</target>
-
-<source>Operation:</source>
-<target>Opération :</target>
+<source>Total bytes to copy</source>
+<target>Nombre total d'octets à copier</target>
<source>Items found:</source>
<target>Elements trouvés :</target>
@@ -549,10 +552,10 @@ La commande est déclenchée si :
<source>Speed:</source>
<target>Vitesse :</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Temps restant :</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Temps écoulé :</target>
<source>Batch job</source>
@@ -675,6 +678,15 @@ est identique
<source>Source code written in C++ utilizing:</source>
<target>Code source écrit en C++ utilisant :</target>
+<source>If you like FreeFileSync</source>
+<target>Si vous aimez FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Faites un don avec PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Pour les traductions de FreeFileSync, un grand merci à :</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Vos commentaires et vos suggestions sont les bienvenus</target>
@@ -687,39 +699,9 @@ est identique
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Pour les traductions de FreeFileSync, un grand merci à :</target>
-
-<source>If you like FreeFileSync</source>
-<target>Si vous aimez FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Faites un don avec PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Publié sous licence GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Ignorer les erreurs suivantes</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Masquer les messages d'erreur suivants pendant le traitement</target>
-
-<source>&Ignore</source>
-<target>&Ignorer</target>
-
-<source>Do not show this dialog again</source>
-<target>Ne plus afficher ce message la prochaine fois</target>
-
-<source>&Switch</source>
-<target>&Changer</target>
-
-<source>&Yes</source>
-<target>&Oui</target>
-
-<source>&No</source>
-<target>&Non</target>
-
<source>Use Recycle Bin</source>
<target>Utiliser la Corbeille</target>
@@ -792,6 +774,9 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Statistics</source>
<target>Statistiques</target>
+<source>Do not show this dialog again</source>
+<target>Ne plus afficher ce message la prochaine fois</target>
+
<source>Find what:</source>
<target>Chercher cela :</target>
@@ -870,8 +855,14 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Never save changes</source>
<target>Ne jamais enregistrer les modifications</target>
-<source>Save changes to current configuration?</source>
-<target>Voulez-vous enregistrer les modifications dans la configuration actuelle ?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Voulez-vous enregistrer les midifications dans %x ?</target>
+
+<source>Save</source>
+<target>Sauvegarder</target>
+
+<source>Don't Save</source>
+<target>Ne pas sauvegarder</target>
<source>Configuration loaded!</source>
<target>Configuration chargée !</target>
@@ -966,9 +957,6 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>All directories in sync!</source>
<target>Tous les répertoires sont synchronisés !</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Veuillez lancer une Comparaison avant de lancer la synchronisation !</target>
-
<source>Comma separated list</source>
<target>Liste d'éléments séparés par une virgule</target>
@@ -1014,6 +1002,24 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<pluralform>%x of %y lignes affichées</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorer les erreurs suivantes</target>
+
+<source>&Ignore</source>
+<target>&Ignorer</target>
+
+<source>&Switch</source>
+<target>&Changer</target>
+
+<source>Question</source>
+<target>Question</target>
+
+<source>&Yes</source>
+<target>&Oui</target>
+
+<source>&No</source>
+<target>&Non</target>
+
<source>Scanning...</source>
<target>Lecture en cours...</target>
@@ -1129,7 +1135,7 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<target>Utiliser la Corbeille lors de la suppression ou du remplacement d'un fichier</target>
<source>Versioning</source>
-<target>Choisir un dossier</target>
+<target>Gestion des versions</target>
<source>Move files into a time-stamped subfolder</source>
<target>Déplacer les fichiers dans un sous-dossier horodaté</target>
@@ -1194,6 +1200,9 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Cannot delete directory %x.</source>
<target>Impossible de supprimer le répertoire %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Impossible d'écrire les attributs de fichier de %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Impossible d'écrire la date de modification de %x.</target>
@@ -1218,9 +1227,6 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Cannot copy symbolic link %x to %y.</source>
<target>Impossible de copier le lien symbolique %x vers %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Impossible d'écrire les attributs de fichier de %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Impossible de copier le fichier %X vers %y.</target>
@@ -1245,11 +1251,8 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>No change since last synchronization!</source>
<target>Aucun changement depuis la dernière synchronisation !</target>
-<source>Filter settings have changed!</source>
-<target>La configuration du filtre a changé !</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Le fichier n'a pas été traité par la dernière synchronisation !</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Les entrées de la Base de données ne sont pas synchronisées vu les paramètres actuels.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Directions de la synchronisation par défaut : les anciens fichiers seront remplacés par les nouveaux.</target>
@@ -1377,14 +1380,14 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Updating attributes of %x</source>
<target>Mise à jour des attributs de %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Le nom du dossier Destination ne doit pas etre vide.</target>
+<source>Target folder input field must not be empty.</source>
+<target>L'entrée dossier de destination ne doit pas être vide.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Le nom du dossier Version ne doit pas être vide.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>L'entrée dossier de gestion des versions ne doit pas être vide.</target>
-<source>Source directory %x not found.</source>
-<target>Impossible de trouver le répertoire source %x.</target>
+<source>Source folder %x not found.</source>
+<target>Dossier source %x non trouvé.</target>
<source>Unresolved conflicts existing!</source>
<target>Il y a des conflits non résolus !</target>
@@ -1401,11 +1404,11 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Not enough free disk space available in:</source>
<target>Espace disque insuffisant sur :</target>
-<source>Free disk space required:</source>
-<target>Espace disque nécessaire :</target>
+<source>Required:</source>
+<target>Requis :</target>
-<source>Free disk space available:</source>
-<target>Espace disque disponible :</target>
+<source>Available:</source>
+<target>Disponible :</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>La corbeille n'est pas valable pour les chemins suivants ! Les fichiers seront détruits définitivement :</target>
@@ -1416,6 +1419,9 @@ Attention : les noms de fichiers doivent être relatifs aux répertoires de base
<source>Processing folder pair:</source>
<target>Traitement de la paire de dossiers :</target>
+<source>Target folder %x already existing.</source>
+<target>Le dossier destination %x existe déjà.</target>
+
<source>Generating database...</source>
<target>Génération de la base de données...</target>
diff --git a/BUILD/Languages/german.lng b/BUILD/Languages/german.lng
index 78f2c847..9e8c9a8d 100644
--- a/BUILD/Languages/german.lng
+++ b/BUILD/Languages/german.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Über</target>
-<source>Warning</source>
-<target>Warnung</target>
-
-<source>Question</source>
-<target>Frage</target>
-
<source>Confirm</source>
<target>Bestätigen</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Warnung</target>
+
<source>Fatal Error</source>
<target>Schwerer Fehler</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Die Datei %x kann nicht gelesen werden.</target>
-
-<source>Cannot write file %x.</source>
-<target>Die Datei %x kann nicht geschrieben werden.</target>
-
<source>Database file %x is incompatible.</source>
<target>Die Datenbankdatei %x ist nicht kompatibel.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Die Datenbankdatei %x existiert noch nicht.</target>
+<source>Database file is corrupt:</source>
+<target>Die Datenbankdatei ist beschädigt:</target>
+
<source>Out of memory!</source>
<target>Nicht genügend Arbeitsspeicher!</target>
+<source>Cannot write file %x.</source>
+<target>Die Datei %x kann nicht geschrieben werden.</target>
+
+<source>Cannot read file %x.</source>
+<target>Die Datei %x kann nicht gelesen werden.</target>
+
<source>Database files do not share a common session.</source>
<target>Die Datenbankdateien teilen keine gemeinsame Sitzung.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/s</target>
+<source>Cannot find file %x.</source>
+<target>Die Datei %x wurde nicht gefunden.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Die Datei %x enthält keine gültige Konfiguration.</target>
@@ -229,14 +232,11 @@
<source>Cannot read the following XML elements:</source>
<target>Die folgenden XML-Elemente können nicht gelesen werden:</target>
-<source>Cannot find file %x.</source>
-<target>Die Datei %x wurde nicht gefunden.</target>
-
<source>&Open...</source>
<target>Ö&ffnen...</target>
-<source>&Save...</source>
-<target>&Speichern...</target>
+<source>Save &As...</source>
+<target>Speichern &unter...</target>
<source>&Quit</source>
<target>&Beenden</target>
@@ -327,8 +327,8 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Waiting for missing directories...</source>
<target>Warte auf fehlende Verzeichnisse...</target>
-<source>An input folder name is empty.</source>
-<target>Der Name eines Eingabeordners ist leer.</target>
+<source>A folder input field is empty.</source>
+<target>Ein Ordnereingabefeld ist leer.</target>
<source>Logging</source>
<target>Protokoll</target>
@@ -351,8 +351,8 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Custom</source>
<target>Eigene</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync Batchdatei</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync Batch</target>
<source>Batch execution</source>
<target>Batchlauf</target>
@@ -376,7 +376,7 @@ Die Befehlszeile wird ausgelöst wenn:
<target>Synchronisation mit Fehlern abgeschlossen!</target>
<source>Nothing to synchronize!</source>
-<target>Nichts zu synchronisieren!</target>
+<target>Es gibt nichts zu synchronisieren!</target>
<source>Synchronization completed successfully!</source>
<target>Synchronisation erfolgreich abgeschlossen!</target>
@@ -390,8 +390,8 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Unable to connect to sourceforge.net!</source>
<target>Es konnte keine Verbindung zu Sourceforge.net aufgebaut werden!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Eine neuere Version von FreeFileSync ist verfügbar:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Eine neue Version von FreeFileSync ist verfügbar:</target>
<source>Download now?</source>
<target>Jetzt herunterladen?</target>
@@ -435,6 +435,12 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Extension</source>
<target>Dateiendung</target>
+<source>Size:</source>
+<target>Größe:</target>
+
+<source>Date:</source>
+<target>Datum:</target>
+
<source>Action</source>
<target>Aktion</target>
@@ -468,6 +474,9 @@ Die Befehlszeile wird ausgelöst wenn:
<source>&New</source>
<target>&Neu</target>
+<source>&Save</source>
+<target>&Speichern</target>
+
<source>&Language</source>
<target>&Sprache</target>
@@ -534,8 +543,8 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Number of files and folders that will be deleted</source>
<target>Anzahl der zu löschenden Dateien und Ordner</target>
-<source>Total amount of data that will be transferred</source>
-<target>Gesamtmenge der zu übertragenden Daten</target>
+<source>Total bytes to copy</source>
+<target>Gesamtmenge der zu kopierenden Daten</target>
<source>Items found:</source>
<target>Gefundene Elemente:</target>
@@ -543,10 +552,10 @@ Die Befehlszeile wird ausgelöst wenn:
<source>Speed:</source>
<target>Geschwindigkeit:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Verbleibende Zeit:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Vergangene Zeit:</target>
<source>Batch job</source>
@@ -669,6 +678,15 @@ gleich ist
<source>Source code written in C++ utilizing:</source>
<target>Sourcecode in C++ geschrieben mit Hilfe von:</target>
+<source>If you like FreeFileSync</source>
+<target>Wenn Sie FreeFileSync mögen</target>
+
+<source>Donate with PayPal</source>
+<target>Mit PayPal spenden</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Vielen Dank für die Lokalisation von FreeFileSync an:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Feedback und Vorschläge sind willkommen</target>
@@ -681,39 +699,9 @@ gleich ist
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Vielen Dank für die Lokalisation von FreeFileSync an:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Wenn Sie FreeFileSync mögen</target>
-
-<source>Donate with PayPal</source>
-<target>Mit PayPal spenden</target>
-
<source>Published under the GNU General Public License</source>
<target>Veröffentlicht unter der Allgemeinen Öffentlichen GNU-Lizenz</target>
-<source>Ignore further errors</source>
-<target>Weitere Fehler ignorieren</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Weitere Fehlermeldungen während des laufenden Prozesses ausblenden</target>
-
-<source>&Ignore</source>
-<target>&Ignorieren</target>
-
-<source>Do not show this dialog again</source>
-<target>Diesen Dialog nicht mehr anzeigen</target>
-
-<source>&Switch</source>
-<target>&Wechseln</target>
-
-<source>&Yes</source>
-<target>&Ja</target>
-
-<source>&No</source>
-<target>&Nein</target>
-
<source>Use Recycle Bin</source>
<target>Papierkorb verwenden</target>
@@ -786,6 +774,9 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Statistics</source>
<target>Statistiken</target>
+<source>Do not show this dialog again</source>
+<target>Diesen Dialog nicht mehr anzeigen</target>
+
<source>Find what:</source>
<target>Suchen nach:</target>
@@ -864,8 +855,14 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Never save changes</source>
<target>Änderungen niemals speichern</target>
-<source>Save changes to current configuration?</source>
-<target>Änderungen der aktuellen Konfiguration sichern?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Möchten Sie die Änderungen an %x speichern?</target>
+
+<source>Save</source>
+<target>Speichern</target>
+
+<source>Don't Save</source>
+<target>Nicht speichern</target>
<source>Configuration loaded!</source>
<target>Konfiguration geladen!</target>
@@ -960,11 +957,8 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>All directories in sync!</source>
<target>Alle Verzeichnisse sind synchron!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Vor der Synchronisation bitte zuerst einen Vergleich ausführen!</target>
-
<source>Comma separated list</source>
-<target>Durch Komma getrennte Liste</target>
+<target>Kommagetrennte Liste</target>
<source>Legend</source>
<target>Legende</target>
@@ -1008,6 +1002,24 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<pluralform>Zeige %x von %y Zeilen</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Weitere Fehler ignorieren</target>
+
+<source>&Ignore</source>
+<target>&Ignorieren</target>
+
+<source>&Switch</source>
+<target>&Wechseln</target>
+
+<source>Question</source>
+<target>Frage</target>
+
+<source>&Yes</source>
+<target>&Ja</target>
+
+<source>&No</source>
+<target>&Nein</target>
+
<source>Scanning...</source>
<target>Suche Dateien...</target>
@@ -1188,12 +1200,12 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Cannot delete directory %x.</source>
<target>Das Verzeichnis %x kann nicht gelöscht werden.</target>
-<source>Cannot write modification time of %x.</source>
-<target>Die Änderungszeit von %x kann nicht geschrieben werden.</target>
-
<source>Cannot write file attributes of %x.</source>
<target>Die Dateiattribute von %x können nicht geschrieben werden.</target>
+<source>Cannot write modification time of %x.</source>
+<target>Die Änderungszeit von %x kann nicht geschrieben werden.</target>
+
<source>Cannot find system function %x.</source>
<target>Die Systemfunktion %x wurde nicht gefunden.</target>
@@ -1239,11 +1251,8 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>No change since last synchronization!</source>
<target>Keine Änderungen seit der letzten Synchronisation!</target>
-<source>Filter settings have changed!</source>
-<target>Die Filtereinstellungen wurden geändert!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Die Datei wurde in der letzten Synchronisation nicht verarbeitet!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Die entsprechenden Datenbankeinträge sind nicht synchron gemäß den aktuellen Einstellungen</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Setze Standardwerte für Synchronisationsrichtungen: Alte Dateien werden durch neuere überschrieben.</target>
@@ -1371,14 +1380,14 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Updating attributes of %x</source>
<target>Aktualisiere Attribute von %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Der Name des Zielordners darf nicht leer sein.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Das Eingabefeld für den Zielordner darf nicht leer sein.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Der Ordnername für die Versionierung darf nicht leer sein.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Das Eingabefeld für den Ordner für die Versionierung darf nicht leer sein.</target>
-<source>Source directory %x not found.</source>
-<target>Das Quellverzeichnis %x wurde nicht gefunden.</target>
+<source>Source folder %x not found.</source>
+<target>Der Quellordner %x wurde nicht gefunden.</target>
<source>Unresolved conflicts existing!</source>
<target>Es existieren ungelöste Konflikte!</target>
@@ -1395,11 +1404,11 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Not enough free disk space available in:</source>
<target>Nicht genügend freier Speicher verfügbar unter:</target>
-<source>Free disk space required:</source>
-<target>Benötigter freier Speicherplatz:</target>
+<source>Required:</source>
+<target>Benötigt:</target>
-<source>Free disk space available:</source>
-<target>Verfügbarer freier Speicherplatz:</target>
+<source>Available:</source>
+<target>Verfügbar:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Der Papierkorb ist auf nachfolgenden Verzeichnissen nicht verfügbar! Die Dateien werden stattdessen permanent gelöscht:</target>
@@ -1410,6 +1419,9 @@ Achtung: Dateinamen müssen relativ zu den Basisverzeichnissen sein!
<source>Processing folder pair:</source>
<target>Bearbeite Ordnerpaar:</target>
+<source>Target folder %x already existing.</source>
+<target>Der Zielordner %x existiert bereits.</target>
+
<source>Generating database...</source>
<target>Erzeuge Synchronisationsdatenbank...</target>
diff --git a/BUILD/Languages/greek.lng b/BUILD/Languages/greek.lng
index 0d750585..f75accaf 100644
--- a/BUILD/Languages/greek.lng
+++ b/BUILD/Languages/greek.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Σχετικά με το...</target>
-<source>Warning</source>
-<target>Προειδοποίηση</target>
-
-<source>Question</source>
-<target>Ερώτηση</target>
-
<source>Confirm</source>
<target>Επιβεβαίωση</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Πληροφορία</target>
+<source>Warning</source>
+<target>Προειδοποίηση</target>
+
<source>Fatal Error</source>
<target>Σημαντικό Σφάλμα</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Δεν μπορεί να γίνει ανάγνωση του αρχείου %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Δεν μπορεί να γίνει εγγραφή του αρχείου %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Το αρχείο βάσης δεδομένων %x δεν είναι συμβατό</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Το αρχείο βάσης δεδομένων %x δεν υπάρχει ακόμα.</target>
+<source>Database file is corrupt:</source>
+<target>Το αρχείο βάσης δεδομένων είναι αλλοιωμένο:</target>
+
<source>Out of memory!</source>
<target>Ανεπαρκής μνήμη!</target>
+<source>Cannot write file %x.</source>
+<target>Δεν μπορεί να γίνει εγγραφή του αρχείου %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Δεν μπορεί να γίνει ανάγνωση του αρχείου %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Τα αρχεία βάσης δεδομένων δεν έχουν χρησιμοποιηθεί από κοινού σε συγχρονισμό.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/δευτερόλεπτο</target>
+<source>Cannot find file %x.</source>
+<target>Το αρχείο %x δε βρέθηκε.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Το αρχείο %x δεν περιέχει μια έγκυρη διάταξη.</target>
@@ -226,17 +229,14 @@
<source>Volume name %x not part of file name %y!</source>
<target>Το όνομα τόμου %x δεν είναι μέρος του ονόματος του αρχείου %y!</target>
-<source>Cannot find file %x.</source>
-<target>Το αρχείο %x δε βρέθηκε.</target>
-
<source>Cannot read the following XML elements:</source>
<target>Δεν ήταν δυνατό να αναγνωσθούν τα ακόλουθα στοιχεία XML:</target>
<source>&Open...</source>
<target>Ά&νοιγμα...</target>
-<source>&Save...</source>
-<target>Α&ποθήκευση...</target>
+<source>Save &As...</source>
+<target>Αποθή&κευση ως...</target>
<source>&Quit</source>
<target>Έ&ξοδος</target>
@@ -312,8 +312,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(Δημιουργήθηκε : %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Διαμόρφωση του RealtimeSync</target>
+<source>All files</source>
+<target>Όλα τα αρχεία</target>
<source>&Restore</source>
<target>&Επαναφορά</target>
@@ -327,8 +327,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>Αναμονή για τους υποκαταλόγους που απουσιάζουν...</target>
-<source>An input folder name is empty.</source>
-<target>Το όνομα ενός υποκαταλόγου είναι κενό.</target>
+<source>A folder input field is empty.</source>
+<target>Ένα πεδίο εισαγωγής υποκαταλόγων είναι άδειο.</target>
<source>Logging</source>
<target>Καταγραφή μηνυμάτων</target>
@@ -351,11 +351,8 @@ The command is triggered if:
<source>Custom</source>
<target>Εξατομίκευση</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync αρχείο δέσμης</target>
-
-<source>FreeFileSync configuration</source>
-<target>Αρχείο διάταξης FreeFileSync</target>
+<source>FreeFileSync batch</source>
+<target>Δέσμη ενεργειών του FreeFileSync</target>
<source>Batch execution</source>
<target>Εκτέλεση δέσμης ενεργειών</target>
@@ -393,18 +390,18 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Δεν είναι δυνατή η σύνδεση με το sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Μια νεότερη έκδοση του FreeFileSync είναι διαθέσιμη:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Μια νέα έκδοση του FreeFileSync είναι διαθέσιμη:</target>
<source>Download now?</source>
<target>Λήψη τώρα;</target>
-<source>Information</source>
-<target>Πληροφορία</target>
-
<source>FreeFileSync is up to date!</source>
<target>Το FreeFileSync είναι ενημερωμένο!</target>
+<source>Information</source>
+<target>Πληροφορία</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Θέλετε το FreeFileSync να ελέγχει αυτόματα για ενημερώσεις κάθε εβδομάδα;</target>
@@ -438,6 +435,12 @@ The command is triggered if:
<source>Extension</source>
<target>Επέκταση</target>
+<source>Size:</source>
+<target>Μέγεθος:</target>
+
+<source>Date:</source>
+<target>Ημερομηνία:</target>
+
<source>Action</source>
<target>Ενέργεια</target>
@@ -471,6 +474,9 @@ The command is triggered if:
<source>&New</source>
<target>&Δημιουργία</target>
+<source>&Save</source>
+<target>Απο&θήκευση</target>
+
<source>&Language</source>
<target>&Γλώσσα</target>
@@ -537,11 +543,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>Αριθμός αρχείων και υποκαταλόγων που θα διαγραφούν</target>
-<source>Total amount of data that will be transferred</source>
-<target>Συνολικός όγκος δεδομένων που θα μεταφερθούν</target>
-
-<source>Operation:</source>
-<target>Λειτουργία:</target>
+<source>Total bytes to copy</source>
+<target>Συνολικός αριθμός bytes προς αντιγραφή</target>
<source>Items found:</source>
<target>Βρέθηκαν στοιχεία:</target>
@@ -549,10 +552,10 @@ The command is triggered if:
<source>Speed:</source>
<target>Ταχύτητα:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Απομένει χρόνος:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Πέρασε χρόνος:</target>
<source>Batch job</source>
@@ -675,6 +678,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>Ο πηγαίος κώδικας γράφτηκε σε C++ χρησιμοποιώντας τα:</target>
+<source>If you like FreeFileSync</source>
+<target>Αν σας αρέσει το FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Κάντε μια δωρεά μέσω PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Για τις μεταφράσεις του FreeFileSync, ευχαριστούμε τους:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Τα σχόλια και οι προτάσεις σας είναι ευπρόσδεκτα</target>
@@ -687,39 +699,9 @@ is the same
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Για τις μεταφράσεις του FreeFileSync, ευχαριστούμε τους:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Αν σας αρέσει το FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Κάντε μια δωρεά μέσω PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Διανέμεται υπό την Γενική Άδεια Δημόσιας Χρήσης GNU</target>
-<source>Ignore further errors</source>
-<target>Αγνόηση επόμενων σφαλμάτων</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Απόκρυψη επόμενων μηνυμάτων σφάλματος στην τρέχουσα διαδικασία</target>
-
-<source>&Ignore</source>
-<target>&Παράβλεψη</target>
-
-<source>Do not show this dialog again</source>
-<target>Να μην εμφανιστεί ξανά αυτό το μήνυμα</target>
-
-<source>&Switch</source>
-<target>&Εναλλαγή</target>
-
-<source>&Yes</source>
-<target>&Ναι</target>
-
-<source>&No</source>
-<target>&Όχι</target>
-
<source>Use Recycle Bin</source>
<target>Χρήση του Κάδου Ανακύκλωσης</target>
@@ -792,6 +774,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>Στατιστικά</target>
+<source>Do not show this dialog again</source>
+<target>Να μην εμφανιστεί ξανά αυτό το μήνυμα</target>
+
<source>Find what:</source>
<target>Αναζήτηση του:</target>
@@ -870,8 +855,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>Να μην αποθηκεύονται οι αλλαγές</target>
-<source>Save changes to current configuration?</source>
-<target>Να αποθηκευτούν οι αλλαγές στην τρέχουσα διάταξη;</target>
+<source>Do you want to save changes to %x?</source>
+<target>Θέλετε να αποθηκεύσετε τις αλλαγές στο %x;</target>
+
+<source>Save</source>
+<target>Αποθήκευση</target>
+
+<source>Don't Save</source>
+<target>Χωρίς αποθήκευση</target>
<source>Configuration loaded!</source>
<target>Η διάταξη έχει ανοιχθεί!</target>
@@ -966,9 +957,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>Όλοι οι υποκατάλογοι είναι συγχρονισμένοι!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Παρακαλώ εκτελέστε πρώτα Σύγκριση πριν το Συγχρονισμό!</target>
-
<source>Comma separated list</source>
<target>Κατάλογος οριοθετημένος με κόμματα</target>
@@ -1014,6 +1002,24 @@ Note: File names must be relative to base directories!
<pluralform>%x από τις %y φανερές γραμμές</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Αγνόηση επόμενων σφαλμάτων</target>
+
+<source>&Ignore</source>
+<target>&Παράβλεψη</target>
+
+<source>&Switch</source>
+<target>&Εναλλαγή</target>
+
+<source>Question</source>
+<target>Ερώτηση</target>
+
+<source>&Yes</source>
+<target>&Ναι</target>
+
+<source>&No</source>
+<target>&Όχι</target>
+
<source>Scanning...</source>
<target>Ανίχνευση...</target>
@@ -1194,6 +1200,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>Δεν μπορεί να διαγραφεί ο υποκατάλογος %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Δεν μπορεί να γίνει εγγραφή των χαρακτηριστικών αρχείου του %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Δεν μπορεί να γίνει εγγραφή της ώρας τροποποίησης του %x.</target>
@@ -1218,9 +1227,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Δεν μπορεί να αντιγραφεί ο συμβολικός δεσμός %x στο %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Δεν μπορεί να γίνει εγγραφή των χαρακτηριστικών αρχείου του %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Δεν μπορεί να αντιγραφεί το αρχείο %x στο %y.</target>
@@ -1245,11 +1251,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>Καμία αλλαγή από τον προηγούμενο συγχρονισμό!</target>
-<source>Filter settings have changed!</source>
-<target>Οι ρυθμίσεις φίλτρου έχουν αλλάξει!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Το αρχείο δεν συμμετείχε στον τελευταίο συγχρονισμό!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Οι αντίστοιχες καταχωρήσεις του αρχείου δεδομένων δεν είναι συγχρονισμένες, λαμβάνοντας υπόψη τις τρέχουσες ρυθμίσεις.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Ρύθμιση προεπιλεγμένης κατεύθυνσης συγχρονισμού: Τα νεότερα αρχεία θα αντικαταστήσουν τα παλιότερα.</target>
@@ -1377,14 +1380,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>Ενημέρωση των χαρακτηριστικών αρχείου του %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Ο υποκατάλογος στόχος πρέπει να μην είναι κενός</target>
+<source>Target folder input field must not be empty.</source>
+<target>Το πεδίο εισαγωγής του υποκαταλόγου-στόχου πρέπει να μην είναι κενό.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Το όνομα του υποκαταλόγου για τη διατήρηση παλιών εκδόσεων δεν μπορεί να είναι κενό.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Το πεδίο εισαγωγής του υποκαταλόγου για διατήρηση παλιών εκδόσεων πρέπει να μην είναι κενό.</target>
-<source>Source directory %x not found.</source>
-<target>Ο υποκατάλογος πηγής %x δεν βρέθηκε.</target>
+<source>Source folder %x not found.</source>
+<target>Ο υποκατάλογος %x δε βρέθηκε.</target>
<source>Unresolved conflicts existing!</source>
<target>Υπάρχουν ανεπίλυτες διενέξεις!</target>
@@ -1401,11 +1404,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>Δεν υπάρχει αρκετός διαθέσιμος χώρος στο δίσκο:</target>
-<source>Free disk space required:</source>
-<target>Απαιτούμενος ελεύθερος χώρος δίσκου:</target>
+<source>Required:</source>
+<target>Απαιτείται:</target>
-<source>Free disk space available:</source>
-<target>Διαθέσιμος ελεύθερος χώρος δίσκου:</target>
+<source>Available:</source>
+<target>Διαθέσιμος:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Ο Κάδος Ανακύκλωσης δεν είναι διαθέσιμος για τις ακόλουθες διαδρομές! Τα αρχεία θα διαγραφούν μόνιμα:</target>
@@ -1416,6 +1419,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>Σύγκριση του ζεύγους υποκαταλόγων:</target>
+<source>Target folder %x already existing.</source>
+<target>Ο υποκατάλογος-στόχος %x υπάρχει ήδη.</target>
+
<source>Generating database...</source>
<target>Δημιουργία βάσης δεδομένων...</target>
diff --git a/BUILD/Languages/hebrew.lng b/BUILD/Languages/hebrew.lng
index e17ef10b..db4dd2c6 100644
--- a/BUILD/Languages/hebrew.lng
+++ b/BUILD/Languages/hebrew.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>מחפש את תיקייה %x...</target>
+<source>Batch execution</source>
+<target>פעולת אצווה</target>
+
+<source>Items processed:</source>
+<target>אלמנטים עובדו:</target>
+
+<source>Items remaining:</source>
+<target>אלמנתים נותרו:</target>
+
+<source>Total time:</source>
+<target>זמן כולל:</target>
+
<source>Show in Explorer</source>
<target>הראה בסייר הקבצים</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>אודות</target>
-<source>Warning</source>
-<target>אזהרה</target>
-
-<source>Question</source>
-<target>שאלה</target>
-
<source>Confirm</source>
<target>אשר</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>מידע</target>
+<source>Warning</source>
+<target>אזהרה</target>
+
<source>Fatal Error</source>
<target>שגיאה פטלית</target>
@@ -139,24 +148,27 @@
<pluralform>%x בייט</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>לא יכול לקרוא קובץ %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>לא יכול לכתוב קובץ %x.</target>
-
<source>Database file %x is incompatible.</source>
-<target>קובץ בסיס נתונים %x אינו במבנה מתאים.</target>
+<target>קובץ מסד נתונים %x אינו במבנה מתאים.</target>
<source>Initial synchronization:</source>
<target>סנכרון ראשוני:</target>
<source>Database file %x does not yet exist.</source>
-<target>קובץ בסיס נתונים %x אינו קיים עדיין.</target>
+<target>קובץ מסד נתונים %x אינו קיים עדיין.</target>
+
+<source>Database file is corrupt:</source>
+<target>קובץ מסד נתונים משובש:</target>
<source>Out of memory!</source>
<target>תם הזכרון!</target>
+<source>Cannot write file %x.</source>
+<target>לא יכול לכתוב קובץ %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>לא יכול לקרוא קובץ %x.</target>
+
<source>Database files do not share a common session.</source>
<target>קבצי הנתונים אינם כוללים מופע פעילות משותף.</target>
@@ -205,6 +217,9 @@
<source>/sec</source>
<target>/שנ</target>
+<source>Cannot find file %x.</source>
+<target>לא יכול למצוא קובץ %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>קובץ %x אינו כולל תצורה תקינה.</target>
@@ -229,14 +244,11 @@
<source>Cannot read the following XML elements:</source>
<target>לא יכול לקרוא את שמות צמתי XML:</target>
-<source>Cannot find file %x.</source>
-<target>לא יכול למצוא קובץ %x.</target>
-
<source>&Open...</source>
<target>&פתח...</target>
-<source>&Save...</source>
-<target>&שמור...</target>
+<source>Save &As...</source>
+<target>שמור בשם&</target>
<source>&Quit</source>
<target>&יציאה</target>
@@ -312,8 +324,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(מבנה: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync בקרת תצורה</target>
+<source>All files</source>
+<target>כל הקבצים</target>
<source>&Restore</source>
<target>&טען מחדש</target>
@@ -327,8 +339,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>מחכה למחיצות חסרות...</target>
-<source>An input folder name is empty.</source>
-<target>שם תיקיית קלט ריק.</target>
+<source>A folder input field is empty.</source>
+<target>שדה קלט תיקייה ריק.</target>
<source>Logging</source>
<target>רישום ביומן</target>
@@ -351,26 +363,8 @@ The command is triggered if:
<source>Custom</source>
<target>מותאם</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync קובץ אצווה</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync הגדרות</target>
-
-<source>Batch execution</source>
-<target>פעולת אצווה</target>
-
-<source>Items processed:</source>
-<target>אלמנטים עובדו:</target>
-
-<source>Items remaining:</source>
-<target>אלמנתים נותרו:</target>
-
-<source>Total time:</source>
-<target>זמן כולל:</target>
-
-<source>Stop</source>
-<target>עצור</target>
+<source>FreeFileSync batch</source>
+<target>אצוות FreeFileSync</target>
<source>Synchronization aborted!</source>
<target>סינכרון בוטל!</target>
@@ -393,8 +387,8 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>אין תקשורת ל sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>קיימת גירסה חדשה יותר:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>גירסה חדשה של FreeFileSync זמינה:</target>
<source>Download now?</source>
<target>הורד עכשיו?</target>
@@ -438,6 +432,12 @@ The command is triggered if:
<source>Extension</source>
<target>סיומת</target>
+<source>Size:</source>
+<target>גודל:</target>
+
+<source>Date:</source>
+<target>תאריך:</target>
+
<source>Action</source>
<target>פעולה</target>
@@ -471,6 +471,9 @@ The command is triggered if:
<source>&New</source>
<target>&חדש</target>
+<source>&Save</source>
+<target>&שמור</target>
+
<source>&Language</source>
<target>&שפה</target>
@@ -537,8 +540,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>מספר הקבצים והתיקיות שימחקו</target>
-<source>Total amount of data that will be transferred</source>
-<target>סך הכל נתונים להעברה</target>
+<source>Total bytes to copy</source>
+<target>סה"כ בתים להעתיק</target>
<source>Items found:</source>
<target>אלמנטים נמצאו:</target>
@@ -546,11 +549,11 @@ The command is triggered if:
<source>Speed:</source>
<target>מהירות:</target>
-<source>Remaining time:</source>
-<target>זמן נותר:</target>
+<source>Time remaining:</source>
+<target>זמן שנשאר:</target>
-<source>Elapsed time:</source>
-<target>זמן עבר:</target>
+<source>Time elapsed:</source>
+<target>זמן שעבר:</target>
<source>Batch job</source>
<target>עבודת אצווה</target>
@@ -592,7 +595,7 @@ The command is triggered if:
<target>בחר משתנה:</target>
<source>Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically.</source>
-<target>זהה והפץ שינויים בשני הצדדים באמצעות שימוש בבסיס נתונים. מחיקות, שינויי שמות וסתירות מתגלים באופן אוטומטי.</target>
+<target>זהה והפץ שינויים בשני הצדדים באמצעות שימוש במסד נתונים. מחיקות, שינויי שמות וסתירות מתגלים באופן אוטומטי.</target>
<source>Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization.</source>
<target>גיבוי מראה של מחיצה ימנית. מחיצה שמאלית תתעדכן ותהיה זהה לימנית לאחר הסינכרון.</target>
@@ -672,6 +675,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>קוד מקור נכתב ב- C++ באמצעות:</target>
+<source>If you like FreeFileSync</source>
+<target>במידה ו-FreeFileSync מוצאת חן בעינכם</target>
+
+<source>Donate with PayPal</source>
+<target>תרום עם פייפל</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>תודות עבור עבודות התרגום של תוכנת הסנכרון:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>משוב והצעות יתקבלו בברכה</target>
@@ -684,39 +696,9 @@ is the same
<source>Email</source>
<target>דוא"ל:</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>תודות עבור עבודות התרגום של תוכנת הסנכרון:</target>
-
-<source>If you like FreeFileSync</source>
-<target>במידה ו-FreeFileSync מוצאת חן בעינכם</target>
-
-<source>Donate with PayPal</source>
-<target>תרום עם פייפל</target>
-
<source>Published under the GNU General Public License</source>
<target>מפורסם במסגרת GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>התעלם משגיאות נוספות</target>
-
-<source>Hide further error messages during the current process</source>
-<target>הסתר הודעות שגיאה נוספות בהמשך התהליך הנוכחי</target>
-
-<source>&Ignore</source>
-<target>&התעלם</target>
-
-<source>Do not show this dialog again</source>
-<target>אל תראה מסך זה שנית</target>
-
-<source>&Switch</source>
-<target>&החלפה</target>
-
-<source>&Yes</source>
-<target>&כן</target>
-
-<source>&No</source>
-<target>&לא</target>
-
<source>Use Recycle Bin</source>
<target>השתמש בסל המיחזור</target>
@@ -789,6 +771,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>סטטיסטיקה</target>
+<source>Do not show this dialog again</source>
+<target>אל תראה מסך זה שנית</target>
+
<source>Find what:</source>
<target>חפש מה:</target>
@@ -867,8 +852,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>אל תשמור שינויים לעולם</target>
-<source>Save changes to current configuration?</source>
-<target>שמור שינויים לתצורה נוכחית?</target>
+<source>Do you want to save changes to %x?</source>
+<target>האם לשמור שינויים אל %x?</target>
+
+<source>Save</source>
+<target>שמור</target>
+
+<source>Don't Save</source>
+<target>אל תשמור</target>
<source>Configuration loaded!</source>
<target>תצורה הוטענה!</target>
@@ -963,9 +954,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>כל המחיצות מסונכרנות!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>הרץ השוואה לפני סנכרון!</target>
-
<source>Comma separated list</source>
<target>רשימה מופרדת פסיקים</target>
@@ -1011,6 +999,24 @@ Note: File names must be relative to base directories!
<pluralform>%x מתוך %y שורות בתצוגה</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>התעלם משגיאות נוספות</target>
+
+<source>&Ignore</source>
+<target>&התעלם</target>
+
+<source>&Switch</source>
+<target>&החלפה</target>
+
+<source>Question</source>
+<target>שאלה</target>
+
+<source>&Yes</source>
+<target>&כן</target>
+
+<source>&No</source>
+<target>&לא</target>
+
<source>Scanning...</source>
<target>סורק...</target>
@@ -1191,6 +1197,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>לא יכול למחוק מחיצה %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>לא יכול לכתוב תכונות קובץ של %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>לא יכול לרשום זמן שינוי של %x.</target>
@@ -1215,9 +1224,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>לא יכול להעתיק קישור סימבולי %x אל %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>לא יכול לכתוב תכונות קובץ של %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>לא יכול להעתיק קובץ %x אל %y.</target>
@@ -1242,11 +1248,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>אין שינוי מאז הסנכרון האחרון!</target>
-<source>Filter settings have changed!</source>
-<target>קביעת המסנן שונו!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>קובץ זה לא טופל בסנכרון האחרון!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>ערכי מסד הנתונים המתאימים אינם מסונכרנים בהתחשב בהגדרות הנוכחיות.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>בחר ברירת מחדל של סנכרון: קבצים ישנים ידרסו ע"י קבצים חדשים יותר.</target>
@@ -1374,14 +1377,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>מעדכן תכונות של %x</target>
-<source>Target folder name must not be empty.</source>
-<target>שם תיקיית מטרה אינו יכול להיות ריק.</target>
+<source>Target folder input field must not be empty.</source>
+<target>קלט תיקיית מטרה אינה יכול להיות ריק.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>שם תיקייה לגרסאות קבצים אינו יכול להיות ריק</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>קלט שדה תיקייה עבור גירסאות אינו יכול להיות ריק.</target>
-<source>Source directory %x not found.</source>
-<target>מחיצת מקור %x לא נמצאה.</target>
+<source>Source folder %x not found.</source>
+<target>תיקיית מקור %x לא נמצאת.</target>
<source>Unresolved conflicts existing!</source>
<target>קיים קונפליקט לא פתור!</target>
@@ -1398,11 +1401,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>אין מספיק מקום דיסק פנוי ב:</target>
-<source>Free disk space required:</source>
-<target>מקום דיסק פנוי נדרש:</target>
+<source>Required:</source>
+<target>נדרש:</target>
-<source>Free disk space available:</source>
-<target>מקום פנוי בדיסק:</target>
+<source>Available:</source>
+<target>זמין:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>סל מחזור אינו זמין עבור הנתיבים הבאים! קבצים ימחקו לצמיתות:</target>
@@ -1413,8 +1416,11 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>מבצע זוג מחיצות:</target>
+<source>Target folder %x already existing.</source>
+<target>תיקיית מטרה %x כבר קיימת.</target>
+
<source>Generating database...</source>
-<target>מיצר בסיס נתונים...</target>
+<target>מייצר מסד נתונים...</target>
<source>Data verification error: Source and target file have different content!</source>
<target>שגיאה של אימות נתונים קובץ מקור ומטרה בעלי תכולת נתונים שונה!</target>
diff --git a/BUILD/Languages/hungarian.lng b/BUILD/Languages/hungarian.lng
index d06b0529..f1b0ae8b 100644
--- a/BUILD/Languages/hungarian.lng
+++ b/BUILD/Languages/hungarian.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>A programról</target>
-<source>Warning</source>
-<target>Figyelem</target>
-
-<source>Question</source>
-<target>Kérdés</target>
-
<source>Confirm</source>
<target>Megerősítés</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Információ</target>
+<source>Warning</source>
+<target>Figyelem</target>
+
<source>Fatal Error</source>
<target>Kritikus hiba</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bájt</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>A következő fájl olvasása sikertelen: %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>A következő fájl írása sikertelen: %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Inkompatibilis adatbázisfájl: %x.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>A következő adatbázisfájl nem létezik: %x.</target>
+<source>Database file is corrupt:</source>
+<target></target>
+
<source>Out of memory!</source>
<target>Elfogyott a szabad memória!</target>
+<source>Cannot write file %x.</source>
+<target>A következő fájl írása sikertelen: %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>A következő fájl olvasása sikertelen: %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Az adatbázisfájlok nem osztanak meg közös munkamenetet.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/másodperc</target>
+<source>Cannot find file %x.</source>
+<target>Nem található a következő fájl: %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>A következő fájl nem tartalmaz érvényes beállításokat: %x.</target>
@@ -229,14 +232,11 @@
<source>Cannot read the following XML elements:</source>
<target>A következő XML elemek olvasása sikertelen:</target>
-<source>Cannot find file %x.</source>
-<target>Nem található a következő fájl: %x.</target>
-
<source>&Open...</source>
<target>&Megnyitás...</target>
-<source>&Save...</source>
-<target>Me&ntés...</target>
+<source>Save &As...</source>
+<target></target>
<source>&Quit</source>
<target>&Kilépés</target>
@@ -327,8 +327,8 @@ A parancs végrehajtódik, ha:
<source>Waiting for missing directories...</source>
<target>Várakozás a hiányzó mappákra...</target>
-<source>An input folder name is empty.</source>
-<target>A megadott mappa neve üres.</target>
+<source>A folder input field is empty.</source>
+<target></target>
<source>Logging</source>
<target>Naplózás</target>
@@ -351,8 +351,8 @@ A parancs végrehajtódik, ha:
<source>Custom</source>
<target>Egyedi</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync kötegelt fájl</target>
+<source>FreeFileSync batch</source>
+<target></target>
<source>Batch execution</source>
<target>Kötegelt végrehajtás</target>
@@ -390,8 +390,8 @@ A parancs végrehajtódik, ha:
<source>Unable to connect to sourceforge.net!</source>
<target>A csatlakozás a sourceforge.net-hez sikertelen!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Elérhető a FreeFileSync egy újabb verziója:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target></target>
<source>Download now?</source>
<target>Letöltsem most?</target>
@@ -435,6 +435,12 @@ A parancs végrehajtódik, ha:
<source>Extension</source>
<target>Kiterjesztés</target>
+<source>Size:</source>
+<target></target>
+
+<source>Date:</source>
+<target></target>
+
<source>Action</source>
<target>Művelet</target>
@@ -468,6 +474,9 @@ A parancs végrehajtódik, ha:
<source>&New</source>
<target>&Új</target>
+<source>&Save</source>
+<target></target>
+
<source>&Language</source>
<target>&Nyelv</target>
@@ -534,8 +543,8 @@ A parancs végrehajtódik, ha:
<source>Number of files and folders that will be deleted</source>
<target>A törlendő fájlok és mappák száma</target>
-<source>Total amount of data that will be transferred</source>
-<target>A mozgatandó adatok összmérete</target>
+<source>Total bytes to copy</source>
+<target></target>
<source>Items found:</source>
<target>Talált elemek száma:</target>
@@ -543,11 +552,11 @@ A parancs végrehajtódik, ha:
<source>Speed:</source>
<target>Sebesség:</target>
-<source>Remaining time:</source>
-<target>Hátralévő idő:</target>
+<source>Time remaining:</source>
+<target></target>
-<source>Elapsed time:</source>
-<target>Eltelt idő:</target>
+<source>Time elapsed:</source>
+<target></target>
<source>Batch job</source>
<target>Kötegelt feladat</target>
@@ -667,6 +676,18 @@ A fájlok megegyeznek, ha megegyezik
<source>Source code written in C++ utilizing:</source>
<target>A programot C++-ban fejlesztették a következők felhasználásával:</target>
+<source>If you like FreeFileSync</source>
+<target>FreeFileSync támogatása</target>
+
+<source>Donate with PayPal</source>
+<target>Ha szereted a FreeFileSync-et, támogasd a PayPal segítségével.</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>
+Nagy köszönet a FreeFileSync lokalizációjáért
+a következő személyeknek:
+</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Várjuk a visszajelzéseket és az ötleteket</target>
@@ -679,42 +700,9 @@ A fájlok megegyeznek, ha megegyezik
<source>Email</source>
<target>E-mail</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>
-Nagy köszönet a FreeFileSync lokalizációjáért
-a következő személyeknek:
-</target>
-
-<source>If you like FreeFileSync</source>
-<target>FreeFileSync támogatása</target>
-
-<source>Donate with PayPal</source>
-<target>Ha szereted a FreeFileSync-et, támogasd a PayPal segítségével.</target>
-
<source>Published under the GNU General Public License</source>
<target>Kiadva a GNU General Public License alatt</target>
-<source>Ignore further errors</source>
-<target>További hibák figyelmen kívül hagyása</target>
-
-<source>Hide further error messages during the current process</source>
-<target>A további hibaüzenetek elrejtése az aktuális folyamat során</target>
-
-<source>&Ignore</source>
-<target>&Kihagy</target>
-
-<source>Do not show this dialog again</source>
-<target>Ne mutasd újra ezt a párbeszédablakot</target>
-
-<source>&Switch</source>
-<target>&Váltás</target>
-
-<source>&Yes</source>
-<target>&Igen</target>
-
-<source>&No</source>
-<target>&Nem</target>
-
<source>Use Recycle Bin</source>
<target>Lomtár (Recycle Bin) használata</target>
@@ -787,6 +775,9 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Statistics</source>
<target>Statisztikák</target>
+<source>Do not show this dialog again</source>
+<target>Ne mutasd újra ezt a párbeszédablakot</target>
+
<source>Find what:</source>
<target>Mit keresünk:</target>
@@ -865,8 +856,14 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Never save changes</source>
<target>Változtatások figyelmen kívül hagyása</target>
-<source>Save changes to current configuration?</source>
-<target>Mentsük az aktuális beállítások változásait?</target>
+<source>Do you want to save changes to %x?</source>
+<target></target>
+
+<source>Save</source>
+<target></target>
+
+<source>Don't Save</source>
+<target></target>
<source>Configuration loaded!</source>
<target>Beállítások betöltve!</target>
@@ -961,9 +958,6 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>All directories in sync!</source>
<target>Minden mappa szinkronban!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Kérjük, futtass le egy összehasonlítást mielőtt szinkronizálnál!</target>
-
<source>Comma separated list</source>
<target>Comma separated values</target>
@@ -1009,6 +1003,24 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<pluralform>%x/%y sor a nézetben</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>További hibák figyelmen kívül hagyása</target>
+
+<source>&Ignore</source>
+<target>&Kihagy</target>
+
+<source>&Switch</source>
+<target>&Váltás</target>
+
+<source>Question</source>
+<target>Kérdés</target>
+
+<source>&Yes</source>
+<target>&Igen</target>
+
+<source>&No</source>
+<target>&Nem</target>
+
<source>Scanning...</source>
<target>Vizsgálat folyamatban...</target>
@@ -1189,12 +1201,12 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Cannot delete directory %x.</source>
<target>A következő mappa törlése sikertelen: %x.</target>
-<source>Cannot write modification time of %x.</source>
-<target>Az utolsó módosítás dátumának a beállítása sikertelen a következő fájlnál: %x.</target>
-
<source>Cannot write file attributes of %x.</source>
<target>A következő fájl attribútumainak írása sikertelen: %x.</target>
+<source>Cannot write modification time of %x.</source>
+<target>Az utolsó módosítás dátumának a beállítása sikertelen a következő fájlnál: %x.</target>
+
<source>Cannot find system function %x.</source>
<target>Nem található a következő rendszerfunkció: %x.</target>
@@ -1240,11 +1252,8 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>No change since last synchronization!</source>
<target>Az utolsó szinkronizálás után nem történt változás.</target>
-<source>Filter settings have changed!</source>
-<target>A szűrőbeállítások megváltoztak!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>A fájl nem lett feldolgozva az utolsó szinkronizáció alkalmával!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target></target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Alapértelmezett szinkronizációs irányok beállítása: a régebbi fájlok felülíródnak az újabbakkal.</target>
@@ -1372,14 +1381,14 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Updating attributes of %x</source>
<target>A(z) %x attribútumainak frissítése</target>
-<source>Target folder name must not be empty.</source>
-<target>A célmappa nem lehet üres.</target>
+<source>Target folder input field must not be empty.</source>
+<target></target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>A fájlok verziókövetéséhez használatos mappa neve nem lehet üres.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target></target>
-<source>Source directory %x not found.</source>
-<target>Nem található a következő forrásmappa: %x.</target>
+<source>Source folder %x not found.</source>
+<target></target>
<source>Unresolved conflicts existing!</source>
<target>Feloldatlan ütközések vannak!</target>
@@ -1396,11 +1405,11 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Not enough free disk space available in:</source>
<target>Nincs elég szabad lemezterület:</target>
-<source>Free disk space required:</source>
-<target>Szükséges szabad lemezterület:</target>
+<source>Required:</source>
+<target></target>
-<source>Free disk space available:</source>
-<target>Szabad lemezterület:</target>
+<source>Available:</source>
+<target></target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>A Lomtár (Recycle Bin) nem elérhető a következő útvonalakhoz! A fájlok azonnali törlésre kerülnek helyette:</target>
@@ -1411,6 +1420,9 @@ Megjegyzés: A fájlneveknek relatívnak kell lenniük az alap mappához viszony
<source>Processing folder pair:</source>
<target>Mappapár feldolgozása:</target>
+<source>Target folder %x already existing.</source>
+<target></target>
+
<source>Generating database...</source>
<target>Adatbázis generálása...</target>
diff --git a/BUILD/Languages/italian.lng b/BUILD/Languages/italian.lng
index f80146fb..53e4b011 100644
--- a/BUILD/Languages/italian.lng
+++ b/BUILD/Languages/italian.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Ricerca della cartella %x...</target>
+<source>Batch execution</source>
+<target>Esecuzione in batch</target>
+
+<source>Items processed:</source>
+<target>Elementi processati:</target>
+
+<source>Items remaining:</source>
+<target>Elementi rimanenti:</target>
+
+<source>Total time:</source>
+<target>Tempo totale:</target>
+
<source>Show in Explorer</source>
<target>Mostra in Esplora Risorse</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>Info su</target>
-<source>Warning</source>
-<target>Attenzione</target>
-
-<source>Question</source>
-<target>Domanda</target>
-
<source>Confirm</source>
<target>Conferma</target>
@@ -86,7 +92,7 @@
<target>Mostra popup</target>
<source>Show pop-up on errors or warnings</source>
-<target>Mostra popup di errori o avviso</target>
+<target>Mostra popup di errore o avviso</target>
<source>Ignore errors</source>
<target>Ignora errori</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Attenzione</target>
+
<source>Fatal Error</source>
<target>Errore fatale</target>
@@ -139,12 +148,6 @@
<pluralform>%x Byte</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Impossibile leggere il file %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Impossibile scrivere il file %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Il file database %x non è compatibile.</target>
@@ -154,9 +157,18 @@
<source>Database file %x does not yet exist.</source>
<target>Il file database %x non è ancora stato creato.</target>
+<source>Database file is corrupt:</source>
+<target>Il file database è corrotto:</target>
+
<source>Out of memory!</source>
<target>Memoria insufficiente!</target>
+<source>Cannot write file %x.</source>
+<target>Impossibile scrivere il file %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Impossibile leggere il file %x.</target>
+
<source>Database files do not share a common session.</source>
<target>I file database non condividono una sessione comune.</target>
@@ -205,6 +217,9 @@
<source>/sec</source>
<target>/sec</target>
+<source>Cannot find file %x.</source>
+<target>Impossibile trovare il file %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Il file %x non contiene una configurazione valida.</target>
@@ -229,14 +244,11 @@
<source>Cannot read the following XML elements:</source>
<target>Impossibile leggere i seguenti elementi XML:</target>
-<source>Cannot find file %x.</source>
-<target>Impossibile trovare il file %x.</target>
-
<source>&Open...</source>
<target>&Apri...</target>
-<source>&Save...</source>
-<target>&Salva...</target>
+<source>Save &As...</source>
+<target>Salva &Con nome...</target>
<source>&Quit</source>
<target>&Esci</target>
@@ -312,8 +324,8 @@ Il comando è attivato se:
<source>(Build: %x)</source>
<target>(Versione: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Configurazione di RealtimeSync</target>
+<source>All files</source>
+<target>Tutti i file</target>
<source>&Restore</source>
<target>&Ripristina</target>
@@ -327,8 +339,8 @@ Il comando è attivato se:
<source>Waiting for missing directories...</source>
<target>In attesa delle cartelle mancanti...</target>
-<source>An input folder name is empty.</source>
-<target>Il nome di una cartella di input è vuoto.</target>
+<source>A folder input field is empty.</source>
+<target>Un campo cartella input è vuoto.</target>
<source>Logging</source>
<target>Registo attività</target>
@@ -351,26 +363,8 @@ Il comando è attivato se:
<source>Custom</source>
<target>Personalizza</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync file batch</target>
-
-<source>FreeFileSync configuration</source>
-<target>Configurazione di FreeFileSync</target>
-
-<source>Batch execution</source>
-<target>Esecuzione in batch</target>
-
-<source>Items processed:</source>
-<target>Elementi processati:</target>
-
-<source>Items remaining:</source>
-<target>Elementi rimanenti:</target>
-
-<source>Total time:</source>
-<target>Tempo totale:</target>
-
-<source>Stop</source>
-<target>Stop</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync batch</target>
<source>Synchronization aborted!</source>
<target>Sincronizzazione abortita!</target>
@@ -393,7 +387,7 @@ Il comando è attivato se:
<source>Unable to connect to sourceforge.net!</source>
<target>Impossibile collegarsi a sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>E' disponibile una nuova versione di FreeFileSync:</target>
<source>Download now?</source>
@@ -438,6 +432,12 @@ Il comando è attivato se:
<source>Extension</source>
<target>Estensione</target>
+<source>Size:</source>
+<target>Dimensione:</target>
+
+<source>Date:</source>
+<target>Data:</target>
+
<source>Action</source>
<target>Azioni</target>
@@ -471,6 +471,9 @@ Il comando è attivato se:
<source>&New</source>
<target>&Nuovo</target>
+<source>&Save</source>
+<target>&Salva</target>
+
<source>&Language</source>
<target>&Lingua</target>
@@ -537,8 +540,8 @@ Il comando è attivato se:
<source>Number of files and folders that will be deleted</source>
<target>Numero di file e cartelle che verranno eliminati</target>
-<source>Total amount of data that will be transferred</source>
-<target>Volume dei dati che verranno trasferiti</target>
+<source>Total bytes to copy</source>
+<target>Bytes totali da copiare</target>
<source>Items found:</source>
<target>Elementi trovati:</target>
@@ -546,14 +549,14 @@ Il comando è attivato se:
<source>Speed:</source>
<target>Velocita':</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Tempo rimanente:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Tempo trascorso:</target>
<source>Batch job</source>
-<target>Attivitò batch</target>
+<target>Attività batch</target>
<source>Create a batch file to automate synchronization. Double-click this file or schedule in your system's task planner: FreeFileSync.exe <job name>.ffs_batch</source>
<target>Crea un file batch per automatizzare la sincronizzazione. Doppio click su questo file o schedula nelle operazioni pianificate del tuo sistema: FreeFileSync.exe <nome file batch>.ffs_batch</target>
@@ -672,6 +675,15 @@ I file sono considerati identici se
<source>Source code written in C++ utilizing:</source>
<target>Codice sorgente scritto in C++ utilizzando:</target>
+<source>If you like FreeFileSync</source>
+<target>Se ti piace FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Fai una donazione con PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Per la traduzione di FreeFileSync, un grazie va a:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Ogni commento o suggerimento è ben accetto</target>
@@ -684,39 +696,9 @@ I file sono considerati identici se
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Per la traduzione di FreeFileSync, un grazie va a:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Se ti piace FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Fai una donazione con PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Pubblicato sotto licenza GNU General Public</target>
-<source>Ignore further errors</source>
-<target>Ignora i prossimi errori</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Non mostrare i successivi messaggi d'errore durante il processo corrente</target>
-
-<source>&Ignore</source>
-<target>&Ignora</target>
-
-<source>Do not show this dialog again</source>
-<target>Non visualizzare più questo messaggio</target>
-
-<source>&Switch</source>
-<target>&Passa</target>
-
-<source>&Yes</source>
-<target>&Si</target>
-
-<source>&No</source>
-<target>&No</target>
-
<source>Use Recycle Bin</source>
<target>Usa il Cestino</target>
@@ -789,6 +771,9 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Statistics</source>
<target>Statistiche</target>
+<source>Do not show this dialog again</source>
+<target>Non visualizzare più questo messaggio</target>
+
<source>Find what:</source>
<target>Trova questo:</target>
@@ -867,8 +852,14 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Never save changes</source>
<target>Non salvare mai le modifiche</target>
-<source>Save changes to current configuration?</source>
-<target>Salvare i cambiamenti alla configurazione corrente?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Vuoi salvare le modifiche a %x?</target>
+
+<source>Save</source>
+<target>Salva</target>
+
+<source>Don't Save</source>
+<target>Non salvare</target>
<source>Configuration loaded!</source>
<target>Configurazione caricata!</target>
@@ -963,9 +954,6 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>All directories in sync!</source>
<target>Tutte le cartelle sincronizzate!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Prima di sincronizzare effettua una comparazione!</target>
-
<source>Comma separated list</source>
<target>Elenco elementi separati da virgola</target>
@@ -1011,6 +999,24 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<pluralform>%x di %y righe nella vista</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignora i prossimi errori</target>
+
+<source>&Ignore</source>
+<target>&Ignora</target>
+
+<source>&Switch</source>
+<target>&Passa</target>
+
+<source>Question</source>
+<target>Domanda</target>
+
+<source>&Yes</source>
+<target>&Si</target>
+
+<source>&No</source>
+<target>&No</target>
+
<source>Scanning...</source>
<target>Scansione...</target>
@@ -1191,6 +1197,9 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Cannot delete directory %x.</source>
<target>Impossibile eliminare la cartella %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Impossibile scrivere attributi file di %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Impossibile scrivere data e ora di modifica di %x.</target>
@@ -1215,9 +1224,6 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Impossibile copiare collegamento %x su %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Impossibile scrivere attributi file di %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Impossibile copiare file %x in %y.</target>
@@ -1242,11 +1248,8 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>No change since last synchronization!</source>
<target>Nessun cambiamento dall'ultima sincronizzazione!</target>
-<source>Filter settings have changed!</source>
-<target>Le impostazioni del filtro sono cambiate!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Il file non era processato nell'ultima sincronizzazione!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Le voci del database corrispondenti non sono in sincronia con le impostazioni correnti.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Imposta direzioni di sincronizzazione dpredefinite: i vecchi file saranno sovrascritti dai nuovi.</target>
@@ -1374,13 +1377,13 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Updating attributes of %x</source>
<target>Aggiornamento attributi di %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Il nome della cartella di destinazione non può essere vuoto.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Il campo per la cartella di destinazione non può essere vuoto.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Il nome della cartella per le versioni dei file non può essere vuoto.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Il campo per la cartella di versione non può essere vuoto.</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>Cartella sorgente %x non trovata.</target>
<source>Unresolved conflicts existing!</source>
@@ -1398,11 +1401,11 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Not enough free disk space available in:</source>
<target>Spazio libero su disco insufficiente in:</target>
-<source>Free disk space required:</source>
-<target>Spazio libero su disco richiesto:</target>
+<source>Required:</source>
+<target>Richiesto:</target>
-<source>Free disk space available:</source>
-<target>Spazio libero su disco disponibile:</target>
+<source>Available:</source>
+<target>Dispobilile:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Cestino non disponibile per i seguenti percorsi! I file verranno cancellati in modo permanente:</target>
@@ -1413,6 +1416,9 @@ Nota: I nomi dei file devono essere relativi alle cartelle di appartenenza!
<source>Processing folder pair:</source>
<target>Elaborazione coppia di cartelle:</target>
+<source>Target folder %x already existing.</source>
+<target>La cartella di destinazione %x è già esistente.</target>
+
<source>Generating database...</source>
<target>Generazione database...</target>
diff --git a/BUILD/Languages/japanese.lng b/BUILD/Languages/japanese.lng
index bd10d465..e40b6f92 100644
--- a/BUILD/Languages/japanese.lng
+++ b/BUILD/Languages/japanese.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>情報</target>
-<source>Warning</source>
-<target>警告</target>
-
-<source>Question</source>
-<target>質問</target>
-
<source>Confirm</source>
<target>確認</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>情報</target>
+<source>Warning</source>
+<target>警告</target>
+
<source>Fatal Error</source>
<target>致命的なエラー</target>
@@ -138,12 +135,6 @@
<pluralform>%x バイト</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>ファイル %x を読み込めません.</target>
-
-<source>Cannot write file %x.</source>
-<target>ファイル %x に書き込めません.</target>
-
<source>Database file %x is incompatible.</source>
<target>データベース %x とは互換性がありません.</target>
@@ -153,9 +144,18 @@
<source>Database file %x does not yet exist.</source>
<target>データベース %x は存在しません.</target>
+<source>Database file is corrupt:</source>
+<target>破損しているデータベース:</target>
+
<source>Out of memory!</source>
<target>メモリが足りません!</target>
+<source>Cannot write file %x.</source>
+<target>ファイル %x に書き込めません.</target>
+
+<source>Cannot read file %x.</source>
+<target>ファイル %x を読み込めません.</target>
+
<source>Database files do not share a common session.</source>
<target>データベースは一般セッションで共有できません.</target>
@@ -202,6 +202,9 @@
<source>/sec</source>
<target>/秒</target>
+<source>Cannot find file %x.</source>
+<target>ファイル %x がみつかりません.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>ファイル %x には有効な構成が含まれていません.</target>
@@ -223,20 +226,17 @@
<source>Volume name %x not part of file name %y!</source>
<target>ボリューム名 %x にファイル名 %y はありません!</target>
-<source>Cannot find file %x.</source>
-<target>ファイル %x がみつかりません.</target>
-
<source>Cannot read the following XML elements:</source>
<target>次の XML要素を読み込めません:</target>
<source>&Open...</source>
<target>開く(&O)...</target>
-<source>&Save...</source>
-<target>保存(&S)...</target>
+<source>Save &As...</source>
+<target>別名保存(&A)...</target>
<source>&Quit</source>
-<target>終了(&Q)(&Q)</target>
+<target>終了(&Q)</target>
<source>&Program</source>
<target>プログラム(&P)</target>
@@ -309,8 +309,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(ビルド: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>リアルタイム同期の構成設定</target>
+<source>All files</source>
+<target>すべてのファイル</target>
<source>&Restore</source>
<target>修復(&R)</target>
@@ -324,8 +324,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>見失ったディレクトリの待機中...</target>
-<source>An input folder name is empty.</source>
-<target>空のフォルダ名入力</target>
+<source>A folder input field is empty.</source>
+<target>フォルダ入力欄が空白です.</target>
<source>Logging</source>
<target>ログ</target>
@@ -348,11 +348,8 @@ The command is triggered if:
<source>Custom</source>
<target>カスタム</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync バッチファイル</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync 構成設定</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync 一括</target>
<source>Batch execution</source>
<target>一括処理を実行</target>
@@ -390,18 +387,18 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Sourceforge.net に接続できません!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>FreeFileSync の新しいバージョンが利用可能です:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>FreeFileSync の新しいバージョンが利用できます:</target>
<source>Download now?</source>
<target>ダウンロードしますか?</target>
-<source>Information</source>
-<target>インフォメーション</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync は最新です!</target>
+<source>Information</source>
+<target>インフォメーション</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>FreeFileSync の更新確認を毎週自動的に行いますか?</target>
@@ -435,6 +432,12 @@ The command is triggered if:
<source>Extension</source>
<target>拡張子</target>
+<source>Size:</source>
+<target>サイズ:</target>
+
+<source>Date:</source>
+<target>日時:</target>
+
<source>Action</source>
<target>操作</target>
@@ -468,6 +471,9 @@ The command is triggered if:
<source>&New</source>
<target>新規(&N)</target>
+<source>&Save</source>
+<target>保存(&S)</target>
+
<source>&Language</source>
<target>使用言語(&L)</target>
@@ -534,11 +540,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>削除されたファイル、およびフォルダの数</target>
-<source>Total amount of data that will be transferred</source>
-<target>転送されたデータの総量</target>
-
-<source>Operation:</source>
-<target>操作:</target>
+<source>Total bytes to copy</source>
+<target>コピーする合計バイト</target>
<source>Items found:</source>
<target>見つかった要素:</target>
@@ -546,11 +549,11 @@ The command is triggered if:
<source>Speed:</source>
<target>速度:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>残り時間:</target>
-<source>Elapsed time:</source>
-<target>経過時間:</target>
+<source>Time elapsed:</source>
+<target>経過時間</target>
<source>Batch job</source>
<target>一括処理</target>
@@ -672,6 +675,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>ソースコードは C++ で書かれています</target>
+<source>If you like FreeFileSync</source>
+<target>FreeFileSync が気に入った場合</target>
+
+<source>Donate with PayPal</source>
+<target>PayPal から寄付する</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>FreeFileSync のローカライズへの協力に感謝します:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>フィードバック、提案などはこちらから</target>
@@ -684,39 +696,9 @@ is the same
<source>Email</source>
<target>E-メール</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>FreeFileSync のローカライズへの協力に感謝します:</target>
-
-<source>If you like FreeFileSync</source>
-<target>FreeFileSync が気に入った場合</target>
-
-<source>Donate with PayPal</source>
-<target>PayPal から寄付する</target>
-
<source>Published under the GNU General Public License</source>
<target>GNU 一般共有使用許諾に基づき公開されています</target>
-<source>Ignore further errors</source>
-<target>以降のエラーを無視</target>
-
-<source>Hide further error messages during the current process</source>
-<target>現在の処理中は以降のエラーメッセージを表示しない</target>
-
-<source>&Ignore</source>
-<target>無視(&I)</target>
-
-<source>Do not show this dialog again</source>
-<target>次回から表示しない</target>
-
-<source>&Switch</source>
-<target>切り替え(&S)</target>
-
-<source>&Yes</source>
-<target>はい(&Y)</target>
-
-<source>&No</source>
-<target>いいえ(&N)</target>
-
<source>Use Recycle Bin</source>
<target>ゴミ箱を使用</target>
@@ -789,6 +771,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>統計</target>
+<source>Do not show this dialog again</source>
+<target>次回から表示しない</target>
+
<source>Find what:</source>
<target>検索語:</target>
@@ -867,8 +852,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>変更を保存しない</target>
-<source>Save changes to current configuration?</source>
-<target>現在の構成の変更を保存しますか?</target>
+<source>Do you want to save changes to %x?</source>
+<target>本当に %x の変更を保存しますか?</target>
+
+<source>Save</source>
+<target>保存</target>
+
+<source>Don't Save</source>
+<target>保存しない</target>
<source>Configuration loaded!</source>
<target>構成設定を読み込み中!</target>
@@ -963,9 +954,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>すべてのディレクトリを同期!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>同期処理を実行する前に比較を行ってください!</target>
-
<source>Comma separated list</source>
<target>カンマ区切り</target>
@@ -1007,6 +995,24 @@ Note: File names must be relative to base directories!
<pluralform>%x / %y 行を表示</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>以降のエラーを無視</target>
+
+<source>&Ignore</source>
+<target>無視(&I)</target>
+
+<source>&Switch</source>
+<target>切り替え(&S)</target>
+
+<source>Question</source>
+<target>質問</target>
+
+<source>&Yes</source>
+<target>はい(&Y)</target>
+
+<source>&No</source>
+<target>いいえ(&N)</target>
+
<source>Scanning...</source>
<target>スキャン中...</target>
@@ -1182,6 +1188,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>ディレクトリ %x を削除できません.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>%x のファイル属性を書き込めません.</target>
+
<source>Cannot write modification time of %x.</source>
<target>%x の更新時刻を書き込めませんでした.</target>
@@ -1206,9 +1215,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>S リンクを %x から %y にコピーできません.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>%x のファイル属性を書き込めません.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>%x から %y にコピーできません.</target>
@@ -1233,11 +1239,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>前回の同期以降、変更はありません!</target>
-<source>Filter settings have changed!</source>
-<target>フィルター設定は変更されています!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>このファイルは最後の同期操作時に処理されていません!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>現在の設定で同期を行うための、対応したデータベースエントリが存在しません.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>同期方向のデフォルト設定: 古いファイルに新しいファイルを上書き</target>
@@ -1365,14 +1368,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>%x の属性を更新</target>
-<source>Target folder name must not be empty.</source>
-<target>対象フォルダ名に空白は使用出来ません.</target>
+<source>Target folder input field must not be empty.</source>
+<target>対象フォルダ入力欄が空白になっています.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>ファイルバージョンのフォルダ名に空白は使用出来ません.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>バージョン管理のためフォルダ入力欄に空白は使えません.</target>
-<source>Source directory %x not found.</source>
-<target>ソースディレクトリ %x がみつかりません.</target>
+<source>Source folder %x not found.</source>
+<target>ソースフォルダ %x が見つかりません</target>
<source>Unresolved conflicts existing!</source>
<target>未解決の不一致があります!</target>
@@ -1389,11 +1392,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>利用可能なディスク空き容量が足りません:</target>
-<source>Free disk space required:</source>
-<target>必要なディスク空き容量:</target>
+<source>Required:</source>
+<target>必須:</target>
-<source>Free disk space available:</source>
-<target>利用可能なディスク空き容量:</target>
+<source>Available:</source>
+<target>利用可能:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>以下のパスにあるゴミ箱が利用できません! 代わりにファイルは完全削除されます:</target>
@@ -1404,6 +1407,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>フォルダペアを処理中:</target>
+<source>Target folder %x already existing.</source>
+<target>対象フォルダ %x は既に存在します.</target>
+
<source>Generating database...</source>
<target>データベースを作成中...</target>
diff --git a/BUILD/Languages/korean.lng b/BUILD/Languages/korean.lng
index 47561dfe..79f58d51 100644
--- a/BUILD/Languages/korean.lng
+++ b/BUILD/Languages/korean.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>상세 정보</target>
-<source>Warning</source>
-<target>경고</target>
-
-<source>Question</source>
-<target>질문</target>
-
<source>Confirm</source>
<target>확인</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>정보</target>
+<source>Warning</source>
+<target>경고</target>
+
<source>Fatal Error</source>
<target>치명적 오류</target>
@@ -138,12 +135,6 @@
<pluralform>%x 바이트</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>파일 %x 을(를) 읽을 수 없습니다.</target>
-
-<source>Cannot write file %x.</source>
-<target>파일 %x 을(를) 쓸 수 없습니다.</target>
-
<source>Database file %x is incompatible.</source>
<target>데이터베이스 파일 %x 은(는) 호환 불가능합니다.</target>
@@ -153,9 +144,18 @@
<source>Database file %x does not yet exist.</source>
<target>데이터베이스 파일 %x 은(는) 아직 존재하지 않습니다.</target>
+<source>Database file is corrupt:</source>
+<target>데이터베이스 파일 손상 :</target>
+
<source>Out of memory!</source>
<target>메모리 부족!</target>
+<source>Cannot write file %x.</source>
+<target>파일 %x 을(를) 쓸 수 없습니다.</target>
+
+<source>Cannot read file %x.</source>
+<target>파일 %x 을(를) 읽을 수 없습니다.</target>
+
<source>Database files do not share a common session.</source>
<target>데이터베이스 파일이 일반/공동 세션을 공유하지 않습니다.</target>
@@ -183,7 +183,7 @@
</target>
<source>Error parsing file %x, row %y, column %z.</source>
-<target>분석 오류 - 파일: %x, 행: %y, 열: %z</target>
+<target>분석 오류 - 파일: %x; 행: %y; 열: %z</target>
<source>Scanning:</source>
<target>스캔 :</target>
@@ -202,6 +202,9 @@
<source>/sec</source>
<target>/초</target>
+<source>Cannot find file %x.</source>
+<target>파일 %x 을(를) 찾을 수 없습니다.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>파일 %x 의 구성이 유효하지 않습니다.</target>
@@ -223,17 +226,14 @@
<source>Volume name %x not part of file name %y!</source>
<target>볼륨 이름 %x 은(는) 파일 이름 %y 의 일부가 아님!</target>
-<source>Cannot find file %x.</source>
-<target>파일 %x 을(를) 찾을 수 없습니다.</target>
-
<source>Cannot read the following XML elements:</source>
<target>다음 XML 요소를 읽을 수 없습니다 :</target>
<source>&Open...</source>
<target>열기(&O)</target>
-<source>&Save...</source>
-<target>저장(&S)</target>
+<source>Save &As...</source>
+<target>다른 이름으로 저장(&A)</target>
<source>&Quit</source>
<target>종료(&Q)</target>
@@ -263,7 +263,7 @@
<target>3. '시작'을 누르세요.</target>
<source>To get started just import a .ffs_batch file.</source>
-<target>시작하려면 .ffs_batch file (일괄 파일)만 가져오면 됩니다.</target>
+<target>시작하려면 .ffs_batch file (일괄 파일)을 가져오십시오.</target>
<source>Folders to watch</source>
<target>열어 볼 폴더</target>
@@ -292,7 +292,7 @@ The command is triggered if:
- new folders arrive (e.g. USB stick insert)
</source>
<target>
-명령은 다음과 경우에 실행됩니다 :
+명령은 다음과 같은 경우에 실행됩니다 :
- 파일이나 하위 폴더 변경 시
- 새 폴더가 생겼을 시 (예 : USB 스틱 삽입)
</target>
@@ -309,8 +309,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(빌드: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>실시간 동기화 설정</target>
+<source>All files</source>
+<target>모든 파일</target>
<source>&Restore</source>
<target>복원(&R)</target>
@@ -324,8 +324,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>누락 디렉토리 대기 중...</target>
-<source>An input folder name is empty.</source>
-<target>입력 폴더 이름이 비어 있습니다.</target>
+<source>A folder input field is empty.</source>
+<target>폴더 입력 필드 하나가 비어 있습니다.</target>
<source>Logging</source>
<target>로깅</target>
@@ -348,11 +348,8 @@ The command is triggered if:
<source>Custom</source>
<target>개인 설정</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync 일괄 파일</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync 구성 설정</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync 일괄처리(배치)</target>
<source>Batch execution</source>
<target>일괄 실행</target>
@@ -390,18 +387,18 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Sourceforge.net에 접속할 수 없습니다!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>새로운 버전의 FreeFileSync가 나왔습니다.</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>새로운 버전의 FreeFileSync가 나왔습니다 :</target>
<source>Download now?</source>
<target>지금 다운로드 하시겠습니까?</target>
-<source>Information</source>
-<target>인포메이션 (정보)</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync 는 현재 최신버전 상태입니다!</target>
+<source>Information</source>
+<target>인포메이션 (정보)</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>FreeFileSync가 매주 자동으로 업데이트를 확인하도록 하시겠습니까?</target>
@@ -435,6 +432,12 @@ The command is triggered if:
<source>Extension</source>
<target>확장자</target>
+<source>Size:</source>
+<target>크기 :</target>
+
+<source>Date:</source>
+<target>날짜 :</target>
+
<source>Action</source>
<target>실행</target>
@@ -460,13 +463,16 @@ The command is triggered if:
<target>최대절전모드</target>
<source>1. &Compare</source>
-<target>1. 비교</target>
+<target>1. 비교(&C)</target>
<source>2. &Synchronize</source>
-<target>2. 동기화</target>
+<target>2. 동기화(&S)</target>
<source>&New</source>
-<target>신규 작업</target>
+<target>신규 작업(&N)</target>
+
+<source>&Save</source>
+<target>저장(&S)</target>
<source>&Language</source>
<target>언어 선택(&L)</target>
@@ -534,11 +540,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>삭제될 파일 및 폴더 ​​개수</target>
-<source>Total amount of data that will be transferred</source>
-<target>전송하게 될 전체 데이터 용량</target>
-
-<source>Operation:</source>
-<target>작업 :</target>
+<source>Total bytes to copy</source>
+<target>복사할 전체 바이트 크기</target>
<source>Items found:</source>
<target>발견된 항목 :</target>
@@ -546,10 +549,10 @@ The command is triggered if:
<source>Speed:</source>
<target>속도 :</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>남은 시간 :</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>경과 시간 :</target>
<source>Batch job</source>
@@ -672,6 +675,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>소스코드는 C++ 언어로 아래 툴을 사용하여 작성되었습니다 :</target>
+<source>If you like FreeFileSync</source>
+<target>FreeFileSync를 위한 기부</target>
+
+<source>Donate with PayPal</source>
+<target>PayPal로 기부하기</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>FreeFileSync 현지화에 도움을 주신 분들께 감사 드립니다 :</target>
+
<source>Feedback and suggestions are welcome</source>
<target>모든 의견 및 건의/제안을 환영합니다</target>
@@ -684,39 +696,9 @@ is the same
<source>Email</source>
<target>이메일</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>FreeFileSync 현지화에 도움을 주신 분들께 감사 드립니다 :</target>
-
-<source>If you like FreeFileSync</source>
-<target>FreeFileSync를 위한 기부</target>
-
-<source>Donate with PayPal</source>
-<target>PayPal로 기부하기</target>
-
<source>Published under the GNU General Public License</source>
<target>GNU 일반 공용 라이센스에 의한 출시</target>
-<source>Ignore further errors</source>
-<target>더 이상의 오류는 무시</target>
-
-<source>Hide further error messages during the current process</source>
-<target>현재 처리과정 동안 추가오류 메세지 숨기기</target>
-
-<source>&Ignore</source>
-<target>무시(&I)</target>
-
-<source>Do not show this dialog again</source>
-<target>다음부터 표시하지 않음</target>
-
-<source>&Switch</source>
-<target>스위치[전환](&S)</target>
-
-<source>&Yes</source>
-<target>예(&Y)</target>
-
-<source>&No</source>
-<target>아니오(&N)</target>
-
<source>Use Recycle Bin</source>
<target>휴지통 사용</target>
@@ -760,7 +742,7 @@ Note: File names must be relative to base directories!
<target>실패 - 안전 파일 복사</target>
<source>Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error.</source>
-<target>임시 파일 (*.ffs_tmp)로 우선 작성 후, 파일명을 변경합니다. 이러면 치명적인 오류가 발생하더라도 일관된 상태를 보장할 수 있습니다.</target>
+<target>임시 파일 (*.ffs_tmp)로 우선 작성 후, 파일명을 변경합니다. 이렇게 할 경우 치명적인 오류가 발생하더라도 일관된 상태를 보장할 수 있습니다.</target>
<source>Copy locked files</source>
<target>락 걸린 파일 복사</target>
@@ -789,6 +771,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>통계</target>
+<source>Do not show this dialog again</source>
+<target>다음부터 표시하지 않음</target>
+
<source>Find what:</source>
<target>검색어 :</target>
@@ -867,8 +852,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>변경사항 절대 저장 안 함.</target>
-<source>Save changes to current configuration?</source>
-<target>현재 설정의 변경 내용을 저장하시겠습니까?</target>
+<source>Do you want to save changes to %x?</source>
+<target>%x의 변경사항을 저장하시겠습니까?</target>
+
+<source>Save</source>
+<target>저장</target>
+
+<source>Don't Save</source>
+<target>저장 안 함.</target>
<source>Configuration loaded!</source>
<target>설정 로드 완료!</target>
@@ -963,9 +954,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>모든 디렉토리 동기화!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>동기화 작업 이전에 비교를 먼저 실행해 주십시오!</target>
-
<source>Comma separated list</source>
<target>콤마 분리 목록</target>
@@ -1007,6 +995,24 @@ Note: File names must be relative to base directories!
<pluralform>보기에 나타난 %y개 행의 %x개 대상</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>더 이상의 오류는 무시</target>
+
+<source>&Ignore</source>
+<target>무시(&I)</target>
+
+<source>&Switch</source>
+<target>스위치[전환](&S)</target>
+
+<source>Question</source>
+<target>질문</target>
+
+<source>&Yes</source>
+<target>예(&Y)</target>
+
+<source>&No</source>
+<target>아니오(&N)</target>
+
<source>Scanning...</source>
<target>스캔 중...</target>
@@ -1182,6 +1188,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>디렉토리 %x 을(를) 삭제할 수 없습니다.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>%x의 파일 속성을 쓸 수 없습니다.</target>
+
<source>Cannot write modification time of %x.</source>
<target>%x의 수정 시간을 쓸 수 없습니다.</target>
@@ -1206,9 +1215,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>심볼릭 링크 %x 을(를) %y (으)로 복사할 수 없습니다.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>%x의 파일 속성을 쓸 수 없습니다.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>파일 %x 을(를) %y (으)로 복사할 수 없습니다.</target>
@@ -1233,11 +1239,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>마지막 동기화 이후 변경사항 없음!</target>
-<source>Filter settings have changed!</source>
-<target>필터 설정이 변경 됐습니다!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>이 파일은 마지막 동기화에서 처리되지 않았습니다!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>해당 데이터베이스 항목은 현재 설정 상태에서 동기화 되지 않습니다.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>기본값 동기화 방향 설정 : 이전 파일들은 신규 파일들로 덮어 쓰여집니다.</target>
@@ -1365,14 +1368,14 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>%x 속성 업데이트 중</target>
-<source>Target folder name must not be empty.</source>
-<target>대상 폴더 이름은 비워둘 수 없습니다.</target>
+<source>Target folder input field must not be empty.</source>
+<target>대상 폴더 입력 필드가 비어 있어서는 안 됩니다.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>파일 버저닝을 위한 폴더 이름은 비워둘 수 없습니다.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>버저닝을 위한 폴더 입력 필드가 비어 있어서는 안 됩니다.</target>
-<source>Source directory %x not found.</source>
-<target>소스 디렉토리 %x 을(를) 찾을 수 없습니다.</target>
+<source>Source folder %x not found.</source>
+<target>소스 폴더 %x을(를) 찾을 수 없음.</target>
<source>Unresolved conflicts existing!</source>
<target>해결되지 않은 충돌이 있습니다!</target>
@@ -1389,11 +1392,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>사용 가능한 디스크 여유 공간이 부족합니다 :</target>
-<source>Free disk space required:</source>
-<target>필요한 디스크 여유 공간 :</target>
+<source>Required:</source>
+<target>필요 공간(크기) :</target>
-<source>Free disk space available:</source>
-<target>사용 가능한 디스크 여유 공간 :</target>
+<source>Available:</source>
+<target>여유 공간(크기) :</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>다음 경로로는 휴지통을 사용할 수 없습니다! 대신 파일을 영구적으로 삭제합니다 :</target>
@@ -1404,6 +1407,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>폴더 페어 처리 중 :</target>
+<source>Target folder %x already existing.</source>
+<target>대상 폴더 %x이(가) 이미 존재함.</target>
+
<source>Generating database...</source>
<target>데이터베이스 생성 중...</target>
diff --git a/BUILD/Languages/lithuanian.lng b/BUILD/Languages/lithuanian.lng
index e30eb48c..7b44874a 100644
--- a/BUILD/Languages/lithuanian.lng
+++ b/BUILD/Languages/lithuanian.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Apie</target>
-<source>Warning</source>
-<target>Perspėjimas</target>
-
-<source>Question</source>
-<target>Klausimas</target>
-
<source>Confirm</source>
<target>Patvirtinti</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Informacija</target>
+<source>Warning</source>
+<target>Perspėjimas</target>
+
<source>Fatal Error</source>
<target>Kritinė klaida</target>
@@ -141,12 +138,6 @@
<pluralform>%x Baitai</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Nepavyksta nuskaityti failo %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Nepavyksta įrašyti failo %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Duomenų bazė %x yra netinkama.</target>
@@ -156,9 +147,18 @@
<source>Database file %x does not yet exist.</source>
<target>Duomenų bazės failo %x dar nėra.</target>
+<source>Database file is corrupt:</source>
+<target></target>
+
<source>Out of memory!</source>
<target>Trūksta atminties!</target>
+<source>Cannot write file %x.</source>
+<target>Nepavyksta įrašyti failo %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Nepavyksta nuskaityti failo %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Duomenų bazės failai nesidalina bendros sesijos.</target>
@@ -211,6 +211,9 @@
<source>/sec</source>
<target>/sek.</target>
+<source>Cannot find file %x.</source>
+<target>Nepavyksta rasti failo %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Failas %x neturi tinkamų nustatymų.</target>
@@ -235,14 +238,11 @@
<source>Cannot read the following XML elements:</source>
<target>Nepavyksta perskaityti sekančių XML elementų:</target>
-<source>Cannot find file %x.</source>
-<target>Nepavyksta rasti failo %x.</target>
-
<source>&Open...</source>
<target>&Atverti...</target>
-<source>&Save...</source>
-<target>&Išsaugoti...</target>
+<source>Save &As...</source>
+<target></target>
<source>&Quit</source>
<target>&Išeiti</target>
@@ -318,8 +318,8 @@ Komanda inicijuojama jei:
<source>(Build: %x)</source>
<target>(Komponavimo versija: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync nustatymai</target>
+<source>All files</source>
+<target></target>
<source>&Restore</source>
<target>&Atstatyti</target>
@@ -333,8 +333,8 @@ Komanda inicijuojama jei:
<source>Waiting for missing directories...</source>
<target>Laikiama trūkstamų katalogų...</target>
-<source>An input folder name is empty.</source>
-<target>Įvesties aplanko pavadinimas yra tuščias.</target>
+<source>A folder input field is empty.</source>
+<target></target>
<source>Logging</source>
<target>Užduoties duomenys</target>
@@ -357,11 +357,8 @@ Komanda inicijuojama jei:
<source>Custom</source>
<target>Savitas</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync paketinės užduoties failas</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync nustatymai</target>
+<source>FreeFileSync batch</source>
+<target></target>
<source>Batch execution</source>
<target>Paketinės užduoties vykdymas</target>
@@ -399,18 +396,18 @@ Komanda inicijuojama jei:
<source>Unable to connect to sourceforge.net!</source>
<target>Nepavyksta prisijungti prie sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Naujesnė FreeFileSync versija yra pasiekiama:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target></target>
<source>Download now?</source>
<target>Atsiųsti dabar?</target>
-<source>Information</source>
-<target>Informacija</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync yra naujausia!</target>
+<source>Information</source>
+<target>Informacija</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Ar tikrai norite, kad FreeFileSync automatiškai ieškoti atnaujinimų kiekvieną savaitę?</target>
@@ -444,6 +441,12 @@ Komanda inicijuojama jei:
<source>Extension</source>
<target>Plėtinys</target>
+<source>Size:</source>
+<target></target>
+
+<source>Date:</source>
+<target></target>
+
<source>Action</source>
<target>Veiksmas</target>
@@ -477,6 +480,9 @@ Komanda inicijuojama jei:
<source>&New</source>
<target>&Naujas</target>
+<source>&Save</source>
+<target></target>
+
<source>&Language</source>
<target>&Kalba</target>
@@ -543,11 +549,8 @@ Komanda inicijuojama jei:
<source>Number of files and folders that will be deleted</source>
<target>Failų ir aplankų, kurie bus ištrinti, skaičius</target>
-<source>Total amount of data that will be transferred</source>
-<target>Visas duomenų kiekis, kuris bus perduotas</target>
-
-<source>Operation:</source>
-<target>Operacija:</target>
+<source>Total bytes to copy</source>
+<target></target>
<source>Items found:</source>
<target>Rasta elementų:</target>
@@ -555,11 +558,11 @@ Komanda inicijuojama jei:
<source>Speed:</source>
<target>Greitis:</target>
-<source>Remaining time:</source>
-<target>Likęs laikas:</target>
+<source>Time remaining:</source>
+<target></target>
-<source>Elapsed time:</source>
-<target>Praėjęs laikas:</target>
+<source>Time elapsed:</source>
+<target></target>
<source>Batch job</source>
<target>Paketinė užduotis</target>
@@ -681,6 +684,15 @@ yra toks pats
<source>Source code written in C++ utilizing:</source>
<target>Šaltinio kodas parašytas su C++ naudojant:</target>
+<source>If you like FreeFileSync</source>
+<target>Jei Jums patinka FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Paremkite per PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Didelė padėka už FreeFileSync vertimą reiškiama:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Nuomonė ir patarimai laukiami</target>
@@ -693,39 +705,9 @@ yra toks pats
<source>Email</source>
<target>El. paštas</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Didelė padėka už FreeFileSync vertimą reiškiama:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Jei Jums patinka FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Paremkite per PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Platinama su GNU General Public licenzija</target>
-<source>Ignore further errors</source>
-<target>Ignoruoti tolimesnes klaidas</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Slėpti tolimesnius klaidų pranešimus per esamą procesą</target>
-
-<source>&Ignore</source>
-<target>&Ignoruoti</target>
-
-<source>Do not show this dialog again</source>
-<target>Nerodyti šio lango daugiau</target>
-
-<source>&Switch</source>
-<target>&Perjungti</target>
-
-<source>&Yes</source>
-<target>&Taip</target>
-
-<source>&No</source>
-<target>&Ne</target>
-
<source>Use Recycle Bin</source>
<target>Naudoti šiukšliadėžę</target>
@@ -798,6 +780,9 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Statistics</source>
<target>Statistika</target>
+<source>Do not show this dialog again</source>
+<target>Nerodyti šio lango daugiau</target>
+
<source>Find what:</source>
<target>Rasti kas:</target>
@@ -876,8 +861,14 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Never save changes</source>
<target>Niekada nesaugoti pakeitimų</target>
-<source>Save changes to current configuration?</source>
-<target>Išsaugoti pakeitimus į esamus nustatymus?</target>
+<source>Do you want to save changes to %x?</source>
+<target></target>
+
+<source>Save</source>
+<target></target>
+
+<source>Don't Save</source>
+<target></target>
<source>Configuration loaded!</source>
<target>Nustatymai įkelti!</target>
@@ -972,9 +963,6 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>All directories in sync!</source>
<target>Visi katalogai sinchronizuoti!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Prašome paleisti sulyginimą prieš sinchronizavimą!</target>
-
<source>Comma separated list</source>
<target>Kableliais atksirtas sąrašas</target>
@@ -1028,6 +1016,24 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<pluralform>%x iš %y eilių rodmenyje</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignoruoti tolimesnes klaidas</target>
+
+<source>&Ignore</source>
+<target>&Ignoruoti</target>
+
+<source>&Switch</source>
+<target>&Perjungti</target>
+
+<source>Question</source>
+<target>Klausimas</target>
+
+<source>&Yes</source>
+<target>&Taip</target>
+
+<source>&No</source>
+<target>&Ne</target>
+
<source>Scanning...</source>
<target>Skenuojama...</target>
@@ -1218,6 +1224,9 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Cannot delete directory %x.</source>
<target>Nepavyksta ištrinti katalogo %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nepavyksta įrašyti atributų failui %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Nepavyksta šrašyti pakeitimo datos %x.</target>
@@ -1242,9 +1251,6 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Nepavyksta nukopijuoti simbolinės nuorodos %x į %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Nepavyksta įrašyti atributų failui %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Nepavyksta nukopijuoti failo %x į %y.</target>
@@ -1269,11 +1275,8 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>No change since last synchronization!</source>
<target>Nėra pakitimo nuo pakutinio sinchronizavimo!</target>
-<source>Filter settings have changed!</source>
-<target>Filtro nustatymai buvo pakeisti!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Failas nebuvo apdirbtas paskutinio sinchronizavimo!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target></target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Nustatomos numatytos sinchronizavimo kryptys: Seni failai bus perrašyti naujesniais failais.</target>
@@ -1401,14 +1404,14 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Updating attributes of %x</source>
<target>Atnaujinami atributai %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Tikslo aplanko pavadinimas privalo nebūti tuščias.</target>
+<source>Target folder input field must not be empty.</source>
+<target></target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Aplanko pavadinimas failų versionavimui privalo nebūti tuščias.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target></target>
-<source>Source directory %x not found.</source>
-<target>Šaltinio katalogas %x nerastas.</target>
+<source>Source folder %x not found.</source>
+<target></target>
<source>Unresolved conflicts existing!</source>
<target>Yra neišspręstų konfliktų!</target>
@@ -1425,11 +1428,11 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Not enough free disk space available in:</source>
<target>Nepakanka laisvos disko vietos:</target>
-<source>Free disk space required:</source>
-<target>Laisva disko vieta reikalinga:</target>
+<source>Required:</source>
+<target></target>
-<source>Free disk space available:</source>
-<target>Laisva disko vieta prieinama:</target>
+<source>Available:</source>
+<target></target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Šiukšliadėžė nepasiekiama sekantiems keliams! Failai bus ištrinti visam laikui išskyrus:</target>
@@ -1440,6 +1443,9 @@ Pastaba: Failų pavadinimai privalo atitikti bazinius katalogus!
<source>Processing folder pair:</source>
<target>Apdorojama aplankų pora:</target>
+<source>Target folder %x already existing.</source>
+<target></target>
+
<source>Generating database...</source>
<target>Generuojama duomenų bazė...</target>
diff --git a/BUILD/Languages/norwegian.lng b/BUILD/Languages/norwegian.lng
index 89bac192..3cf0f3d6 100644
--- a/BUILD/Languages/norwegian.lng
+++ b/BUILD/Languages/norwegian.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Om</target>
-<source>Warning</source>
-<target>Advarsel</target>
-
-<source>Question</source>
-<target>Spørsmål</target>
-
<source>Confirm</source>
<target>Bekreft</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Advarsel</target>
+
<source>Fatal Error</source>
<target>Fatal feil</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Kan ikke lese fil %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Kan ikke skrive fil %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Databasefil %x er inkompatibel.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Databasefil %x finnes ikke ennå.</target>
+<source>Database file is corrupt:</source>
+<target></target>
+
<source>Out of memory!</source>
<target>For lite minne!</target>
+<source>Cannot write file %x.</source>
+<target>Kan ikke skrive fil %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Kan ikke lese fil %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Databasefiler deler ikke en felles synkroniseringsøkt.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/sek</target>
+<source>Cannot find file %x.</source>
+<target>Kan ikke finne filen %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Filen %x inneholder ikke en gyldig innstilling.</target>
@@ -226,16 +229,13 @@
<source>Volume name %x not part of file name %y!</source>
<target>Volumnavn %x ikke del av filnavn %y!</target>
-<source>Cannot find file %x.</source>
-<target>Kan ikke finne filen %x.</target>
-
<source>Cannot read the following XML elements:</source>
<target>Kan ikke lese følgende XML-elementer:</target>
<source>&Open...</source>
<target></target>
-<source>&Save...</source>
+<source>Save &As...</source>
<target></target>
<source>&Quit</source>
@@ -308,8 +308,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(Build: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync-innstilling</target>
+<source>All files</source>
+<target></target>
<source>&Restore</source>
<target>&Gjenopprett</target>
@@ -323,7 +323,7 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>Venter på manglende mapper...</target>
-<source>An input folder name is empty.</source>
+<source>A folder input field is empty.</source>
<target></target>
<source>Logging</source>
@@ -347,11 +347,8 @@ The command is triggered if:
<source>Custom</source>
<target>Brukerdefinert</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync batch-fil</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync-innstilling</target>
+<source>FreeFileSync batch</source>
+<target></target>
<source>Batch execution</source>
<target>Batch-kjøring</target>
@@ -389,18 +386,18 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Ikke i stand til å koble til sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>En nyere versjon av FreeFileSync er tilgjengelig:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target></target>
<source>Download now?</source>
<target>Laste ned nå?</target>
-<source>Information</source>
-<target>Informasjon</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync er oppdatert!</target>
+<source>Information</source>
+<target>Informasjon</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Skal FreeFileSync automatisk se etter oppdateringer hver uke?</target>
@@ -434,6 +431,12 @@ The command is triggered if:
<source>Extension</source>
<target>Filendelse</target>
+<source>Size:</source>
+<target></target>
+
+<source>Date:</source>
+<target></target>
+
<source>Action</source>
<target>Handling</target>
@@ -467,6 +470,9 @@ The command is triggered if:
<source>&New</source>
<target>&Ny</target>
+<source>&Save</source>
+<target></target>
+
<source>&Language</source>
<target>&Språk</target>
@@ -533,11 +539,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target></target>
-<source>Total amount of data that will be transferred</source>
-<target>Totale antall data som blir overført</target>
-
-<source>Operation:</source>
-<target>Handling:</target>
+<source>Total bytes to copy</source>
+<target></target>
<source>Items found:</source>
<target>Elementer funnet:</target>
@@ -545,11 +548,11 @@ The command is triggered if:
<source>Speed:</source>
<target>Hastighet:</target>
-<source>Remaining time:</source>
-<target>Gjenstående tid:</target>
+<source>Time remaining:</source>
+<target></target>
-<source>Elapsed time:</source>
-<target>Tid gått:</target>
+<source>Time elapsed:</source>
+<target></target>
<source>Batch job</source>
<target>Batch-jobb</target>
@@ -671,6 +674,15 @@ er det samme
<source>Source code written in C++ utilizing:</source>
<target>Kildekode skrevet i C++ med hjelp fra:</target>
+<source>If you like FreeFileSync</source>
+<target>Hvis du liker FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Doner med PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Stor takk for oversettelse av FreeFileSync går til:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Tilbakemelding og forslag er velkomne</target>
@@ -683,39 +695,9 @@ er det samme
<source>Email</source>
<target>E-post</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Stor takk for oversettelse av FreeFileSync går til:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Hvis du liker FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Doner med PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Utgitt under GNU General Public Licence</target>
-<source>Ignore further errors</source>
-<target>Ignorer ytterligere feil</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Skjul ytterligere feilmeldinger under den gjeldende prosessen</target>
-
-<source>&Ignore</source>
-<target>&Ignorer</target>
-
-<source>Do not show this dialog again</source>
-<target>Ikke vis denne dialog igjen</target>
-
-<source>&Switch</source>
-<target>&Skift</target>
-
-<source>&Yes</source>
-<target>&Ja</target>
-
-<source>&No</source>
-<target>&Nei</target>
-
<source>Use Recycle Bin</source>
<target>Bruk papirkurv</target>
@@ -788,6 +770,9 @@ Merk: Filnavn må være relative til basismapper!
<source>Statistics</source>
<target>Statistikk</target>
+<source>Do not show this dialog again</source>
+<target>Ikke vis denne dialog igjen</target>
+
<source>Find what:</source>
<target>Søk hva:</target>
@@ -866,8 +851,14 @@ Merk: Filnavn må være relative til basismapper!
<source>Never save changes</source>
<target>Aldri lagre endringer</target>
-<source>Save changes to current configuration?</source>
-<target>Lagre endringer til gjeldende innstilling?</target>
+<source>Do you want to save changes to %x?</source>
+<target></target>
+
+<source>Save</source>
+<target></target>
+
+<source>Don't Save</source>
+<target></target>
<source>Configuration loaded!</source>
<target>Innstilling lastet!</target>
@@ -962,9 +953,6 @@ Merk: Filnavn må være relative til basismapper!
<source>All directories in sync!</source>
<target>Alle mapper er synkronisert!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Kjør en sammenligning før synkronisering!</target>
-
<source>Comma separated list</source>
<target>Komma-separert liste</target>
@@ -1010,6 +998,24 @@ Merk: Filnavn må være relative til basismapper!
<pluralform>%x av %y rekker</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorer ytterligere feil</target>
+
+<source>&Ignore</source>
+<target>&Ignorer</target>
+
+<source>&Switch</source>
+<target>&Skift</target>
+
+<source>Question</source>
+<target>Spørsmål</target>
+
+<source>&Yes</source>
+<target>&Ja</target>
+
+<source>&No</source>
+<target>&Nei</target>
+
<source>Scanning...</source>
<target>Skanner...</target>
@@ -1190,6 +1196,9 @@ Merk: Filnavn må være relative til basismapper!
<source>Cannot delete directory %x.</source>
<target>Kan ikke slette mappen %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Kan ikke skrive filattributter til %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Kan ikke skrive endringstid til %x.</target>
@@ -1214,9 +1223,6 @@ Merk: Filnavn må være relative til basismapper!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Kan ikke kopiere symbolsk lenke %x til %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Kan ikke skrive filattributter til %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Kan ikke kopiere filen %x til %y.</target>
@@ -1241,11 +1247,8 @@ Merk: Filnavn må være relative til basismapper!
<source>No change since last synchronization!</source>
<target>Ingen endringer siden siste synkronisering!</target>
-<source>Filter settings have changed!</source>
-<target>Filterinnstillinger er endret!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Filen ble ikke behandlet ved siste synkronisering!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target></target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Stiller inn standard synkroniseringsretning: Gamle filer blir overskrevet med nyere filer.</target>
@@ -1373,14 +1376,14 @@ Merk: Filnavn må være relative til basismapper!
<source>Updating attributes of %x</source>
<target>Oppdaterer attributter til %x</target>
-<source>Target folder name must not be empty.</source>
+<source>Target folder input field must not be empty.</source>
<target></target>
-<source>Folder name for file versioning must not be empty.</source>
+<source>Folder input field for versioning must not be empty.</source>
<target></target>
-<source>Source directory %x not found.</source>
-<target>Kildemappen %x ikke funnet.</target>
+<source>Source folder %x not found.</source>
+<target></target>
<source>Unresolved conflicts existing!</source>
<target>Uløste konflikter finnes!</target>
@@ -1397,11 +1400,11 @@ Merk: Filnavn må være relative til basismapper!
<source>Not enough free disk space available in:</source>
<target>Ikke nok ledig diskplass tilgjengelig på:</target>
-<source>Free disk space required:</source>
-<target>Ledig diskplass som kreves:</target>
+<source>Required:</source>
+<target></target>
-<source>Free disk space available:</source>
-<target>Ledig diskplass tilgjengelig:</target>
+<source>Available:</source>
+<target></target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Papirkurv er ikke tilgjengelig for de følgende baner! Filer blir isteden slettet permanent:</target>
@@ -1412,6 +1415,9 @@ Merk: Filnavn må være relative til basismapper!
<source>Processing folder pair:</source>
<target>Behandler mappepar:</target>
+<source>Target folder %x already existing.</source>
+<target></target>
+
<source>Generating database...</source>
<target>Oppretter database...</target>
diff --git a/BUILD/Languages/polish.lng b/BUILD/Languages/polish.lng
index 255cd2ab..08b5366c 100644
--- a/BUILD/Languages/polish.lng
+++ b/BUILD/Languages/polish.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Wyszukiwanie katalogu %x...</target>
+<source>Batch execution</source>
+<target>Uruchomienie pliku wsadowego</target>
+
+<source>Items processed:</source>
+<target>Przetworzeone elementy:</target>
+
+<source>Items remaining:</source>
+<target>Pozostałe elementy:</target>
+
+<source>Total time:</source>
+<target>Całkowity czas:</target>
+
<source>Show in Explorer</source>
<target>Wyświetl w Explorerze</target>
@@ -32,7 +44,7 @@
<target>Określ alternatywne ustawienia porównywania</target>
<source>Select alternate synchronization settings</source>
-<target>Stwórz alternatywne reguły synchronizacji</target>
+<target>Określ alternatywne reguły synchronizacji</target>
<source>Filter is active</source>
<target>Filtr jest aktywny</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>O Programie</target>
-<source>Warning</source>
-<target>Ostrzeżenie</target>
-
-<source>Question</source>
-<target>Pytanie</target>
-
<source>Confirm</source>
<target>Potwierdź</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Ostrzeżenie</target>
+
<source>Fatal Error</source>
<target>Błąd krytyczny</target>
@@ -140,12 +149,6 @@
<pluralform>%x Bajtów</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Nie można odczytać pliku %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Nie można zapisać pliku %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Plika bazy danych %x nie jest kompatybilny.</target>
@@ -155,9 +158,18 @@
<source>Database file %x does not yet exist.</source>
<target>Plik bazy danych %x nie istnieje.</target>
+<source>Database file is corrupt:</source>
+<target>Plik bazy danych jest uszkodzony:</target>
+
<source>Out of memory!</source>
<target>Brak wolnej pamięci!</target>
+<source>Cannot write file %x.</source>
+<target>Nie można zapisać pliku %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Nie można odczytać pliku %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Pliki bazy danych nie współdzielą sesji.</target>
@@ -208,6 +220,9 @@
<source>/sec</source>
<target>/sekundę</target>
+<source>Cannot find file %x.</source>
+<target>Nie można znaleźć pliku %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Plik %x nie zawiera prawidłowej konfiguracji</target>
@@ -232,14 +247,11 @@
<source>Cannot read the following XML elements:</source>
<target>Nie można odczytać elementu XML:</target>
-<source>Cannot find file %x.</source>
-<target>Nie można znaleźć pliku %x.</target>
-
<source>&Open...</source>
<target>&Otwórz...</target>
-<source>&Save...</source>
-<target>&Zapisz</target>
+<source>Save &As...</source>
+<target>Zapi&sz jako...</target>
<source>&Quit</source>
<target>&Zamknij</target>
@@ -248,13 +260,13 @@
<target>&Program</target>
<source>&Content</source>
-<target>&Zawartość</target>
+<target>Za&wartość</target>
<source>&About</source>
-<target>&O Programie</target>
+<target>O Program&ie</target>
<source>&Help</source>
-<target>&Pomoc</target>
+<target>P&omoc</target>
<source>Usage:</source>
<target>Użycie:</target>
@@ -269,19 +281,19 @@
<target>3. Wciśnij 'Start'.</target>
<source>To get started just import a .ffs_batch file.</source>
-<target>Aby rozpocząć po prostu zaimportuj plik .ffs_batch</target>
+<target>Aby rozpocząć po zaimportuj plik .ffs_batch.</target>
<source>Folders to watch</source>
<target>Obserwowane katalogi</target>
<source>Add folder</source>
-<target>Dodaj folder</target>
+<target>Dodaj katalog</target>
<source>Remove folder</source>
-<target>Usuń folder</target>
+<target>Usuń katalog</target>
<source>Select a folder</source>
-<target>Wybierz folder</target>
+<target>Wybierz katalog</target>
<source>Delay [seconds]</source>
<target>Opóźnienie [sekundy]</target>
@@ -315,8 +327,8 @@ Komenda jest wykonywana gdy:
<source>(Build: %x)</source>
<target>(Zbudowano: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Konfiguracja RealtimeSync</target>
+<source>All files</source>
+<target>Wszystkie pliki</target>
<source>&Restore</source>
<target>&Przywróć</target>
@@ -330,8 +342,8 @@ Komenda jest wykonywana gdy:
<source>Waiting for missing directories...</source>
<target>Oczekiwanie na brakujące katalogi...</target>
-<source>An input folder name is empty.</source>
-<target>Nazwa katalogu jest pusta.</target>
+<source>A folder input field is empty.</source>
+<target>Pole katalog źródłowy jest puste.</target>
<source>Logging</source>
<target>Tworzenie logów</target>
@@ -354,32 +366,14 @@ Komenda jest wykonywana gdy:
<source>Custom</source>
<target>Własne</target>
-<source>FreeFileSync batch file</source>
+<source>FreeFileSync batch</source>
<target>Plik wsadowy FreeFileSync</target>
-<source>FreeFileSync configuration</source>
-<target>Konfiguracja FreeFileSync</target>
-
-<source>Batch execution</source>
-<target>Uruchomienie pliku wsadowego</target>
-
-<source>Items processed:</source>
-<target>Przetworzeone elementy:</target>
-
-<source>Items remaining:</source>
-<target>Pozostałe elementy:</target>
-
-<source>Total time:</source>
-<target>Całkowity czas:</target>
-
-<source>Stop</source>
-<target>Zatrzymaj</target>
-
<source>Synchronization aborted!</source>
<target>Synchronizacja przerwana!</target>
<source>Synchronization completed with errors!</source>
-<target>Synchronizacja zakończona z błędami.</target>
+<target>Synchronizacja zakończona z błędami!</target>
<source>Nothing to synchronize!</source>
<target>Brak plików do synchronizacji!</target>
@@ -388,7 +382,7 @@ Komenda jest wykonywana gdy:
<target>Synchronizacja zakończona pomyślnie!</target>
<source>Press "Switch" to resolve issues in FreeFileSync main dialog.</source>
-<target>Wciśnij "Przełącz" aby rozwiązać wszystkie problemy w głównym oknie FreeFileSync.</target>
+<target>Kliknij "Przełącz" aby rozwiązać wszystkie problemy w głównym oknie FreeFileSync.</target>
<source>Switching to FreeFileSync main dialog...</source>
<target>Przełączanie do głównego okna FreeFileSync...</target>
@@ -396,20 +390,20 @@ Komenda jest wykonywana gdy:
<source>Unable to connect to sourceforge.net!</source>
<target>Nie można się połączyć z sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Dostępna jest nowa wersja FreeFileSync:</target>
<source>Download now?</source>
<target>Pobrać teraz?</target>
-<source>Information</source>
-<target>Informacja</target>
-
<source>FreeFileSync is up to date!</source>
<target>Posiadasz aktualną wersję FreeFileSync!</target>
+<source>Information</source>
+<target>Informacja</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
-<target>Czy chcesz aby FreeFileSync sprawdzał uaktualnienia co tydzień?</target>
+<target>Czy chcesz aby FreeFileSync sprawdzał aktualizacje co tydzień?</target>
<source>(Requires an Internet connection!)</source>
<target>(Wymaga połączenia z Internetem!)</target>
@@ -441,6 +435,12 @@ Komenda jest wykonywana gdy:
<source>Extension</source>
<target>Rozszerzenie</target>
+<source>Size:</source>
+<target>Rozmiar:</target>
+
+<source>Date:</source>
+<target>Data:</target>
+
<source>Action</source>
<target>Akcja</target>
@@ -474,6 +474,9 @@ Komenda jest wykonywana gdy:
<source>&New</source>
<target>&Nowy</target>
+<source>&Save</source>
+<target>&Zapisz</target>
+
<source>&Language</source>
<target>&Język</target>
@@ -508,10 +511,10 @@ Komenda jest wykonywana gdy:
<target>Rozpocznij synchronizację</target>
<source>Add folder pair</source>
-<target>Dodaj foldery do porównania</target>
+<target>Dodaj katalogi do porównania</target>
<source>Remove folder pair</source>
-<target>Usuń parę folderów</target>
+<target>Usuń katalogi</target>
<source>Swap sides</source>
<target>Zamień stronami</target>
@@ -520,7 +523,7 @@ Komenda jest wykonywana gdy:
<target>Wczytaj konfigurację z pliku</target>
<source>Save current configuration to file</source>
-<target>Zapisz aktualny plik konfiguracyjny</target>
+<target>Zapisz konfiguracyję do pliku</target>
<source>Last used configurations (press DEL to remove from list)</source>
<target>Ostatnio użyta konfiguracja (naciśnij DEL żeby usunąć z listy)</target>
@@ -540,11 +543,8 @@ Komenda jest wykonywana gdy:
<source>Number of files and folders that will be deleted</source>
<target>Liczba plików i katalogów, które zostaną usunięte</target>
-<source>Total amount of data that will be transferred</source>
-<target>Liczba danych do przekopiowania</target>
-
-<source>Operation:</source>
-<target>Operacja:</target>
+<source>Total bytes to copy</source>
+<target>Całkowity rozmiar do skopiowania</target>
<source>Items found:</source>
<target>Znalezione elementy:</target>
@@ -552,17 +552,17 @@ Komenda jest wykonywana gdy:
<source>Speed:</source>
<target>Prędkość:</target>
-<source>Remaining time:</source>
-<target>Pozostały czas:</target>
+<source>Time remaining:</source>
+<target>Do ukończenia:</target>
-<source>Elapsed time:</source>
-<target>Czas:</target>
+<source>Time elapsed:</source>
+<target>Szacowany czas:</target>
<source>Batch job</source>
<target>Plik wsadowy</target>
<source>Create a batch file to automate synchronization. Double-click this file or schedule in your system's task planner: FreeFileSync.exe <job name>.ffs_batch</source>
-<target>Utwórz plik wsadowy aby zautomatyzować proces synchronizacji. Kliknij dwa razy na ten plik lub dodaj go do menadżera zadań w swoim systemie: FreeFileSync.exe <nazwa_pliku>.ffs_batch</target>
+<target>Utwórz plik wsadowy aby zautomatyzować proces synchronizacji. Kliknij dwa razy na ten plik lub dodaj go do menadżera zadań w Twoim systemie: FreeFileSync.exe <nazwa_pliku>.ffs_batch</target>
<source>Help</source>
<target>Pomoc</target>
@@ -577,7 +577,7 @@ Komenda jest wykonywana gdy:
<target>Prawy</target>
<source>Status feedback</source>
-<target>Opinia statusu</target>
+<target>Status</target>
<source>Show progress dialog</source>
<target>Pokaż okno postępu</target>
@@ -607,7 +607,7 @@ Komenda jest wykonywana gdy:
<target>Kopiuj nowe lub aktualniejsze pliki na prawą stronę.</target>
<source>Configure your own synchronization rules.</source>
-<target>Skonfiguruj swoje własne zasady synchronizacji.</target>
+<target>Skonfiguruj swoje własne reguły synchronizacji.</target>
<source>Deletion handling</source>
<target>Obsługa usuwania</target>
@@ -650,8 +650,8 @@ are the same
</source>
<target>
Pliki są równe jeżeli
- - ostatni czas zapisu
- - rozmiar pliku
+ - ostatni czas zapisu
+ - rozmiar pliku
są równe
</target>
@@ -678,6 +678,15 @@ jest identyczna
<source>Source code written in C++ utilizing:</source>
<target>Kod stworzony w C++ z wykorzystaniem:</target>
+<source>If you like FreeFileSync</source>
+<target>Podoba Ci się FreeFileSync?</target>
+
+<source>Donate with PayPal</source>
+<target>Wesprzyj z PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Podziękowania za tłumaczenie FreeFileSync:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Wszelkie opinie i sugestie mile widziane</target>
@@ -690,39 +699,9 @@ jest identyczna
<source>Email</source>
<target>Poczta</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Podziękowania za tłumaczenie FreeFileSync:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Podoba Ci się FreeFileSync?</target>
-
-<source>Donate with PayPal</source>
-<target>Wesprzyj z PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Udostępnione na zasadach licencji GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Ignoruj kolejne błędy</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Ukryj kolejne informacje o błędach dla tego zadania</target>
-
-<source>&Ignore</source>
-<target>&Ignoruj</target>
-
-<source>Do not show this dialog again</source>
-<target>Nie pokazuj tego okna ponownie</target>
-
-<source>&Switch</source>
-<target>&Zamień</target>
-
-<source>&Yes</source>
-<target>&Tak</target>
-
-<source>&No</source>
-<target>&Nie</target>
-
<source>Use Recycle Bin</source>
<target>Użyj kosza</target>
@@ -772,7 +751,7 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<target>Kopiuj zablokowane pliki</target>
<source>Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)</source>
-<target>Kopiuj pliki udostępnione i zablokowane używając usługi Volume Shadow Copy (Wymaga uprawnień administratora)</target>
+<target>Kopiuj udostępnione lub zablokowane pliki używając usługi Volume Shadow Copy (Wymaga uprawnień administratora)</target>
<source>Copy file access permissions</source>
<target>Kopiuj uprawnienia plików</target>
@@ -795,6 +774,9 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Statistics</source>
<target>Statystyki</target>
+<source>Do not show this dialog again</source>
+<target>Nie pokazuj tego okna ponownie</target>
+
<source>Find what:</source>
<target>Co:</target>
@@ -873,8 +855,14 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Never save changes</source>
<target>Nigdy nie zapisuj zmian</target>
-<source>Save changes to current configuration?</source>
-<target>Zapisać zmiany obecnej konfiguracji?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Czy chcesz zapisać zmiany w %x?</target>
+
+<source>Save</source>
+<target>Zapisz</target>
+
+<source>Don't Save</source>
+<target>Nie zapisuj</target>
<source>Configuration loaded!</source>
<target>Konfiguracja wczytana!</target>
@@ -969,9 +957,6 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>All directories in sync!</source>
<target>Wszystkie katalogi zsynchronizowane!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Przed synchronizacją należy uruchomić Porównaj!</target>
-
<source>Comma separated list</source>
<target>Lista oddzielona przecinkami</target>
@@ -1021,6 +1006,24 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<pluralform>%x z %y rzędów w widoku</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignoruj kolejne błędy</target>
+
+<source>&Ignore</source>
+<target>&Ignoruj</target>
+
+<source>&Switch</source>
+<target>&Zamień</target>
+
+<source>Question</source>
+<target>Pytanie</target>
+
+<source>&Yes</source>
+<target>&Tak</target>
+
+<source>&No</source>
+<target>&Nie</target>
+
<source>Scanning...</source>
<target>Skanowanie...</target>
@@ -1206,6 +1209,9 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Cannot delete directory %x.</source>
<target>Nie można usunąć katalogu %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nie można zapisać atrybutów %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Nie można zapisać czasu modyfikacji %x.</target>
@@ -1230,9 +1236,6 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Cannot copy symbolic link %x to %y.</source>
<target>Nie można skopiować dowiązania symbolicznego %x do %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Nie można zapisać atrybutów %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Nie można skopiować pliku %x do %y.</target>
@@ -1257,11 +1260,8 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>No change since last synchronization!</source>
<target>Brak zmian od ostatniej synchronizacji!</target>
-<source>Filter settings have changed!</source>
-<target>Ustawienia filtra uległy zmianie!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Plik nie został przetworzony podczas ostatniej synchronizacji!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Zgodnie z obecnymi ustawieniami, poszczególne wpisy w bazie danych nie są zsynchronizowane.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Ustawianie domyślnego kierunku synchronizacji: Stare pliki zostaną nadpisane nowszymi.</target>
@@ -1330,7 +1330,7 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<target>Nadpisz prawy element</target>
<source>Do nothing</source>
-<target>Nic nie rób</target>
+<target>Nie rób nic</target>
<source>Update attributes on left</source>
<target>Aktualizuj atrybuty po lewej stronie</target>
@@ -1389,14 +1389,14 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Updating attributes of %x</source>
<target>Aktualizowanie atrybutów %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Katalog docelowy nie może być pusty.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Pole katalog docelowy nie może być puste.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Nazwa katalogu do wersjonowania plików nie może być pusta.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Pole katalog źródłowy nie może być puste.</target>
-<source>Source directory %x not found.</source>
-<target>Katalog źródłowy %x nie istnieje.</target>
+<source>Source folder %x not found.</source>
+<target>Nie znaleziono katalogu docelowego %x.</target>
<source>Unresolved conflicts existing!</source>
<target>Istnieją nierozwiązane konflikty!</target>
@@ -1413,11 +1413,11 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Not enough free disk space available in:</source>
<target>Brak wystarczającej przestrzeni dyskowej na:</target>
-<source>Free disk space required:</source>
-<target>Wymagane wolne miejsce:</target>
+<source>Required:</source>
+<target>Wymagane:</target>
-<source>Free disk space available:</source>
-<target>Wolne miejsce:</target>
+<source>Available:</source>
+<target>Dostępne:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Kosz nie jest dostępny dla określonych ścieżek! Pliki zostaną nieodwracalnie usuniętę:</target>
@@ -1428,6 +1428,9 @@ Uwaga: Nazwy plików muszą być podane jako relatywne względem katalogu bazowe
<source>Processing folder pair:</source>
<target>Przetwarzanie folderów:</target>
+<source>Target folder %x already existing.</source>
+<target>Katalog docelowy %x już istnieje.</target>
+
<source>Generating database...</source>
<target>Generowanie bazy danych...</target>
diff --git a/BUILD/Languages/portuguese.lng b/BUILD/Languages/portuguese.lng
index 70530ccb..b75ffb70 100644
--- a/BUILD/Languages/portuguese.lng
+++ b/BUILD/Languages/portuguese.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Sobre</target>
-<source>Warning</source>
-<target>Atenção</target>
-
-<source>Question</source>
-<target>Questão</target>
-
<source>Confirm</source>
<target>Confirmar</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Atenção</target>
+
<source>Fatal Error</source>
<target>Erro crítico</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Não é possível ler o ficheiro %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Não é possível escrever o ficheiro %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Base de dados %x não é compatível.</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Base de dados %x não existe.</target>
+<source>Database file is corrupt:</source>
+<target></target>
+
<source>Out of memory!</source>
<target>Sem memória disponível!</target>
+<source>Cannot write file %x.</source>
+<target>Não é possível escrever o ficheiro %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Não é possível ler o ficheiro %x.</target>
+
<source>Database files do not share a common session.</source>
<target>As bases de dados são de sessões diferentes.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/seg</target>
+<source>Cannot find file %x.</source>
+<target>Não é possível encontrar o ficheiro %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Ficheiro %x não tem uma configuração válida.</target>
@@ -229,14 +232,11 @@
<source>Cannot read the following XML elements:</source>
<target>Não é possível ler os elementos XML:</target>
-<source>Cannot find file %x.</source>
-<target>Não é possível encontrar o ficheiro %x.</target>
-
<source>&Open...</source>
<target>&Abrir...</target>
-<source>&Save...</source>
-<target>&Guardar...</target>
+<source>Save &As...</source>
+<target></target>
<source>&Quit</source>
<target>S&air</target>
@@ -312,8 +312,8 @@ O comando é executado se:
<source>(Build: %x)</source>
<target>(Build: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Configuração do RealtimeSync</target>
+<source>All files</source>
+<target></target>
<source>&Restore</source>
<target>&Restaurar</target>
@@ -327,8 +327,8 @@ O comando é executado se:
<source>Waiting for missing directories...</source>
<target>A aguardar pelos directórios em falta...</target>
-<source>An input folder name is empty.</source>
-<target>Um dos campos de comparação está vazio.</target>
+<source>A folder input field is empty.</source>
+<target></target>
<source>Logging</source>
<target>A escrever em log</target>
@@ -351,11 +351,8 @@ O comando é executado se:
<source>Custom</source>
<target>Personalizado</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync ficheiro batch</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync configuração</target>
+<source>FreeFileSync batch</source>
+<target></target>
<source>Batch execution</source>
<target>Execução do batch</target>
@@ -393,18 +390,18 @@ O comando é executado se:
<source>Unable to connect to sourceforge.net!</source>
<target>Não é possível ligar a sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Mais recente versão do FreeFileSync disponível:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target></target>
<source>Download now?</source>
<target>Fazer download agora?</target>
-<source>Information</source>
-<target>Informação</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync está actualizado!</target>
+<source>Information</source>
+<target>Informação</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Deseja que o FreeFileSync procure automaticamente actualizações todas as semanas?</target>
@@ -438,6 +435,12 @@ O comando é executado se:
<source>Extension</source>
<target>Extensão</target>
+<source>Size:</source>
+<target></target>
+
+<source>Date:</source>
+<target></target>
+
<source>Action</source>
<target>Ação</target>
@@ -471,6 +474,9 @@ O comando é executado se:
<source>&New</source>
<target>&Novo</target>
+<source>&Save</source>
+<target></target>
+
<source>&Language</source>
<target>&Língua</target>
@@ -537,11 +543,8 @@ O comando é executado se:
<source>Number of files and folders that will be deleted</source>
<target>Número de ficheiros e pastas a ser eliminados</target>
-<source>Total amount of data that will be transferred</source>
-<target>Volume de dados a ser transferido</target>
-
-<source>Operation:</source>
-<target>Operação:</target>
+<source>Total bytes to copy</source>
+<target></target>
<source>Items found:</source>
<target>Elementos encontrados:</target>
@@ -549,11 +552,11 @@ O comando é executado se:
<source>Speed:</source>
<target>Velocidade:</target>
-<source>Remaining time:</source>
-<target>Tempo restante:</target>
+<source>Time remaining:</source>
+<target></target>
-<source>Elapsed time:</source>
-<target>Tempo passado:</target>
+<source>Time elapsed:</source>
+<target></target>
<source>Batch job</source>
<target>Ficheiro Batch</target>
@@ -674,6 +677,15 @@ Os ficheiros são considerados iguais se
<source>Source code written in C++ utilizing:</source>
<target>Código fonte escrito em C++ utilizando:</target>
+<source>If you like FreeFileSync</source>
+<target>Se gosta do FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Doar usando PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Pela tradução de FreeFileSync, um agradecimento a:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Comentários e sugestões são apreciados</target>
@@ -686,39 +698,9 @@ Os ficheiros são considerados iguais se
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Pela tradução de FreeFileSync, um agradecimento a:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Se gosta do FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Doar usando PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Publicado sobre GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Ignorar próximos erros</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Ocultar próximas mensagens de erro durante este processo</target>
-
-<source>&Ignore</source>
-<target>&Ignorar</target>
-
-<source>Do not show this dialog again</source>
-<target>Não mostrar este diálogo novamente</target>
-
-<source>&Switch</source>
-<target>&Trocar</target>
-
-<source>&Yes</source>
-<target>&Sim</target>
-
-<source>&No</source>
-<target>&Não</target>
-
<source>Use Recycle Bin</source>
<target>Utilizar Reciclagem</target>
@@ -791,6 +773,9 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Statistics</source>
<target>Estatísticas</target>
+<source>Do not show this dialog again</source>
+<target>Não mostrar este diálogo novamente</target>
+
<source>Find what:</source>
<target>Procurar:</target>
@@ -869,8 +854,14 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Never save changes</source>
<target>Nunca guardar alterações</target>
-<source>Save changes to current configuration?</source>
-<target>Guardar alterações à configuração?</target>
+<source>Do you want to save changes to %x?</source>
+<target></target>
+
+<source>Save</source>
+<target></target>
+
+<source>Don't Save</source>
+<target></target>
<source>Configuration loaded!</source>
<target>Configuração carregada!</target>
@@ -965,9 +956,6 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>All directories in sync!</source>
<target>Todas as pastas sincronizadas!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Use Comparar antes da primeira sincronização!</target>
-
<source>Comma separated list</source>
<target>Lista de itens separados por vírgulas</target>
@@ -1013,6 +1001,24 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<pluralform>%x de %y linhas em vista</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorar próximos erros</target>
+
+<source>&Ignore</source>
+<target>&Ignorar</target>
+
+<source>&Switch</source>
+<target>&Trocar</target>
+
+<source>Question</source>
+<target>Questão</target>
+
+<source>&Yes</source>
+<target>&Sim</target>
+
+<source>&No</source>
+<target>&Não</target>
+
<source>Scanning...</source>
<target>A pesquisar...</target>
@@ -1193,6 +1199,9 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Cannot delete directory %x.</source>
<target>Não é possível eliminar o directório %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Não é possível escrever os atributos de %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Não é possível alterar a data de modificação a %x.</target>
@@ -1217,9 +1226,6 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Não é possível copiar o link simbólico %x para %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Não é possível escrever os atributos de %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Não é possível copiar o ficheiro %x para %y.</target>
@@ -1244,11 +1250,8 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>No change since last synchronization!</source>
<target>Não há alterações desde a última sincronização!</target>
-<source>Filter settings have changed!</source>
-<target>Opções de filtro alteradas!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>O ficheiro não foi processado na última sincronização!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target></target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Escolher direcção de sincronização por defeito: Os ficheiros antigos serão substituídos pelos novos.</target>
@@ -1376,14 +1379,14 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Updating attributes of %x</source>
<target>Actualizar atributos de %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Nome da pasta de destino não pode estar vazio.</target>
+<source>Target folder input field must not be empty.</source>
+<target></target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Nome da pasta para manter versões não pode estar vazio.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target></target>
-<source>Source directory %x not found.</source>
-<target>Directório fonte %x não encontrado.</target>
+<source>Source folder %x not found.</source>
+<target></target>
<source>Unresolved conflicts existing!</source>
<target>Existem conflitos por resolver!</target>
@@ -1400,11 +1403,11 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Not enough free disk space available in:</source>
<target>Não há espaço livre suficiente em:</target>
-<source>Free disk space required:</source>
-<target>Espaço livre necessário em disco:</target>
+<source>Required:</source>
+<target></target>
-<source>Free disk space available:</source>
-<target>Espaço livre disponível em disco:</target>
+<source>Available:</source>
+<target></target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Reciclagem não disponível para os seguintes caminhos! Os ficheiros serão apagados permanentemente:</target>
@@ -1415,6 +1418,9 @@ Nota: Nome dos ficheiros tem que ser relativo aos diretórios base!
<source>Processing folder pair:</source>
<target>A processar o par do directorio:</target>
+<source>Target folder %x already existing.</source>
+<target></target>
+
<source>Generating database...</source>
<target>A gerar base de dados...</target>
diff --git a/BUILD/Languages/portuguese_br.lng b/BUILD/Languages/portuguese_br.lng
index a6e83355..6a7f1332 100644
--- a/BUILD/Languages/portuguese_br.lng
+++ b/BUILD/Languages/portuguese_br.lng
@@ -1,5 +1,5 @@
<header>
- <language name>Português do Brasil</language name>
+ <language name>Português (BR)</language name>
<translator>Edison Aranha</translator>
<locale>pt_BR</locale>
<flag file>brazil.png</flag file>
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Buscando pela pasta %x...</target>
+<source>Batch execution</source>
+<target>Execução da tarefa em lote</target>
+
+<source>Items processed:</source>
+<target>Elementos processados:</target>
+
+<source>Items remaining:</source>
+<target>Elementos restantes:</target>
+
+<source>Total time:</source>
+<target>Tempo total:</target>
+
<source>Show in Explorer</source>
<target>Mostrar no Explorer</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>Sobre</target>
-<source>Warning</source>
-<target>Avisos</target>
-
-<source>Question</source>
-<target>Questão</target>
-
<source>Confirm</source>
<target>Confirmar</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Informações</target>
+<source>Warning</source>
+<target>Avisos</target>
+
<source>Fatal Error</source>
<target>Erro fatal</target>
@@ -139,12 +148,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Não foi possível ler o arquivo %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Não foi possível escrever o arquivo %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>O arquivo de banco de dados %x é incompatível.</target>
@@ -154,9 +157,18 @@
<source>Database file %x does not yet exist.</source>
<target>O arquivo de banco de dados %x ainda não existe.</target>
+<source>Database file is corrupt:</source>
+<target>O arquivo de banco de dados está corrompido</target>
+
<source>Out of memory!</source>
<target>Falta de memória!</target>
+<source>Cannot write file %x.</source>
+<target>Não foi possível escrever o arquivo %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Não foi possível ler o arquivo %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Os arquivos de banco de dados são de sessões diferentes.</target>
@@ -205,6 +217,9 @@
<source>/sec</source>
<target>/seg</target>
+<source>Cannot find file %x.</source>
+<target>Não foi possível encontrar o aquivo %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>O arquivo %x não contém uma configuração válida.</target>
@@ -226,17 +241,14 @@
<source>Volume name %x not part of file name %y!</source>
<target>Nome do volume %x não é parte do arquivo %y!</target>
-<source>Cannot find file %x.</source>
-<target>Não foi possível encontrar o aquivo %x.</target>
-
<source>Cannot read the following XML elements:</source>
<target>Não foi possível ler os seguintes elementos XML:</target>
<source>&Open...</source>
<target>&Abrir...</target>
-<source>&Save...</source>
-<target>&Salvar...</target>
+<source>Save &As...</source>
+<target>Salvar &Como...</target>
<source>&Quit</source>
<target>Sai&r</target>
@@ -312,8 +324,8 @@ O comando é disparado se:
<source>(Build: %x)</source>
<target>(Versão: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Configuração do RealtimeSync</target>
+<source>All files</source>
+<target>Todos os arquivos</target>
<source>&Restore</source>
<target>&Restaurar</target>
@@ -327,8 +339,8 @@ O comando é disparado se:
<source>Waiting for missing directories...</source>
<target>Esperando por diretórios faltantes...</target>
-<source>An input folder name is empty.</source>
-<target>Um nome de pasta de entrada está em branco.</target>
+<source>A folder input field is empty.</source>
+<target>Um campo de entrada de pasta está vazio.</target>
<source>Logging</source>
<target>Ver Log</target>
@@ -351,26 +363,8 @@ O comando é disparado se:
<source>Custom</source>
<target>Personalizado</target>
-<source>FreeFileSync batch file</source>
-<target>Arquivo de lote do FreeFileSync</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync configuração</target>
-
-<source>Batch execution</source>
-<target>Execução da tarefa em lote</target>
-
-<source>Items processed:</source>
-<target>Elementos processados:</target>
-
-<source>Items remaining:</source>
-<target>Elementos restantes:</target>
-
-<source>Total time:</source>
-<target>Tempo total:</target>
-
-<source>Stop</source>
-<target>Parar</target>
+<source>FreeFileSync batch</source>
+<target>Tarefa em lote do FreeFileSync</target>
<source>Synchronization aborted!</source>
<target>Sincronização cancelada!</target>
@@ -393,18 +387,18 @@ O comando é disparado se:
<source>Unable to connect to sourceforge.net!</source>
<target>Não foi possível conectar a sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Uma nova versão do FreeFileSync está disponível:</target>
<source>Download now?</source>
<target>Baixar agora?</target>
-<source>Information</source>
-<target>Informação</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync está atualizado!</target>
+<source>Information</source>
+<target>Informação</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Deseja que o FreeFileSync procure automaticamente novas versões todas as semanas?</target>
@@ -438,6 +432,12 @@ O comando é disparado se:
<source>Extension</source>
<target>Extensão</target>
+<source>Size:</source>
+<target>Tamanho:</target>
+
+<source>Date:</source>
+<target>Data:</target>
+
<source>Action</source>
<target>Ação</target>
@@ -463,7 +463,7 @@ O comando é disparado se:
<target>Hibernar</target>
<source>1. &Compare</source>
-<target>1. &Comparar</target>
+<target>1. C&omparar</target>
<source>2. &Synchronize</source>
<target>2. S&incronizar</target>
@@ -471,6 +471,9 @@ O comando é disparado se:
<source>&New</source>
<target>&Novo</target>
+<source>&Save</source>
+<target>&Salvar</target>
+
<source>&Language</source>
<target>&Idioma</target>
@@ -537,11 +540,8 @@ O comando é disparado se:
<source>Number of files and folders that will be deleted</source>
<target>Número de arquivos e pastas que serão apagados</target>
-<source>Total amount of data that will be transferred</source>
-<target>Volume total de dados que será transferido</target>
-
-<source>Operation:</source>
-<target>Operação:</target>
+<source>Total bytes to copy</source>
+<target>Bytes totais a serem copiados</target>
<source>Items found:</source>
<target>Elementos encontrados:</target>
@@ -549,10 +549,10 @@ O comando é disparado se:
<source>Speed:</source>
<target>Velocidade:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Tempo restante:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Tempo decorrido:</target>
<source>Batch job</source>
@@ -675,6 +675,15 @@ Os arquivos são considerados iguais se
<source>Source code written in C++ utilizing:</source>
<target>Código-fonte escrito em C++ utilizando:</target>
+<source>If you like FreeFileSync</source>
+<target>Se você gosta do FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Doar usando PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Pela tradução do FreeFileSync, um agradecimento a:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Críticas e sugestões são bem-vindas</target>
@@ -687,39 +696,9 @@ Os arquivos são considerados iguais se
<source>Email</source>
<target>E-mail</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Pela tradução do FreeFileSync, um agradecimento a:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Se você gosta do FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Doar usando PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Publicado sobre a GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Ignorar erros subsequentes</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Ocultar próximas mensagens de erro durante este processo</target>
-
-<source>&Ignore</source>
-<target>&Ignorar</target>
-
-<source>Do not show this dialog again</source>
-<target>Não mostrar este diálogo novamente</target>
-
-<source>&Switch</source>
-<target>&Alterar</target>
-
-<source>&Yes</source>
-<target>&Sim</target>
-
-<source>&No</source>
-<target>&Não</target>
-
<source>Use Recycle Bin</source>
<target>Utilizar Lixeira</target>
@@ -760,7 +739,7 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<target>&Config. Padrão</target>
<source>Fail-safe file copy</source>
-<target>Cópia de arquivos a prova de falha</target>
+<target>Cópia de arquivos a prova de falhas</target>
<source>Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error.</source>
<target>Escreve para um arquivo temporário primeiro (*.ffs_tmp) e depois o renomeia. Isto garante um estado consistente mesmo em caso de erro fatal.</target>
@@ -792,6 +771,9 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Statistics</source>
<target>Estatísticas</target>
+<source>Do not show this dialog again</source>
+<target>Não mostrar este diálogo novamente</target>
+
<source>Find what:</source>
<target>Localizar o que:</target>
@@ -870,8 +852,14 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Never save changes</source>
<target>Nunca salvar alterações</target>
-<source>Save changes to current configuration?</source>
-<target>Salvar modificações para a configuração atual?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Gostaria de salvar as alterações para %x?</target>
+
+<source>Save</source>
+<target>Salvar</target>
+
+<source>Don't Save</source>
+<target>Não Salvar</target>
<source>Configuration loaded!</source>
<target>Configuração carregada!</target>
@@ -966,9 +954,6 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>All directories in sync!</source>
<target>Todos os diretórios em sincronismo!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Por favor execute primeiro a Comparação antes de sincronizar!</target>
-
<source>Comma separated list</source>
<target>Lista de itens separados por vírgulas</target>
@@ -1014,6 +999,24 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<pluralform>%x de %y linhas</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorar erros subsequentes</target>
+
+<source>&Ignore</source>
+<target>&Ignorar</target>
+
+<source>&Switch</source>
+<target>&Alterar</target>
+
+<source>Question</source>
+<target>Questão</target>
+
+<source>&Yes</source>
+<target>&Sim</target>
+
+<source>&No</source>
+<target>&Não</target>
+
<source>Scanning...</source>
<target>Pesquisando...</target>
@@ -1194,6 +1197,9 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Cannot delete directory %x.</source>
<target>Não foi possível excluir o diretório %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Não foi possível escrever os atributos de arquivo de %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Não foi possível escrever a data de modificação de %x.</target>
@@ -1218,9 +1224,6 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Não foi possível copiar o link simbólico %x para %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Não foi possível escrever os atributos de arquivo de %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Não foi possível copiar o arquivo %x para %y.</target>
@@ -1245,11 +1248,8 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>No change since last synchronization!</source>
<target>Nenhuma mudança desde a última sincronização!</target>
-<source>Filter settings have changed!</source>
-<target>As configurações do filtro foram alteradas!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>O arquivo não foi processado pela última sincronização!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>As entradas de banco de dados correspondentes não estão em sincronia considerando as configurações atuais.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Configurando direções padrões de sincronização: Arquivos antigos serão substituídos por arquivos mais novos.</target>
@@ -1315,7 +1315,7 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<target>Sobrescrever item à esquerda</target>
<source>Overwrite right item</source>
-<target>Sobrescrever item à esquerda</target>
+<target>Sobrescrever item à direita</target>
<source>Do nothing</source>
<target>Não fazer nada</target>
@@ -1377,14 +1377,14 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Updating attributes of %x</source>
<target>Atualizando atributos de %x</target>
-<source>Target folder name must not be empty.</source>
-<target>O nome da pasta de destino não pode estar em branco.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Campo de entrada da pasta de destino não pode ficar vazio.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>O nome da pasta para o controle de versões não pode estar em branco.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Campo de entrada da pasta para controle de versão não pode ficar vazio.</target>
-<source>Source directory %x not found.</source>
-<target>O diretório de origem %x não foi encontrado.</target>
+<source>Source folder %x not found.</source>
+<target>Pasta de origem %x não foi encontrada.</target>
<source>Unresolved conflicts existing!</source>
<target>Conflitos não resolvidos existentes!</target>
@@ -1401,11 +1401,11 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Not enough free disk space available in:</source>
<target>Espaço em disco insuficiente em:</target>
-<source>Free disk space required:</source>
-<target>Espaço livre em disco requerido:</target>
+<source>Required:</source>
+<target>Requerido:</target>
-<source>Free disk space available:</source>
-<target>Espaço livre em disco:</target>
+<source>Available:</source>
+<target>Disponível:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>A Lixeira não está disponível para os seguintes caminhos! Os arquivos serão apagados permanentemente:</target>
@@ -1416,6 +1416,9 @@ Nota: Os nomes dos arquivos devem ser relativos aos diretórios base!
<source>Processing folder pair:</source>
<target>Processando par de pastas:</target>
+<source>Target folder %x already existing.</source>
+<target>Pasta de destino %x já existe.</target>
+
<source>Generating database...</source>
<target>Gerando banco de dados...</target>
diff --git a/BUILD/Languages/romanian.lng b/BUILD/Languages/romanian.lng
index 1e526883..9c0f7999 100644
--- a/BUILD/Languages/romanian.lng
+++ b/BUILD/Languages/romanian.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Despre</target>
-<source>Warning</source>
-<target>Atenție</target>
-
-<source>Question</source>
-<target>Întrebare</target>
-
<source>Confirm</source>
<target>Confirmare</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Informații</target>
+<source>Warning</source>
+<target>Atenție</target>
+
<source>Fatal Error</source>
<target>Eroare Fatală</target>
@@ -140,12 +137,6 @@
<pluralform>%x de Baiți</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Nu pot citi fila %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Nu pot scrie fila %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Fila cu baza de date %x este incompatibilă.</target>
@@ -155,9 +146,18 @@
<source>Database file %x does not yet exist.</source>
<target>Fila cu baza de date %x nu există încă.</target>
+<source>Database file is corrupt:</source>
+<target>Fila bazei de date este stricată (coruptă)</target>
+
<source>Out of memory!</source>
<target>Memorie epuizată!</target>
+<source>Cannot write file %x.</source>
+<target>Nu pot scrie fila %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Nu pot citi fila %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Filele cu baze de date nu partajează o sesiune comună.</target>
@@ -208,6 +208,9 @@
<source>/sec</source>
<target>/sec</target>
+<source>Cannot find file %x.</source>
+<target>Nu pot găsi fila %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Fila %x nu conține o configurație validă.</target>
@@ -232,14 +235,11 @@
<source>Cannot read the following XML elements:</source>
<target>Nu pot citi următoarele elemente XML:</target>
-<source>Cannot find file %x.</source>
-<target>Nu pot găsi fila %x.</target>
-
<source>&Open...</source>
<target>&Deschide...</target>
-<source>&Save...</source>
-<target>&Salvează...</target>
+<source>Save &As...</source>
+<target>Salvează c&a...</target>
<source>&Quit</source>
<target>&Ieși</target>
@@ -315,8 +315,8 @@ Comanda este declanșată dacă:
<source>(Build: %x)</source>
<target>(Compilația: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Configurația RealtimeSync</target>
+<source>All files</source>
+<target>Toate Filele</target>
<source>&Restore</source>
<target>&Restaurează</target>
@@ -330,8 +330,8 @@ Comanda este declanșată dacă:
<source>Waiting for missing directories...</source>
<target>Aștept ca dosarele lipsă să devină disponibile...</target>
-<source>An input folder name is empty.</source>
-<target>Un cîmp de introducere a numelui de dosar este gol.</target>
+<source>A folder input field is empty.</source>
+<target>Un cîmp de introducere a dosarului este gol.</target>
<source>Logging</source>
<target>Jurnal</target>
@@ -354,11 +354,8 @@ Comanda este declanșată dacă:
<source>Custom</source>
<target>Sincronizare Personalizată</target>
-<source>FreeFileSync batch file</source>
-<target>Filă Set FreeFileSync</target>
-
-<source>FreeFileSync configuration</source>
-<target>Configurație FreeFileSync</target>
+<source>FreeFileSync batch</source>
+<target>Set FreeFileSync</target>
<source>Batch execution</source>
<target>Execută Fila Set</target>
@@ -396,18 +393,18 @@ Comanda este declanșată dacă:
<source>Unable to connect to sourceforge.net!</source>
<target>Conectarea la situl sourceforge.net nu poate fi realizată!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Este disponibilă o versiune nouă a softului:</target>
<source>Download now?</source>
<target>Vrei s-o descarci acum ?</target>
-<source>Information</source>
-<target>Informații</target>
-
<source>FreeFileSync is up to date!</source>
<target>Ai deja ultima versiune a softului!</target>
+<source>Information</source>
+<target>Informații</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Vrei ca FreeFileSync să caute automat actualizări în fiecare săptămînă ?</target>
@@ -441,6 +438,12 @@ Comanda este declanșată dacă:
<source>Extension</source>
<target>Extensie</target>
+<source>Size:</source>
+<target>Mărime:</target>
+
+<source>Date:</source>
+<target>Dată:</target>
+
<source>Action</source>
<target>Acțiune</target>
@@ -474,6 +477,9 @@ Comanda este declanșată dacă:
<source>&New</source>
<target>Configurație &Nouă</target>
+<source>&Save</source>
+<target>&Salvează</target>
+
<source>&Language</source>
<target>&Limbă</target>
@@ -540,11 +546,8 @@ Comanda este declanșată dacă:
<source>Number of files and folders that will be deleted</source>
<target>Numărul de file și dosare care vor fi șterse</target>
-<source>Total amount of data that will be transferred</source>
-<target>Volumul total de date care va fi transferat</target>
-
-<source>Operation:</source>
-<target>Operație:</target>
+<source>Total bytes to copy</source>
+<target>Numărul total de baiți copiați</target>
<source>Items found:</source>
<target>Elemente Găsite:</target>
@@ -552,10 +555,10 @@ Comanda este declanșată dacă:
<source>Speed:</source>
<target>Viteză:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Timp Rămas:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Timp Scurs:</target>
<source>Batch job</source>
@@ -678,6 +681,15 @@ este același
<source>Source code written in C++ utilizing:</source>
<target>Cod sursă scris în C++ folosind:</target>
+<source>If you like FreeFileSync</source>
+<target>Donează pentru FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Donează prin PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Mulțumiri pentru traducerea FreeFileSync:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Opiniile și sugestiile despre program sînt binevenite</target>
@@ -690,39 +702,9 @@ este același
<source>Email</source>
<target>Adresa Autorului</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Mulțumiri pentru traducerea FreeFileSync:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Donează pentru FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Donează prin PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Publicat sub licența GNU GPL</target>
-<source>Ignore further errors</source>
-<target>Ignoră erorile ulterioare</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Ascunde mesajele de eroare apărute ulterior în timpul acestui proces</target>
-
-<source>&Ignore</source>
-<target>&Ignoră</target>
-
-<source>Do not show this dialog again</source>
-<target>Nu arăta acest dialog din nou</target>
-
-<source>&Switch</source>
-<target>&Comută</target>
-
-<source>&Yes</source>
-<target>&Da</target>
-
-<source>&No</source>
-<target>&Nu</target>
-
<source>Use Recycle Bin</source>
<target>Mută în Reciclator</target>
@@ -795,6 +777,9 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Statistics</source>
<target>Statistici</target>
+<source>Do not show this dialog again</source>
+<target>Nu arăta acest dialog din nou</target>
+
<source>Find what:</source>
<target>Găsește Asta:</target>
@@ -873,8 +858,14 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Never save changes</source>
<target>Nu salva niciodată modificările</target>
-<source>Save changes to current configuration?</source>
-<target>Vrei să salvezi modificările configurației curente?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Vrei să salvezi modificările făcute la %x?</target>
+
+<source>Save</source>
+<target>Salvează</target>
+
+<source>Don't Save</source>
+<target>Nu Salva</target>
<source>Configuration loaded!</source>
<target>Configurație deschisă !</target>
@@ -969,9 +960,6 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>All directories in sync!</source>
<target>Toate dosarele au fost sincronizate!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Rulează compararea înainte de a sincroniza!</target>
-
<source>Comma separated list</source>
<target>Listă de elemente separate prin virgulă</target>
@@ -1021,6 +1009,24 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<pluralform>%x din %y de rînduri afișate</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignoră erorile ulterioare</target>
+
+<source>&Ignore</source>
+<target>&OK</target>
+
+<source>&Switch</source>
+<target>&Comută</target>
+
+<source>Question</source>
+<target>Întrebare</target>
+
+<source>&Yes</source>
+<target>&Da</target>
+
+<source>&No</source>
+<target>&Nu</target>
+
<source>Scanning...</source>
<target>Scanez...</target>
@@ -1206,6 +1212,9 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Cannot delete directory %x.</source>
<target>Nu pot șterge dosarul %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Nu pot scrie atributele de filă ale lui %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Nu pot scrie modificarea timpului pentru %x.</target>
@@ -1230,9 +1239,6 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Nu pot copia legătura simbolică %x în %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Nu pot scrie atributele de filă ale lui %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Nu pot copia fila %x în %y.</target>
@@ -1257,11 +1263,8 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>No change since last synchronization!</source>
<target>Nu sînt schimbări de la ultima sincronizare!</target>
-<source>Filter settings have changed!</source>
-<target>Setările filtrului au fost schimbate!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Fila nu a fost procesată la ultima sincronizare!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Intrările corespondente din baza de date nu sînt considerate sincronizate, avînd în vedere setările curente.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Baza de date existentă va fi făcută compatibilă cu versiunea softului și apoi va fi setat sensul implicit de sincronizare: Filele vechi vor fi suprascrise de cele noi.</target>
@@ -1389,13 +1392,13 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Updating attributes of %x</source>
<target>Actualizez atributele lui %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Numele dosarului țintă nu poate să lipsească.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Cîmpul de introducere a dosarului țintă nu trebuie să fie gol.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Numele dosarului pentru versionarea filelor nu poate să lipsească.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Cîmpul de introducere a dosarului pentru versionare nu trebuie să fie gol.</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>Dosarul sursă %x nu a fost găsit.</target>
<source>Unresolved conflicts existing!</source>
@@ -1413,11 +1416,11 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Not enough free disk space available in:</source>
<target>Spațiu de stocare insuficient pe:</target>
-<source>Free disk space required:</source>
-<target>Spațiu liber necesar:</target>
+<source>Required:</source>
+<target>Necesar:</target>
-<source>Free disk space available:</source>
-<target>Spațiu liber disponibil:</target>
+<source>Available:</source>
+<target>Disponibil:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Reciclatorul nu este disponibil pentru căile următoare! Filele vor fi deci șterse definitiv:</target>
@@ -1428,6 +1431,9 @@ Notă: Numele filelor trebuie să fie relative la dosarele bază (rădăcină)!
<source>Processing folder pair:</source>
<target>Procesez perechea de dosare:</target>
+<source>Target folder %x already existing.</source>
+<target>Dosarul țintă %x există deja.</target>
+
<source>Generating database...</source>
<target>Generez baza de date...</target>
diff --git a/BUILD/Languages/russian.lng b/BUILD/Languages/russian.lng
index 79b98c07..2bf43563 100644
--- a/BUILD/Languages/russian.lng
+++ b/BUILD/Languages/russian.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Поиск папки %x...</target>
+<source>Batch execution</source>
+<target>Выполнение пакетного задания</target>
+
+<source>Items processed:</source>
+<target>Элементов обработано:</target>
+
+<source>Items remaining:</source>
+<target>Элементов осталось:</target>
+
+<source>Total time:</source>
+<target>Общее время:</target>
+
<source>Show in Explorer</source>
<target>Показать в Проводнике</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>О программе</target>
-<source>Warning</source>
-<target>Внимание</target>
-
-<source>Question</source>
-<target>Вопрос</target>
-
<source>Confirm</source>
<target>Подтвердить</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Информация</target>
+<source>Warning</source>
+<target>Внимание</target>
+
<source>Fatal Error</source>
<target>Критическая ошибка</target>
@@ -140,12 +149,6 @@
<pluralform>%x Байт</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Не удается прочитать файл %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Не удается записать файл %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Файл базы данных %x несовместим.</target>
@@ -155,9 +158,18 @@
<source>Database file %x does not yet exist.</source>
<target>Файл базы данных %x еще не существует.</target>
+<source>Database file is corrupt:</source>
+<target>Файл базы данных поврежден:</target>
+
<source>Out of memory!</source>
<target>Недостаточно памяти!</target>
+<source>Cannot write file %x.</source>
+<target>Не удается записать файл %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Не удается прочитать файл %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Файлы баз данных не имеют общей сессии.</target>
@@ -208,6 +220,9 @@
<source>/sec</source>
<target>/с</target>
+<source>Cannot find file %x.</source>
+<target>Не удается найти файл %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Файл %x не содержит действительной конфигурации.</target>
@@ -232,14 +247,11 @@
<source>Cannot read the following XML elements:</source>
<target>Невозможно прочитать следующие XML элементы:</target>
-<source>Cannot find file %x.</source>
-<target>Не удается найти файл %x.</target>
-
<source>&Open...</source>
<target>&Открыть...</target>
-<source>&Save...</source>
-<target>&Сохранить...</target>
+<source>Save &As...</source>
+<target>Сохранить &как...</target>
<source>&Quit</source>
<target>&Выход</target>
@@ -316,7 +328,7 @@ The command is triggered if:
<target>(сборка %x)</target>
<source>All files</source>
-<target></target>
+<target>Все файлы</target>
<source>&Restore</source>
<target>&Восстановить</target>
@@ -330,8 +342,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>Ожидание пропущенных папок...</target>
-<source>An input folder name is empty.</source>
-<target>Поле ввода имени папки пустое.</target>
+<source>A folder input field is empty.</source>
+<target>Поле ввода папки пустое.</target>
<source>Logging</source>
<target>Лог-файлы</target>
@@ -354,23 +366,8 @@ The command is triggered if:
<source>Custom</source>
<target>Выборочно</target>
-<source>FreeFileSync batch file</source>
-<target>Файл пакетного задания FreeFileSync</target>
-
-<source>Batch execution</source>
-<target>Выполнение пакетного задания</target>
-
-<source>Items processed:</source>
-<target>Элементов обработано:</target>
-
-<source>Items remaining:</source>
-<target>Элементов осталось:</target>
-
-<source>Total time:</source>
-<target>Общее время:</target>
-
-<source>Stop</source>
-<target>Стоп</target>
+<source>FreeFileSync batch</source>
+<target>Пакетное задание FreeFileSync</target>
<source>Synchronization aborted!</source>
<target>Синхронизация отменена!</target>
@@ -393,7 +390,7 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Невозможно соединиться с sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Доступна новая версия FreeFileSync:</target>
<source>Download now?</source>
@@ -438,6 +435,12 @@ The command is triggered if:
<source>Extension</source>
<target>Расширение</target>
+<source>Size:</source>
+<target>Размер:</target>
+
+<source>Date:</source>
+<target>Дата:</target>
+
<source>Action</source>
<target>Действие</target>
@@ -471,6 +474,9 @@ The command is triggered if:
<source>&New</source>
<target>&Новая</target>
+<source>&Save</source>
+<target>&Сохранить</target>
+
<source>&Language</source>
<target>&Язык</target>
@@ -540,8 +546,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>Количество файлов и папок, которые будут удалены</target>
-<source>Total amount of data that will be transferred</source>
-<target>Общий объем данных, который будет передаваться</target>
+<source>Total bytes to copy</source>
+<target>Всего байт для копирования</target>
<source>Items found:</source>
<target>Элементов найдено:</target>
@@ -549,10 +555,10 @@ The command is triggered if:
<source>Speed:</source>
<target>Скорость:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Времени осталось:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Времени прошло:</target>
<source>Batch job</source>
@@ -670,6 +676,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>Исходный код написан на C++ с использованием:</target>
+<source>If you like FreeFileSync</source>
+<target>Если Вам понравился FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Отправить деньги через PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Большое спасибо за перевод FreeFileSync:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Замечания и предложения приветствуются</target>
@@ -682,39 +697,9 @@ is the same
<source>Email</source>
<target>Почта</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Большое спасибо за перевод FreeFileSync:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Если Вам понравился FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Отправить деньги через PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Издается под лицензией GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Игнорировать последующие ошибки</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Скрыть последующие ошибки во время текущего процесса</target>
-
-<source>&Ignore</source>
-<target>&Игнорировать</target>
-
-<source>Do not show this dialog again</source>
-<target>Больше не показывать это окно</target>
-
-<source>&Switch</source>
-<target>&Переключить</target>
-
-<source>&Yes</source>
-<target>&Да</target>
-
-<source>&No</source>
-<target>&Нет</target>
-
<source>Use Recycle Bin</source>
<target>Использовать "Корзину"</target>
@@ -787,6 +772,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>Статистика</target>
+<source>Do not show this dialog again</source>
+<target>Больше не показывать это окно</target>
+
<source>Find what:</source>
<target>Найти:</target>
@@ -865,8 +853,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>Никогда не сохранять изменения</target>
-<source>Save changes to current configuration?</source>
-<target>Сохранить изменения в текущих настройках синхронизации?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Вы хотите сохранить изменения в %x?</target>
+
+<source>Save</source>
+<target>Сохранить</target>
+
+<source>Don't Save</source>
+<target>Не сохранять</target>
<source>Configuration loaded!</source>
<target>Настройки синхронизации загружены!</target>
@@ -961,9 +955,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>Все папки синхронизированы!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Пожалуйста, запустите сравнение перед синхронизацией!</target>
-
<source>Comma separated list</source>
<target>Список, разделяемый запятыми</target>
@@ -1013,6 +1004,24 @@ Note: File names must be relative to base directories!
<pluralform>%x из %y строк показано</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Игнорировать последующие ошибки</target>
+
+<source>&Ignore</source>
+<target>&Игнорировать</target>
+
+<source>&Switch</source>
+<target>&Переключить</target>
+
+<source>Question</source>
+<target>Вопрос</target>
+
+<source>&Yes</source>
+<target>&Да</target>
+
+<source>&No</source>
+<target>&Нет</target>
+
<source>Scanning...</source>
<target>Сканирование...</target>
@@ -1201,12 +1210,12 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>Не удается удалить папку %x.</target>
-<source>Cannot write modification time of %x.</source>
-<target>Не удается записать время модификации файла %x.</target>
-
<source>Cannot write file attributes of %x.</source>
<target>Не удается записать атрибуты файла %x.</target>
+<source>Cannot write modification time of %x.</source>
+<target>Не удается записать время модификации файла %x.</target>
+
<source>Cannot find system function %x.</source>
<target>Не удается найти системную функцию %x.</target>
@@ -1252,11 +1261,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>Никаких изменений с последней синхронизации!</target>
-<source>Filter settings have changed!</source>
-<target>Настройки фильтра были изменены!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Файл не был обработан при последней синхронизации!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Соответствующие записи в базе данных не синхронизированы с учетом текущих настроек.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>
@@ -1387,13 +1393,13 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>Обновление атрибутов %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Путь целевой папки не должен быть пустым.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Поле ввода целевой папки не должно быть пустым.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Путь папки для старых версий файлов не должен быть пустым.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Поле ввода папки для старых версий файлов не должно быть пустым.</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>Исходная папка %x не найдена.</target>
<source>Unresolved conflicts existing!</source>
@@ -1411,11 +1417,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>Не достаточно свободного места в:</target>
-<source>Free disk space required:</source>
-<target>Требуемое свободное место на диске:</target>
+<source>Required:</source>
+<target>Требуется:</target>
-<source>Free disk space available:</source>
-<target>Доступно свободного места на диске:</target>
+<source>Available:</source>
+<target>Доступно:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Для этого пути "Корзина" не доступна! Файлы будут удалены безвозвратно:</target>
@@ -1426,6 +1432,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>Обработка пары папок:</target>
+<source>Target folder %x already existing.</source>
+<target>Целевая папка %x уже существует.</target>
+
<source>Generating database...</source>
<target>Создание базы данных...</target>
diff --git a/BUILD/Languages/slovenian.lng b/BUILD/Languages/slovenian.lng
index 49461187..21511cea 100644
--- a/BUILD/Languages/slovenian.lng
+++ b/BUILD/Languages/slovenian.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>O programu(1)</target>
-<source>Warning</source>
-<target>Pozor</target>
-
-<source>Question</source>
-<target>Vprašanje</target>
-
<source>Confirm</source>
<target>Potrdi</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Pozor</target>
+
<source>Fatal Error</source>
<target>Usodna napaka</target>
@@ -141,14 +138,8 @@
<pluralform>%x Bajtov</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Ne morem prebrati datoteke %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Ne morem zapisati datoteke %x.</target>
-
<source>Database file %x is incompatible.</source>
-<target>Datoteka podatkovne baze %x je nekopatibilna.</target>
+<target>Datoteka podatkovne baze %x je nekompatibilna.</target>
<source>Initial synchronization:</source>
<target>Začetna sinhronizacija:</target>
@@ -156,9 +147,18 @@
<source>Database file %x does not yet exist.</source>
<target>Datoteka podatkovne baze %x še ne obstaja.</target>
+<source>Database file is corrupt:</source>
+<target>Datoteka podatkovne baze je poškodovana:</target>
+
<source>Out of memory!</source>
<target>Zmanjkalo pomnilnika!</target>
+<source>Cannot write file %x.</source>
+<target>Ne morem zapisati datoteke %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Ne morem prebrati datoteke %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Datoteke podatkovne baze si ne delijo skupne seje.</target>
@@ -211,6 +211,9 @@
<source>/sec</source>
<target>/sek</target>
+<source>Cannot find file %x.</source>
+<target>Ne morem najti datoteke %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Datoteka %x ne vsebuje veljavnih nastavitev</target>
@@ -235,14 +238,11 @@
<source>Cannot read the following XML elements:</source>
<target>Ne morem brati naslednje XML elemente:</target>
-<source>Cannot find file %x.</source>
-<target>Ne morem najti datoteke %x.</target>
-
<source>&Open...</source>
<target>&Odpri...</target>
-<source>&Save...</source>
-<target>&Shrani...</target>
+<source>Save &As...</source>
+<target>Shr&ani kot...</target>
<source>&Quit</source>
<target>&Zapri</target>
@@ -318,8 +318,8 @@ Ukaz se sproži če:
<source>(Build: %x)</source>
<target>(Izgradnja: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync nastavitve</target>
+<source>All files</source>
+<target>Vse datoteke</target>
<source>&Restore</source>
<target>&Obnovi</target>
@@ -333,8 +333,8 @@ Ukaz se sproži če:
<source>Waiting for missing directories...</source>
<target>Čakam na manjkajoče imenike...</target>
-<source>An input folder name is empty.</source>
-<target>Vhodno ime mape je prazno.</target>
+<source>A folder input field is empty.</source>
+<target>Vnosno polje za mapo je prazno.</target>
<source>Logging</source>
<target>Beleženje</target>
@@ -357,11 +357,8 @@ Ukaz se sproži če:
<source>Custom</source>
<target>Po meri</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync paketna datoteka</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync konfiguracija</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync paket</target>
<source>Batch execution</source>
<target>Paketno izvajanje</target>
@@ -399,18 +396,18 @@ Ukaz se sproži če:
<source>Unable to connect to sourceforge.net!</source>
<target>Ne morem se povezati na sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>Na voljo je nova različica FreeFileSync:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Nova različica FreeFileSync je na voljo:</target>
<source>Download now?</source>
<target>Prenesem sedaj?</target>
-<source>Information</source>
-<target>Informacije</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync je posodobljen!</target>
+<source>Information</source>
+<target>Informacije</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Ali želite, da FreeFileSync samodejno preverja za posodobitve vsak teden?</target>
@@ -444,6 +441,12 @@ Ukaz se sproži če:
<source>Extension</source>
<target>Razširitev</target>
+<source>Size:</source>
+<target>Velikost:</target>
+
+<source>Date:</source>
+<target>Datum:</target>
+
<source>Action</source>
<target>Ukrep</target>
@@ -477,6 +480,9 @@ Ukaz se sproži če:
<source>&New</source>
<target>&Novo</target>
+<source>&Save</source>
+<target>&Shrani</target>
+
<source>&Language</source>
<target>&Jezik</target>
@@ -543,11 +549,8 @@ Ukaz se sproži če:
<source>Number of files and folders that will be deleted</source>
<target>Število datotek in map, ki bodo izbrisane</target>
-<source>Total amount of data that will be transferred</source>
-<target>Količina podatkov, ki bo prenesena</target>
-
-<source>Operation:</source>
-<target>Operacija:</target>
+<source>Total bytes to copy</source>
+<target>Skupno bajtov za kopiranje</target>
<source>Items found:</source>
<target>Najdenih elementov:</target>
@@ -555,11 +558,11 @@ Ukaz se sproži če:
<source>Speed:</source>
<target>Hitrost:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Preostali čas:</target>
-<source>Elapsed time:</source>
-<target>Pretečen čas:</target>
+<source>Time elapsed:</source>
+<target>Pretečeni čas:</target>
<source>Batch job</source>
<target>Paketno opravilo</target>
@@ -681,6 +684,15 @@ enaka
<source>Source code written in C++ utilizing:</source>
<target>Izvorna koda napisana v C++ z uporabo:</target>
+<source>If you like FreeFileSync</source>
+<target>Če vam je FreeFileSync všeč</target>
+
+<source>Donate with PayPal</source>
+<target>Doniraj s PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Zahvale za prevod FreeFileSync gredo:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Povratne informacije in predlogi so dobrodošli</target>
@@ -693,39 +705,9 @@ enaka
<source>Email</source>
<target>Email</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Zahvale za prevod FreeFileSync gredo:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Če vam je FreeFileSync všeč</target>
-
-<source>Donate with PayPal</source>
-<target>Doniraj s PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Objavljeno pod licenco GNU General Public</target>
-<source>Ignore further errors</source>
-<target>Ignoriraj nadaljnje napake</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Skrijte nadaljnja obvestila o napakah med trenutnim procesom</target>
-
-<source>&Ignore</source>
-<target>&Ignoriraj</target>
-
-<source>Do not show this dialog again</source>
-<target>Ne prikaži več tega pogovornega okna</target>
-
-<source>&Switch</source>
-<target>&Preklopi</target>
-
-<source>&Yes</source>
-<target>&Da</target>
-
-<source>&No</source>
-<target>&Ne</target>
-
<source>Use Recycle Bin</source>
<target>Uporabi Koš</target>
@@ -798,6 +780,9 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Statistics</source>
<target>Statistika</target>
+<source>Do not show this dialog again</source>
+<target>Ne prikaži več tega pogovornega okna</target>
+
<source>Find what:</source>
<target>Najdi kaj</target>
@@ -876,8 +861,14 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Never save changes</source>
<target>Nikoli ne shrani sprememb</target>
-<source>Save changes to current configuration?</source>
-<target>Shranim spremembe trenutne konfiguracije?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Ali želite shraniti spremembe v %x?</target>
+
+<source>Save</source>
+<target>Shrani</target>
+
+<source>Don't Save</source>
+<target>Ne shrani</target>
<source>Configuration loaded!</source>
<target>Konfiguracija naložena!</target>
@@ -972,9 +963,6 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>All directories in sync!</source>
<target>Vsi imeniki so sinhronizirani!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Prosim najprej zaženite Primerjaj preden sinhronizirate!</target>
-
<source>Comma separated list</source>
<target>Seznam ločen z vejico</target>
@@ -1028,6 +1016,24 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<pluralform>%x od %y vrstic v prikazu</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignoriraj nadaljnje napake</target>
+
+<source>&Ignore</source>
+<target>&Ignoriraj</target>
+
+<source>&Switch</source>
+<target>&Preklopi</target>
+
+<source>Question</source>
+<target>Vprašanje</target>
+
+<source>&Yes</source>
+<target>&Da</target>
+
+<source>&No</source>
+<target>&Ne</target>
+
<source>Scanning...</source>
<target>Pregledujem...</target>
@@ -1218,6 +1224,9 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Cannot delete directory %x.</source>
<target>Ne morem izbrisati imenika %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Ne morem zapisati datotečnih atributov od %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Ne morem zapisati časa spremembe od %x.</target>
@@ -1242,9 +1251,6 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Ne morem kopirati simboličnih povezav %x v %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Ne morem zapisati datotečnih atributov od %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Ne morem kopirati datoteke %x v %y.</target>
@@ -1269,11 +1275,8 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>No change since last synchronization!</source>
<target>Ni sprememb od zadnje sinhronizacije!</target>
-<source>Filter settings have changed!</source>
-<target>Nastavitve filtra so bile spremenjene!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Datoteka ni bila obdelana z zadnjo sinhronizacijo!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Ustrezni vnosi v podatkovni bazi niso sinhronizirani pri upoštevanju trenutnih nastavitev.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Nastavljanje privzetih smeri sinhronizacije: Stare datoteke bodo prepisane z novimi datotekami.</target>
@@ -1401,14 +1404,14 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Updating attributes of %x</source>
<target>Posodabljam atribute od %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Ime ciljne mape ne sme biti prazno.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Vnosno polje za ciljno mapo ne sme biti prazno.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Ime mape za ustvarjanje različic ne sme biti prazno.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Vnosno polje za ustvarjanje različic ne sme biti prazno.</target>
-<source>Source directory %x not found.</source>
-<target>Izvorni imenik %x ni bil najden.</target>
+<source>Source folder %x not found.</source>
+<target>Izvorna mapa %x se ne najde.</target>
<source>Unresolved conflicts existing!</source>
<target>Obstajajo nerešeni spori!</target>
@@ -1425,11 +1428,11 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Not enough free disk space available in:</source>
<target>Na voljo ni dovolj prostega prostora na disku v:</target>
-<source>Free disk space required:</source>
-<target>Potreben prostor na disku:</target>
+<source>Required:</source>
+<target>Zahtevano:</target>
-<source>Free disk space available:</source>
-<target>Prosti disk, ki je na voljo:</target>
+<source>Available:</source>
+<target>Na voljo:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Koš ni na voljo za naslednje poti! Namesto tega bodo datoteke trajno izbrisane:</target>
@@ -1440,6 +1443,9 @@ Opomba: Imena datoteka morajo biti relativna osnovnim imenikom!
<source>Processing folder pair:</source>
<target>Obdelujem par map:</target>
+<source>Target folder %x already existing.</source>
+<target>Ciljna mapa %x že obstaja.</target>
+
<source>Generating database...</source>
<target>Ustvarjam podatkovno bazo...</target>
diff --git a/BUILD/Languages/spanish.lng b/BUILD/Languages/spanish.lng
index 39f6db69..fa14ba86 100644
--- a/BUILD/Languages/spanish.lng
+++ b/BUILD/Languages/spanish.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Buscando carpeta %x...</target>
+<source>Batch execution</source>
+<target>Ejecución por lotes</target>
+
+<source>Items processed:</source>
+<target>Elementos procesados:</target>
+
+<source>Items remaining:</source>
+<target>Elementos restantes:</target>
+
+<source>Total time:</source>
+<target>Tiempo total:</target>
+
<source>Show in Explorer</source>
<target>Mostrar en Explorer</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>Acerca de</target>
-<source>Warning</source>
-<target>Atención</target>
-
-<source>Question</source>
-<target>Pregunta</target>
-
<source>Confirm</source>
<target>Confirmar</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Atención</target>
+
<source>Fatal Error</source>
<target>Error fatal</target>
@@ -139,12 +148,6 @@
<pluralform>%x Bytes</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>No se puede leer el archivo %x</target>
-
-<source>Cannot write file %x.</source>
-<target>No se puede escribir el archivo %x</target>
-
<source>Database file %x is incompatible.</source>
<target>El archivo de base de datos %x es incompatible</target>
@@ -154,9 +157,18 @@
<source>Database file %x does not yet exist.</source>
<target>El archivo de base de datos %x aún no existe</target>
+<source>Database file is corrupt:</source>
+<target>El archivo de base de datos está dañado:</target>
+
<source>Out of memory!</source>
<target>¡Sin memoria!</target>
+<source>Cannot write file %x.</source>
+<target>No se puede escribir el archivo %x</target>
+
+<source>Cannot read file %x.</source>
+<target>No se puede leer el archivo %x</target>
+
<source>Database files do not share a common session.</source>
<target>Los archivos de base de datos no comparten una sesión común</target>
@@ -205,6 +217,9 @@
<source>/sec</source>
<target>/seg</target>
+<source>Cannot find file %x.</source>
+<target>No se puede encontrar el archivo %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>El archivo %x no contiene una configuración válida.</target>
@@ -229,14 +244,11 @@
<source>Cannot read the following XML elements:</source>
<target>Incapaz de leer los siguientes elementos XML:</target>
-<source>Cannot find file %x.</source>
-<target>No se puede encontrar el archivo %x.</target>
-
<source>&Open...</source>
<target>&Abrir...</target>
-<source>&Save...</source>
-<target>&Guardar...</target>
+<source>Save &As...</source>
+<target>Guardar &Como...</target>
<source>&Quit</source>
<target>&Salir</target>
@@ -312,8 +324,8 @@ El comando es disparado si::
<source>(Build: %x)</source>
<target>(Completado: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Configuración de RealtimeSync</target>
+<source>All files</source>
+<target>Todos los archivos</target>
<source>&Restore</source>
<target>&Restaurar</target>
@@ -327,8 +339,8 @@ El comando es disparado si::
<source>Waiting for missing directories...</source>
<target>Esperando directorios faltantes...</target>
-<source>An input folder name is empty.</source>
-<target>Un nombre de carpeta de entrada está vacío.</target>
+<source>A folder input field is empty.</source>
+<target>Un campo de entrada de la carpeta está vacío.</target>
<source>Logging</source>
<target>Registro</target>
@@ -351,26 +363,8 @@ El comando es disparado si::
<source>Custom</source>
<target>Personalizado</target>
-<source>FreeFileSync batch file</source>
-<target>Archivo por lotes de FreeFileSync</target>
-
-<source>FreeFileSync configuration</source>
-<target>Configuración de FreeFileSync</target>
-
-<source>Batch execution</source>
-<target>Ejecución por lotes</target>
-
-<source>Items processed:</source>
-<target>Elementos procesados:</target>
-
-<source>Items remaining:</source>
-<target>Elementos restantes:</target>
-
-<source>Total time:</source>
-<target>Tiempo total:</target>
-
-<source>Stop</source>
-<target>Detener</target>
+<source>FreeFileSync batch</source>
+<target>Batch de FreeFileSync</target>
<source>Synchronization aborted!</source>
<target>¡Sincronización abortada!</target>
@@ -393,18 +387,18 @@ El comando es disparado si::
<source>Unable to connect to sourceforge.net!</source>
<target>¡Incapaz de conectar con sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Una nueva versión de FreeFileSync está disponible:</target>
<source>Download now?</source>
<target>¿Descargar ahora?</target>
-<source>Information</source>
-<target>Información</target>
-
<source>FreeFileSync is up to date!</source>
<target>¡FreeFileSync está actualizado!</target>
+<source>Information</source>
+<target>Información</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>¿Quiere que FreeFileSync detecte automáticamente actualizaciones cada semana?</target>
@@ -438,6 +432,12 @@ El comando es disparado si::
<source>Extension</source>
<target>Extensión</target>
+<source>Size:</source>
+<target>Tamaño:</target>
+
+<source>Date:</source>
+<target>Fecha:</target>
+
<source>Action</source>
<target>Acción</target>
@@ -471,6 +471,9 @@ El comando es disparado si::
<source>&New</source>
<target>&Nuevo</target>
+<source>&Save</source>
+<target>&Guardar</target>
+
<source>&Language</source>
<target>&Idioma</target>
@@ -537,11 +540,8 @@ El comando es disparado si::
<source>Number of files and folders that will be deleted</source>
<target>Número de archivos y carpetas que serán eliminados</target>
-<source>Total amount of data that will be transferred</source>
-<target>Cantidad total de datos que serán transferidos</target>
-
-<source>Operation:</source>
-<target>Operación:</target>
+<source>Total bytes to copy</source>
+<target>Total de bytes a copiar</target>
<source>Items found:</source>
<target>Elementos encontrados:</target>
@@ -549,10 +549,10 @@ El comando es disparado si::
<source>Speed:</source>
<target>Velocidad:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Tiempo restante:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Tiempo transcurrido:</target>
<source>Batch job</source>
@@ -675,6 +675,15 @@ es el mismo
<source>Source code written in C++ utilizing:</source>
<target>Código fuente escrito en C++ utilizando:</target>
+<source>If you like FreeFileSync</source>
+<target>Si te gusta FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Donar a través de PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Agradecimientos por la traducción de FreeFileSync a:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Feedback y sugerencias son bienvenidas</target>
@@ -687,39 +696,9 @@ es el mismo
<source>Email</source>
<target>Correo electrónico</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Agradecimientos por la traducción de FreeFileSync a:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Si te gusta FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Donar a través de PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Publicado bajo "GNU General Public License"</target>
-<source>Ignore further errors</source>
-<target>Ignorar más errores</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Ocultar próximos mensajes de error durante el proceso actual</target>
-
-<source>&Ignore</source>
-<target>&Ignorar</target>
-
-<source>Do not show this dialog again</source>
-<target>No volver a mostrar este diálogo</target>
-
-<source>&Switch</source>
-<target>&Cambiar</target>
-
-<source>&Yes</source>
-<target>&Si</target>
-
-<source>&No</source>
-<target>&No</target>
-
<source>Use Recycle Bin</source>
<target>Utilizar Papelera de Reciclaje</target>
@@ -792,6 +771,9 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Statistics</source>
<target>Estadísticas</target>
+<source>Do not show this dialog again</source>
+<target>No volver a mostrar este diálogo</target>
+
<source>Find what:</source>
<target>Buscar:</target>
@@ -870,8 +852,14 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Never save changes</source>
<target>Nunca guardar cambios</target>
-<source>Save changes to current configuration?</source>
-<target>¿Guardar los cambios de la configuración actual?</target>
+<source>Do you want to save changes to %x?</source>
+<target>¿Quiere guardar los cambios de %x?</target>
+
+<source>Save</source>
+<target>Guardar</target>
+
+<source>Don't Save</source>
+<target>No guardar</target>
<source>Configuration loaded!</source>
<target>¡Configuración cargada!</target>
@@ -966,9 +954,6 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>All directories in sync!</source>
<target>¡Todos los directorios en sincronización!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>¡Por favor, ejecute la comparación antes de la sincronización!</target>
-
<source>Comma separated list</source>
<target>Lista separada por comas</target>
@@ -1014,6 +999,24 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<pluralform>%x de %y filas en vista</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorar más errores</target>
+
+<source>&Ignore</source>
+<target>&Ignorar</target>
+
+<source>&Switch</source>
+<target>&Cambiar</target>
+
+<source>Question</source>
+<target>Pregunta</target>
+
+<source>&Yes</source>
+<target>&Si</target>
+
+<source>&No</source>
+<target>&No</target>
+
<source>Scanning...</source>
<target>Escaneando...</target>
@@ -1194,6 +1197,9 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Cannot delete directory %x.</source>
<target>No se puede eliminar el directorio %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>No se pueden escribir los atributos de archivo de %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>No se puede escribir el tiempo de modificación de %x.</target>
@@ -1218,9 +1224,6 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Cannot copy symbolic link %x to %y.</source>
<target>No se puede copiar el enlance simbólico %x a %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>No se pueden escribir los atributos de archivo de %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>No se puede copiar el archivo %x a %y.</target>
@@ -1245,11 +1248,8 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>No change since last synchronization!</source>
<target>¡Ningún cambio desde la última sincronización!</target>
-<source>Filter settings have changed!</source>
-<target>¡Las opciones de filtrado han cambiado!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>¡El archivo no fue procesado por la última sincronización!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Las correspondientes entradas de la base de datos no se encuentran en sincronización, considerando la configuración actual.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Fijando direcciones de sincronización por defecto: Los archivos viejos serán sobreescritos por los archivos nuevos.</target>
@@ -1377,14 +1377,14 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Updating attributes of %x</source>
<target>Actualizar atributos de %x</target>
-<source>Target folder name must not be empty.</source>
-<target>El nombre de la carpeta de destino no debe estar vacío.</target>
+<source>Target folder input field must not be empty.</source>
+<target>El campo de entrada de la carpeta de destino no debe estar vacío.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>El nombre de la carpeta de versiones de archivos no debe estar vacío.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>El campo de entrada de la carpeta para el control de versiones no debe estar vacío.</target>
-<source>Source directory %x not found.</source>
-<target>Directorio fuente %x no encontrado.</target>
+<source>Source folder %x not found.</source>
+<target>El archivo de origen %x no ha sido encontrado.</target>
<source>Unresolved conflicts existing!</source>
<target>¡Existen conflictos sin resolver!</target>
@@ -1401,11 +1401,11 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Not enough free disk space available in:</source>
<target>Espacio en disco insuficiente en:</target>
-<source>Free disk space required:</source>
-<target>Espacio de disco necesario:</target>
+<source>Required:</source>
+<target>Requerido:</target>
-<source>Free disk space available:</source>
-<target>Espacio de disco disponible:</target>
+<source>Available:</source>
+<target>Disponible:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>¡La papelera de reciclaje no está disponible para las siguientes rutas! Los archivos serán eliminados permanentemente:</target>
@@ -1416,6 +1416,9 @@ Aviso: ¡Los nombres de archivos deben ser relativos a los directorios base!
<source>Processing folder pair:</source>
<target>Procesar un par de carpetas:</target>
+<source>Target folder %x already existing.</source>
+<target>La carpeta de destino %x ya existe.</target>
+
<source>Generating database...</source>
<target>Generando base de datos...</target>
diff --git a/BUILD/Languages/swedish.lng b/BUILD/Languages/swedish.lng
index 85364f34..e472d893 100644
--- a/BUILD/Languages/swedish.lng
+++ b/BUILD/Languages/swedish.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Om</target>
-<source>Warning</source>
-<target>Varning</target>
-
-<source>Question</source>
-<target>Fråga</target>
-
<source>Confirm</source>
<target>Bekräfta</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Info</target>
+<source>Warning</source>
+<target>Varning</target>
+
<source>Fatal Error</source>
<target>Allvarligt fel</target>
@@ -139,12 +136,6 @@
<pluralform>%x Byte</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Filen %x kan inte läsas in</target>
-
-<source>Cannot write file %x.</source>
-<target>Filen %x kan inte skrivas</target>
-
<source>Database file %x is incompatible.</source>
<target>Databasfilen %x är inkompatibel</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>Databasfilen %x finns ännu inte</target>
+<source>Database file is corrupt:</source>
+<target>Databafilen är korrupt</target>
+
<source>Out of memory!</source>
<target>Minnesbrist!</target>
+<source>Cannot write file %x.</source>
+<target>Filen %x kan inte skrivas</target>
+
+<source>Cannot read file %x.</source>
+<target>Filen %x kan inte läsas in</target>
+
<source>Database files do not share a common session.</source>
<target>Databasfilerna har ingen gemensam session</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/s</target>
+<source>Cannot find file %x.</source>
+<target>Filen %x kan inte hittas</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Filen %x innehåller ingen giltig konfiguration.</target>
@@ -226,17 +229,14 @@
<source>Volume name %x not part of file name %y!</source>
<target>Volymnamn %x saknas i filnamn %y!</target>
-<source>Cannot find file %x.</source>
-<target>Filen %x kan inte hittas</target>
-
<source>Cannot read the following XML elements:</source>
<target>Kan inte läsa följande XML-element:</target>
<source>&Open...</source>
<target>&Öppna...</target>
-<source>&Save...</source>
-<target>&Spara...</target>
+<source>Save &As...</source>
+<target>Spara s&om...</target>
<source>&Quit</source>
<target>&Avsluta</target>
@@ -312,8 +312,8 @@ Kommandot triggas om:
<source>(Build: %x)</source>
<target>(Bygge: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync konfiguration</target>
+<source>All files</source>
+<target>Alla filer</target>
<source>&Restore</source>
<target>&Återställ</target>
@@ -325,10 +325,10 @@ Kommandot triggas om:
<target>Övervakning aktiverad...</target>
<source>Waiting for missing directories...</source>
-<target>Väntar på saknade destinationer...</target>
+<target>Väntar på saknade mappsökvägar...</target>
-<source>An input folder name is empty.</source>
-<target>Det saknas ett källmappsnamn</target>
+<source>A folder input field is empty.</source>
+<target>Ett inmatningsfält är tomt</target>
<source>Logging</source>
<target>Loggar</target>
@@ -351,11 +351,8 @@ Kommandot triggas om:
<source>Custom</source>
<target>Anpassat</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync batch-fil</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync konfiguration</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync batch</target>
<source>Batch execution</source>
<target>Batch-körning</target>
@@ -393,18 +390,18 @@ Kommandot triggas om:
<source>Unable to connect to sourceforge.net!</source>
<target>Kan inte ansluta sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>En nyare version av FreeFileSync finns tillgänglig:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Det finns en ny version av FreeFileSync</target>
<source>Download now?</source>
<target>Ladda ner nu?</target>
-<source>Information</source>
-<target>Information</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync är uppdaterad!</target>
+<source>Information</source>
+<target>Information</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>Vill du att FreeFileSync skall söka efter uppdateringar varje vecka?</target>
@@ -438,6 +435,12 @@ Kommandot triggas om:
<source>Extension</source>
<target>Filformat</target>
+<source>Size:</source>
+<target>Storlek:</target>
+
+<source>Date:</source>
+<target>Datum:</target>
+
<source>Action</source>
<target>Aktivitet</target>
@@ -471,6 +474,9 @@ Kommandot triggas om:
<source>&New</source>
<target>&Nytt</target>
+<source>&Save</source>
+<target>&Spara</target>
+
<source>&Language</source>
<target>&Språk</target>
@@ -537,11 +543,8 @@ Kommandot triggas om:
<source>Number of files and folders that will be deleted</source>
<target>Antal filer och mappar som kommer att tas bort</target>
-<source>Total amount of data that will be transferred</source>
-<target>Total mängd data som kommer att överföras</target>
-
-<source>Operation:</source>
-<target>Arbetsuppgift:</target>
+<source>Total bytes to copy</source>
+<target>Byte att kopiera</target>
<source>Items found:</source>
<target>Funna poster:</target>
@@ -549,10 +552,10 @@ Kommandot triggas om:
<source>Speed:</source>
<target>Hastighet:</target>
-<source>Remaining time:</source>
-<target>Kvarvarande tid:</target>
+<source>Time remaining:</source>
+<target>Återstående tid:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Förfluten tid:</target>
<source>Batch job</source>
@@ -675,6 +678,15 @@ Filerna betecknas som lika om,
<source>Source code written in C++ utilizing:</source>
<target>Källkod skriven i C++ med hjälp av:</target>
+<source>If you like FreeFileSync</source>
+<target>Om du gillar FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Donera via PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Stort tack för översättningen av FreeFileSync går till:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Återkoppling och förslag är välkommna</target>
@@ -687,39 +699,9 @@ Filerna betecknas som lika om,
<source>Email</source>
<target>E-post</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Stort tack för översättningen av FreeFileSync går till:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Om du gillar FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Donera via PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Publiserad under GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Ignorera ytterligare fel</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Dölj vidare felmeddelanden under aktuell process</target>
-
-<source>&Ignore</source>
-<target>&Ignorera</target>
-
-<source>Do not show this dialog again</source>
-<target>Visa inte den här dialogrutan igen</target>
-
-<source>&Switch</source>
-<target>&Växla</target>
-
-<source>&Yes</source>
-<target>&Ja</target>
-
-<source>&No</source>
-<target>&Nej</target>
-
<source>Use Recycle Bin</source>
<target>Använd papperskorgen</target>
@@ -792,6 +774,9 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Statistics</source>
<target>Statistik</target>
+<source>Do not show this dialog again</source>
+<target>Visa inte den här dialogrutan igen</target>
+
<source>Find what:</source>
<target>Sök efter:</target>
@@ -870,8 +855,14 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Never save changes</source>
<target>Spara aldrig ändringar</target>
-<source>Save changes to current configuration?</source>
-<target>Vill du spara ändringarna i aktuella inställningar?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Vill du spara ändringar till %x?</target>
+
+<source>Save</source>
+<target>Spara</target>
+
+<source>Don't Save</source>
+<target>Spara inte</target>
<source>Configuration loaded!</source>
<target>Inställningar inlästa!</target>
@@ -966,9 +957,6 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>All directories in sync!</source>
<target>Alla mappar synkroniserade!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Du måste trycka "Jämför" innan du kan synkronisera.</target>
-
<source>Comma separated list</source>
<target>Komma-separerad lista</target>
@@ -1014,6 +1002,24 @@ OBS! Filnamnen måste anges relativt till basmappar
<pluralform>%x av %y rader i vyn</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ignorera ytterligare fel</target>
+
+<source>&Ignore</source>
+<target>&Ignorera</target>
+
+<source>&Switch</source>
+<target>&Växla</target>
+
+<source>Question</source>
+<target>Fråga</target>
+
+<source>&Yes</source>
+<target>&Ja</target>
+
+<source>&No</source>
+<target>&Nej</target>
+
<source>Scanning...</source>
<target>Skannar...</target>
@@ -1194,6 +1200,9 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Cannot delete directory %x.</source>
<target>Kan inte ta bort mappen %x.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Kan inte skriva filattribut för %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Kan inte ändra tidsangivelsen för %x.</target>
@@ -1218,9 +1227,6 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Cannot copy symbolic link %x to %y.</source>
<target>Kan inte kopiera den symboliska länken %x till %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Kan inte skriva filattribut för %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Kan inte kopiera filen %x till %y.</target>
@@ -1245,11 +1251,8 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>No change since last synchronization!</source>
<target>Inga ändringar sedan senaste synkronisering!</target>
-<source>Filter settings have changed!</source>
-<target>Filterinställningar har ändrats!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Filen bearbetades inte vid senaste synkroniseringen</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Aktuella databasposter är inte synkroniserad i förhållande till aktuella inställningar</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Standardsynkronisering: Gamla filer kommer att skrivas över av nyare versioner.</target>
@@ -1377,14 +1380,14 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Updating attributes of %x</source>
<target>Uppdaterar attribut för %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Målmappens namn saknas.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Indatafältet för målmapp får inte vara tomt.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Mappnamn för versionshantering saknas.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Indatafältet för versionshantering får inte vara tomt.</target>
-<source>Source directory %x not found.</source>
-<target>Källmappen %x hittas inte</target>
+<source>Source folder %x not found.</source>
+<target>Källmappen %x kan inte hittas.</target>
<source>Unresolved conflicts existing!</source>
<target>Obehandlad konflikt upptäckt!</target>
@@ -1401,11 +1404,11 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Not enough free disk space available in:</source>
<target>Ej tillräckligt ledigt diskutrymme på:</target>
-<source>Free disk space required:</source>
-<target>Krav på ledigt diskutrymme:</target>
+<source>Required:</source>
+<target>Utrymmeskrav:</target>
-<source>Free disk space available:</source>
-<target>Ledigt diskutrymme:</target>
+<source>Available:</source>
+<target>Tillgängligt:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Papperskorgen är inte tillgänglig för följande sökvägar! Filerna tas i stället bort permanent.</target>
@@ -1416,6 +1419,9 @@ OBS! Filnamnen måste anges relativt till basmappar
<source>Processing folder pair:</source>
<target>Bearbetar mapp-paret:</target>
+<source>Target folder %x already existing.</source>
+<target>Målmappen %x finns redan.</target>
+
<source>Generating database...</source>
<target>Skapar databas...</target>
diff --git a/BUILD/Languages/turkish.lng b/BUILD/Languages/turkish.lng
index 8a654cae..c58532a3 100644
--- a/BUILD/Languages/turkish.lng
+++ b/BUILD/Languages/turkish.lng
@@ -58,12 +58,6 @@
<source>About</source>
<target>Hakkında</target>
-<source>Warning</source>
-<target>Uyarı</target>
-
-<source>Question</source>
-<target>Soru</target>
-
<source>Confirm</source>
<target>Doğrula</target>
@@ -109,6 +103,9 @@
<source>Info</source>
<target>Bilgi</target>
+<source>Warning</source>
+<target>Uyarı</target>
+
<source>Fatal Error</source>
<target>Ölümcül Hata</target>
@@ -139,12 +136,6 @@
<pluralform>%x Bayt</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>%x dosyası okunamadı.</target>
-
-<source>Cannot write file %x.</source>
-<target>%x dosyası yazılamadı.</target>
-
<source>Database file %x is incompatible.</source>
<target>%x veritabanı dosyası uyumsuz</target>
@@ -154,9 +145,18 @@
<source>Database file %x does not yet exist.</source>
<target>%x veritabanı dosyası henüz yok.</target>
+<source>Database file is corrupt:</source>
+<target>Veritabanı dosyası bozulmuş:</target>
+
<source>Out of memory!</source>
<target>Bellek yetersiz!</target>
+<source>Cannot write file %x.</source>
+<target>%x dosyası yazılamadı.</target>
+
+<source>Cannot read file %x.</source>
+<target>%x dosyası okunamadı.</target>
+
<source>Database files do not share a common session.</source>
<target>Veritabanı dosyaları ortak bir oturumu paylaşamaz.</target>
@@ -205,6 +205,9 @@
<source>/sec</source>
<target>/san</target>
+<source>Cannot find file %x.</source>
+<target>%x dosyası bulunamadı.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>%x dosyası geçerli bir yapılandırma bilgisi içermiyor.</target>
@@ -229,14 +232,11 @@
<source>Cannot read the following XML elements:</source>
<target>Şu XML elemanları okunamadı:</target>
-<source>Cannot find file %x.</source>
-<target>%x dosyası bulunamadı.</target>
-
<source>&Open...</source>
<target>&Aç...</target>
-<source>&Save...</source>
-<target>&Kaydet</target>
+<source>Save &As...</source>
+<target>F&arklı Kaydet...</target>
<source>&Quit</source>
<target>Çı&k</target>
@@ -312,8 +312,8 @@ Komut şu durumlarda yürütülür:
<source>(Build: %x)</source>
<target>(Yapım: %x)</target>
-<source>RealtimeSync configuration</source>
-<target>RealtimeSync yapılandırması</target>
+<source>All files</source>
+<target>Tüm dosyalar</target>
<source>&Restore</source>
<target>Ge&ri yükle</target>
@@ -327,8 +327,8 @@ Komut şu durumlarda yürütülür:
<source>Waiting for missing directories...</source>
<target>Kayıp klasörler için bekleniyor...</target>
-<source>An input folder name is empty.</source>
-<target>Bir giriş klasörü adı eksik.</target>
+<source>A folder input field is empty.</source>
+<target>Bir klasör giriş alanı boş.</target>
<source>Logging</source>
<target>Günlükleme</target>
@@ -351,11 +351,8 @@ Komut şu durumlarda yürütülür:
<source>Custom</source>
<target>Özel</target>
-<source>FreeFileSync batch file</source>
-<target>FreeFileSync toplu iş dosyası</target>
-
-<source>FreeFileSync configuration</source>
-<target>FreeFileSync yapılandırması</target>
+<source>FreeFileSync batch</source>
+<target>FreeFileSync toplu işi</target>
<source>Batch execution</source>
<target>Toplu komut yürütme</target>
@@ -393,18 +390,18 @@ Komut şu durumlarda yürütülür:
<source>Unable to connect to sourceforge.net!</source>
<target>sourceforge.net sitesine bağlanılamıyor!</target>
-<source>A newer version of FreeFileSync is available:</source>
-<target>FreeFileSync programının yeni bir sürümü yayınlanmış:</target>
+<source>A new version of FreeFileSync is available:</source>
+<target>Yeni bir FreeFileSync sürümü yayınlanmış:</target>
<source>Download now?</source>
<target>Şimdi indir?</target>
-<source>Information</source>
-<target>Bilgi</target>
-
<source>FreeFileSync is up to date!</source>
<target>FreeFileSync güncel!</target>
+<source>Information</source>
+<target>Bilgi</target>
+
<source>Do you want FreeFileSync to automatically check for updates every week?</source>
<target>FreeFileSync güncellemelerinin her hafta denetlenmesini ister misiniz?</target>
@@ -438,6 +435,12 @@ Komut şu durumlarda yürütülür:
<source>Extension</source>
<target>Uzantı</target>
+<source>Size:</source>
+<target>Boyut:</target>
+
+<source>Date:</source>
+<target>Tarih:</target>
+
<source>Action</source>
<target>İşlem</target>
@@ -471,6 +474,9 @@ Komut şu durumlarda yürütülür:
<source>&New</source>
<target>Ye&ni</target>
+<source>&Save</source>
+<target>&Kaydet</target>
+
<source>&Language</source>
<target>Di&l</target>
@@ -537,11 +543,8 @@ Komut şu durumlarda yürütülür:
<source>Number of files and folders that will be deleted</source>
<target>Silinecek dosya ve klasör sayısı</target>
-<source>Total amount of data that will be transferred</source>
-<target>Aktarılacak toplam veri miktarı</target>
-
-<source>Operation:</source>
-<target>İşlem:</target>
+<source>Total bytes to copy</source>
+<target>Toplam kopyalayanacak bayt</target>
<source>Items found:</source>
<target>Bulunan bileşenler:</target>
@@ -549,17 +552,17 @@ Komut şu durumlarda yürütülür:
<source>Speed:</source>
<target>Hız:</target>
-<source>Remaining time:</source>
-<target>Kalan zaman:</target>
+<source>Time remaining:</source>
+<target>Kalan süre:</target>
-<source>Elapsed time:</source>
-<target>Geçen zaman:</target>
+<source>Time elapsed:</source>
+<target>Geçen süre:</target>
<source>Batch job</source>
<target>Toplu iş</target>
<source>Create a batch file to automate synchronization. Double-click this file or schedule in your system's task planner: FreeFileSync.exe <job name>.ffs_batch</source>
-<target>Eşleştirmeyi otomatikleştirmek için bir komut yığın dosyası oluşturun. Bu dosyaya çift tıklayarak ya da sisteminizdeki görev zamanlayıcıya: FreeFileSync.exe <görev adı>.ffs_batch şeklinde yazarak ekleyin</target>
+<target>Eşleştirmeyi otomatikleştirmek için bir toplu iş komut dosyası oluşturun. Bu dosyaya çift tıklayarak ya da sisteminizdeki görev zamanlayıcıya: FreeFileSync.exe <görev adı>.ffs_batch şeklinde yazarak ekleyin</target>
<source>Help</source>
<target>Yardım</target>
@@ -675,6 +678,15 @@ aynı olmalıdır
<source>Source code written in C++ utilizing:</source>
<target>Kaynak kodu C++ kullanılarak yazılmıştır:</target>
+<source>If you like FreeFileSync</source>
+<target>FreeFileSync’i beğendiyseniz</target>
+
+<source>Donate with PayPal</source>
+<target>PayPal ile bağış yapın</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>FreeFileSync çevirmenlerine çok teşekkürler:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Öneri ve geri bildirimlerinizi bekleriz</target>
@@ -687,39 +699,9 @@ aynı olmalıdır
<source>Email</source>
<target>E-posta</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>FreeFileSync çevirmenlerine çok teşekkürler:</target>
-
-<source>If you like FreeFileSync</source>
-<target>FreeFileSync’i beğendiyseniz</target>
-
-<source>Donate with PayPal</source>
-<target>PayPal ile bağış yapın</target>
-
<source>Published under the GNU General Public License</source>
<target>GNU Genel Kamu Lisansı şartları altında yayınlanmıştır</target>
-<source>Ignore further errors</source>
-<target>Sonraki hataları yoksay</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Yürürlükteki işlem boyunca başka hata iletisi gösterme</target>
-
-<source>&Ignore</source>
-<target>&Yoksay</target>
-
-<source>Do not show this dialog again</source>
-<target>Bu iletiyi yeniden gösterme</target>
-
-<source>&Switch</source>
-<target>&Değiştir</target>
-
-<source>&Yes</source>
-<target>&Evet</target>
-
-<source>&No</source>
-<target>&Hayır</target>
-
<source>Use Recycle Bin</source>
<target>Geri Dönüşüm Kutusu'nu kullan</target>
@@ -792,6 +774,9 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Statistics</source>
<target>İstatistikler</target>
+<source>Do not show this dialog again</source>
+<target>Bu iletiyi yeniden gösterme</target>
+
<source>Find what:</source>
<target>Aranacak:</target>
@@ -870,8 +855,14 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Never save changes</source>
<target>Asla değişiklikleri kaydetme</target>
-<source>Save changes to current configuration?</source>
-<target>Değişiklikleri şu anki yapılandırmaya kaydetmek ister misiniz?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Değişiklikleri %x dosyasına kaydetmek istiyor musunuz?</target>
+
+<source>Save</source>
+<target>Kaydet</target>
+
+<source>Don't Save</source>
+<target>Kaydetme</target>
<source>Configuration loaded!</source>
<target>Yapılandırma yüklendi!</target>
@@ -966,9 +957,6 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>All directories in sync!</source>
<target>Tüm klasörler eş!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Lütfen eşleştirmeden önce karşılaştırma yapın!</target>
-
<source>Comma separated list</source>
<target>Virgül ile ayrılmış liste</target>
@@ -1014,6 +1002,24 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<pluralform>%x / %y satır gösteriliyor</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Sonraki hataları yoksay</target>
+
+<source>&Ignore</source>
+<target>&Yoksay</target>
+
+<source>&Switch</source>
+<target>&Değiştir</target>
+
+<source>Question</source>
+<target>Soru</target>
+
+<source>&Yes</source>
+<target>&Evet</target>
+
+<source>&No</source>
+<target>&Hayır</target>
+
<source>Scanning...</source>
<target>Taranıyor...</target>
@@ -1194,6 +1200,9 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Cannot delete directory %x.</source>
<target>%x klasörü silinemedi.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>%x dosya öznitelikleri yazılamadı.</target>
+
<source>Cannot write modification time of %x.</source>
<target>%x son değişiklik zamanı yazılamadı.</target>
@@ -1218,9 +1227,6 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Cannot copy symbolic link %x to %y.</source>
<target>%x simgesel bağlantısı %y olarak kopyalanamadı.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>%x dosya öznitelikleri yazılamadı.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>%x dosyası %y olarak kopyalanamadı.</target>
@@ -1245,11 +1251,8 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>No change since last synchronization!</source>
<target>Son eşleştirmeden bu yana değişik olmamış!</target>
-<source>Filter settings have changed!</source>
-<target>Süzgeç ayarları değiştirildi!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Dosya son eşleştirmede işlenmemiş!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Karşı düşen veritabanı kayıtları, geçerli ayarlar göz önüne alındığında eşleşmiyor.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>Varsayılan eşleştirme yönleri ayarlanıyor: Yeni dosyalar eski dosyaların üzerine yazılacak.</target>
@@ -1377,13 +1380,13 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Updating attributes of %x</source>
<target>%x öznitelikleri güncelleniyor</target>
-<source>Target folder name must not be empty.</source>
-<target>Hedef klasör adı boş olamaz.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Hedef klasör giriş alanı boş olmamalı.</target>
-<source>Folder name for file versioning must not be empty.</source>
-<target>Dosya sürümlemesi için klasör adı boş olamaz.</target>
+<source>Folder input field for versioning must not be empty.</source>
+<target>Sürüm için klasör giriş alanı boş olmamalı.</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>%x kaynak klasörü bulunamadı.</target>
<source>Unresolved conflicts existing!</source>
@@ -1401,11 +1404,11 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Not enough free disk space available in:</source>
<target>Şurada yeterli disk alanı yok :</target>
-<source>Free disk space required:</source>
-<target>Gereken boş disk alanı:</target>
+<source>Required:</source>
+<target>Zorunlu:</target>
-<source>Free disk space available:</source>
-<target>Kullanılabilir disk alanı:</target>
+<source>Available:</source>
+<target>Kullanılabilir:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Şu yollar için geri dönüşüm kutusu kullanılamaz! Dosyalar anında ve tamamen silinir:</target>
@@ -1416,6 +1419,9 @@ Not: Dosya adları kök klasörlere göre bağıl olmalıdır!
<source>Processing folder pair:</source>
<target>İşlenen klasör çifti:</target>
+<source>Target folder %x already existing.</source>
+<target>%x hedef klasörü zaten var.</target>
+
<source>Generating database...</source>
<target>Veri tabanı oluşturuluyor...</target>
diff --git a/BUILD/Languages/ukrainian.lng b/BUILD/Languages/ukrainian.lng
index b7f89539..9de06b00 100644
--- a/BUILD/Languages/ukrainian.lng
+++ b/BUILD/Languages/ukrainian.lng
@@ -10,6 +10,18 @@
<source>Searching for folder %x...</source>
<target>Пошук каталогу %x...</target>
+<source>Batch execution</source>
+<target>Виконання пакетного завдання</target>
+
+<source>Items processed:</source>
+<target>Елементів оброблено:</target>
+
+<source>Items remaining:</source>
+<target>Елементів залишилось:</target>
+
+<source>Total time:</source>
+<target>Загальний час:</target>
+
<source>Show in Explorer</source>
<target>Показати у Провіднику</target>
@@ -58,12 +70,6 @@
<source>About</source>
<target>Про</target>
-<source>Warning</source>
-<target>Увага</target>
-
-<source>Question</source>
-<target>Питання</target>
-
<source>Confirm</source>
<target>Підтвердити</target>
@@ -109,6 +115,9 @@
<source>Info</source>
<target>Інформація</target>
+<source>Warning</source>
+<target>Увага</target>
+
<source>Fatal Error</source>
<target>Критична помилка</target>
@@ -140,12 +149,6 @@
<pluralform>%x байтів</pluralform>
</target>
-<source>Cannot read file %x.</source>
-<target>Не вдається прочитати файл %x.</target>
-
-<source>Cannot write file %x.</source>
-<target>Не вдається записати файл %x.</target>
-
<source>Database file %x is incompatible.</source>
<target>Несумісний файл бази даних %x.</target>
@@ -155,9 +158,18 @@
<source>Database file %x does not yet exist.</source>
<target>Файл бази даних %x ще не існує.</target>
+<source>Database file is corrupt:</source>
+<target>Файл бази даних пошкоджений:</target>
+
<source>Out of memory!</source>
<target>Бракує пам'яті!</target>
+<source>Cannot write file %x.</source>
+<target>Не вдається записати файл %x.</target>
+
+<source>Cannot read file %x.</source>
+<target>Не вдається прочитати файл %x.</target>
+
<source>Database files do not share a common session.</source>
<target>Файли баз даних не поділяють спільну сесію.</target>
@@ -208,6 +220,9 @@
<source>/sec</source>
<target>/сек</target>
+<source>Cannot find file %x.</source>
+<target>Не вдається знайти файлу %x.</target>
+
<source>File %x does not contain a valid configuration.</source>
<target>Файл %x не містить правильної конфігурації.</target>
@@ -232,14 +247,11 @@
<source>Cannot read the following XML elements:</source>
<target>Не вдається прочитати такі елементи XML:</target>
-<source>Cannot find file %x.</source>
-<target>Не вдається знайти файлу %x.</target>
-
<source>&Open...</source>
<target>Відкрити...</target>
-<source>&Save...</source>
-<target>Зберегти...</target>
+<source>Save &As...</source>
+<target>Зберегти як...</target>
<source>&Quit</source>
<target>Вихід</target>
@@ -315,8 +327,8 @@ The command is triggered if:
<source>(Build: %x)</source>
<target>(компіляція %x)</target>
-<source>RealtimeSync configuration</source>
-<target>Налаштування RealtimeSync</target>
+<source>All files</source>
+<target>Всі файли</target>
<source>&Restore</source>
<target>&Відновити</target>
@@ -330,8 +342,8 @@ The command is triggered if:
<source>Waiting for missing directories...</source>
<target>Очікування пропущених каталогів...</target>
-<source>An input folder name is empty.</source>
-<target>Назва вхідної папки порожня.</target>
+<source>A folder input field is empty.</source>
+<target>Порожнє поле папки.</target>
<source>Logging</source>
<target>Лог-файли</target>
@@ -354,26 +366,8 @@ The command is triggered if:
<source>Custom</source>
<target>Вибірково</target>
-<source>FreeFileSync batch file</source>
-<target>Файл завдання FreeFileSync</target>
-
-<source>FreeFileSync configuration</source>
-<target>Налаштування FreeFileSync</target>
-
-<source>Batch execution</source>
-<target>Виконання пакетного завдання</target>
-
-<source>Items processed:</source>
-<target>Елементів оброблено:</target>
-
-<source>Items remaining:</source>
-<target>Елементів залишилось:</target>
-
-<source>Total time:</source>
-<target>Загальний час:</target>
-
-<source>Stop</source>
-<target>Стоп</target>
+<source>FreeFileSync batch</source>
+<target>Командний файл FreeFileSync</target>
<source>Synchronization aborted!</source>
<target>Синхронізація припинена!</target>
@@ -396,7 +390,7 @@ The command is triggered if:
<source>Unable to connect to sourceforge.net!</source>
<target>Не можна з’єднатися з sourceforge.net!</target>
-<source>A newer version of FreeFileSync is available:</source>
+<source>A new version of FreeFileSync is available:</source>
<target>Доступна нова версія FreeFileSync:</target>
<source>Download now?</source>
@@ -441,6 +435,12 @@ The command is triggered if:
<source>Extension</source>
<target>Розширення</target>
+<source>Size:</source>
+<target>Розмір:</target>
+
+<source>Date:</source>
+<target>Дата:</target>
+
<source>Action</source>
<target>Дія</target>
@@ -472,7 +472,10 @@ The command is triggered if:
<target>2. &Синхронізувати</target>
<source>&New</source>
-<target>&Нова</target>
+<target>Нова</target>
+
+<source>&Save</source>
+<target>Зберегти</target>
<source>&Language</source>
<target>&Мова</target>
@@ -543,8 +546,8 @@ The command is triggered if:
<source>Number of files and folders that will be deleted</source>
<target>Кількість файлів і папок, які будуть вилучені</target>
-<source>Total amount of data that will be transferred</source>
-<target>Загальний об’єм даних, які будуть передаватися</target>
+<source>Total bytes to copy</source>
+<target>Всього зкопіювати байтів</target>
<source>Items found:</source>
<target>Елементів знайдено:</target>
@@ -552,10 +555,10 @@ The command is triggered if:
<source>Speed:</source>
<target>Швидкість:</target>
-<source>Remaining time:</source>
+<source>Time remaining:</source>
<target>Залишилось часу:</target>
-<source>Elapsed time:</source>
+<source>Time elapsed:</source>
<target>Пройшло часу:</target>
<source>Batch job</source>
@@ -674,6 +677,15 @@ is the same
<source>Source code written in C++ utilizing:</source>
<target>Код програми написаний на C++ з використанням:</target>
+<source>If you like FreeFileSync</source>
+<target>Якщо Вам сподобався FreeFileSync</target>
+
+<source>Donate with PayPal</source>
+<target>Пожертвувати через PayPal</target>
+
+<source>Big thanks for localizing FreeFileSync goes out to:</source>
+<target>Щира подяка за переклад FreeFileSync:</target>
+
<source>Feedback and suggestions are welcome</source>
<target>Відгуки та пропозиції вітаються</target>
@@ -686,39 +698,9 @@ is the same
<source>Email</source>
<target>Почта</target>
-<source>Big thanks for localizing FreeFileSync goes out to:</source>
-<target>Щира подяка за переклад FreeFileSync:</target>
-
-<source>If you like FreeFileSync</source>
-<target>Якщо Вам сподобався FreeFileSync</target>
-
-<source>Donate with PayPal</source>
-<target>Пожертвувати через PayPal</target>
-
<source>Published under the GNU General Public License</source>
<target>Видано за ліцензією GNU General Public License</target>
-<source>Ignore further errors</source>
-<target>Ігнорувати майбутні помилки</target>
-
-<source>Hide further error messages during the current process</source>
-<target>Приховати наступні помилки підчас цього процесу</target>
-
-<source>&Ignore</source>
-<target>&Ігнорувати</target>
-
-<source>Do not show this dialog again</source>
-<target>Надалі не показувати це вікно</target>
-
-<source>&Switch</source>
-<target>&Змінити</target>
-
-<source>&Yes</source>
-<target>&Так</target>
-
-<source>&No</source>
-<target>&Ні</target>
-
<source>Use Recycle Bin</source>
<target>Використовувати "Корзину"</target>
@@ -791,6 +773,9 @@ Note: File names must be relative to base directories!
<source>Statistics</source>
<target>Статистика</target>
+<source>Do not show this dialog again</source>
+<target>Надалі не показувати це вікно</target>
+
<source>Find what:</source>
<target>Знайти:</target>
@@ -869,8 +854,14 @@ Note: File names must be relative to base directories!
<source>Never save changes</source>
<target>Ніколи не зберігати змін</target>
-<source>Save changes to current configuration?</source>
-<target>Зберегти зміни в активних налаштуваннях?</target>
+<source>Do you want to save changes to %x?</source>
+<target>Зберегти зміни в %x?</target>
+
+<source>Save</source>
+<target>Зберегти</target>
+
+<source>Don't Save</source>
+<target>Не зберігати</target>
<source>Configuration loaded!</source>
<target>Налаштування синхронізації загружено!</target>
@@ -965,9 +956,6 @@ Note: File names must be relative to base directories!
<source>All directories in sync!</source>
<target>Всі каталоги синхронізовані!</target>
-<source>Please run a Compare first before synchronizing!</source>
-<target>Будь ласка, запустіть порівняння перед синхронізацією!</target>
-
<source>Comma separated list</source>
<target>Розділений комами список</target>
@@ -1017,6 +1005,24 @@ Note: File names must be relative to base directories!
<pluralform>%x з %y рядків</pluralform>
</target>
+<source>Ignore further errors</source>
+<target>Ігнорувати майбутні помилки</target>
+
+<source>&Ignore</source>
+<target>&Ігнорувати</target>
+
+<source>&Switch</source>
+<target>&Змінити</target>
+
+<source>Question</source>
+<target>Питання</target>
+
+<source>&Yes</source>
+<target>&Так</target>
+
+<source>&No</source>
+<target>&Ні</target>
+
<source>Scanning...</source>
<target>Сканування...</target>
@@ -1202,6 +1208,9 @@ Note: File names must be relative to base directories!
<source>Cannot delete directory %x.</source>
<target>Не вдається видалити каталог х%.</target>
+<source>Cannot write file attributes of %x.</source>
+<target>Не вдається записати атрибути файла %x.</target>
+
<source>Cannot write modification time of %x.</source>
<target>Не вдається записати часу модифікації %х.</target>
@@ -1226,9 +1235,6 @@ Note: File names must be relative to base directories!
<source>Cannot copy symbolic link %x to %y.</source>
<target>Не вдається зкопіювати символьне посилання %х в %y.</target>
-<source>Cannot write file attributes of %x.</source>
-<target>Не вдається записати атрибути файла %x.</target>
-
<source>Cannot copy file %x to %y.</source>
<target>Не вдається зкопіювати файл %х до %y.</target>
@@ -1253,11 +1259,8 @@ Note: File names must be relative to base directories!
<source>No change since last synchronization!</source>
<target>Жодних змін з останньої синхронізації!</target>
-<source>Filter settings have changed!</source>
-<target>Налаштування фільтра були змінені!</target>
-
-<source>The file was not processed by last synchronization!</source>
-<target>Файл не був оброблений при останній синхронізації!</target>
+<source>The corresponding database entries are not in sync considering current settings.</source>
+<target>Згідно з поточними налаштуваннями відповідні записи в базах даних не синхронізовані.</target>
<source>Setting default synchronization directions: Old files will be overwritten with newer files.</source>
<target>
@@ -1388,13 +1391,13 @@ Note: File names must be relative to base directories!
<source>Updating attributes of %x</source>
<target>Оновлення атрибутів %x</target>
-<source>Target folder name must not be empty.</source>
-<target>Назва цільової папки не повинна бути порожньою.</target>
+<source>Target folder input field must not be empty.</source>
+<target>Поле цільової папки не повинно бути порожнім.</target>
-<source>Folder name for file versioning must not be empty.</source>
+<source>Folder input field for versioning must not be empty.</source>
<target>Назва папки для версій файлів не повинна бути порожньою.</target>
-<source>Source directory %x not found.</source>
+<source>Source folder %x not found.</source>
<target>Вихідний каталог %x не знайдено.</target>
<source>Unresolved conflicts existing!</source>
@@ -1412,11 +1415,11 @@ Note: File names must be relative to base directories!
<source>Not enough free disk space available in:</source>
<target>Не достатньо вільного місця в:</target>
-<source>Free disk space required:</source>
-<target>Потрібне вільне місце на диску:</target>
+<source>Required:</source>
+<target>Потрібно:</target>
-<source>Free disk space available:</source>
-<target>Доступно вільного місця на диску:</target>
+<source>Available:</source>
+<target>Доступно:</target>
<source>Recycle Bin is not available for the following paths! Files will be deleted permanently instead:</source>
<target>Корзина для цього шляху недоступна. Файли будуть вилучені назавжди:</target>
@@ -1427,6 +1430,9 @@ Note: File names must be relative to base directories!
<source>Processing folder pair:</source>
<target>Обробка пари папок:</target>
+<source>Target folder %x already existing.</source>
+<target>Цільова папка %x вже існує.</target>
+
<source>Generating database...</source>
<target>Створення бази даних...</target>
diff --git a/BUILD/Resources.zip b/BUILD/Resources.zip
index 54e6e657..2f132d17 100644
--- a/BUILD/Resources.zip
+++ b/BUILD/Resources.zip
Binary files differ
diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp
index 03631460..e874a6e0 100644
--- a/FreeFileSync.cbp
+++ b/FreeFileSync.cbp
@@ -18,12 +18,14 @@
<Compiler>
<Add option="-O3" />
<Add option="-DNDEBUG" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_release_lib\mswu" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-static" />
- <Add library="libboost_thread-mgw46-mt-s-1_49.a" />
+ <Add library="libboost_thread-mgw47-mt-s-1_50.a" />
+ <Add library="libboost_system-mgw47-mt-s-1_50.a" />
+ <Add library="libboost_chrono-mgw47-mt-s-1_50.a" />
<Add library="libwxmsw28u_aui.a" />
<Add library="libwxmsw28u_adv.a" />
<Add library="libwxmsw28u_core.a" />
@@ -31,7 +33,7 @@
<Add library="libwxbase28u_net.a" />
<Add library="libwxpng.a" />
<Add library="libwxzlib.a" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_release_lib" />
</Linker>
<ExtraCommands>
<Add after='&quot;C:\Program Files\C++\CodeSigning\SignCode.cmd&quot; &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot;' />
@@ -50,16 +52,19 @@
<Add option="-Winvalid-pch" />
<Add option='-include &quot;wx+/pch.h&quot;' />
<Add option="-D__WXDEBUG__" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_dll\mswud" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_debug_dll\mswud" />
</Compiler>
<Linker>
- <Add library="libboost_thread-mgw46-mt-sd-1_49.a" />
+ <Add library="libboost_thread-mgw47-mt-sd-1_50.a" />
+ <Add library="libboost_system-mgw47-mt-sd-1_50.a" />
+ <Add library="libboost_chrono-mgw47-mt-sd-1_50.a" />
<Add library="libwxmsw28ud_aui.a" />
<Add library="libwxmsw28ud_adv.a" />
<Add library="libwxmsw28ud_core.a" />
<Add library="libwxbase28ud.a" />
<Add library="libwxbase28ud_net.a" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_dll" />
+ <Add library="libwxzlibd.a" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_debug_dll" />
</Linker>
</Target>
<Target title="Unit Test">
@@ -75,18 +80,20 @@
<Add option="-Winvalid-pch" />
<Add option='-include &quot;wx+/pch.h&quot;' />
<Add option="-D__WXDEBUG__" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_dll\mswud" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_debug_dll\mswud" />
<Add directory="lib\gtest" />
<Add directory="lib\gtest\include" />
</Compiler>
<Linker>
- <Add library="libboost_thread-mgw46-mt-sd-1_49.a" />
+ <Add library="libboost_thread-mgw47-mt-sd-1_50.a" />
+ <Add library="libboost_system-mgw47-mt-sd-1_50.a" />
+ <Add library="libboost_chrono-mgw47-mt-sd-1_50.a" />
<Add library="libwxmsw28ud_adv.a" />
<Add library="libwxmsw28ud_core.a" />
<Add library="libwxbase28ud.a" />
<Add library="libwxpngd.a" />
<Add library="libwxzlibd.a" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_dll" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_debug_dll" />
</Linker>
</Target>
</Build>
@@ -99,7 +106,7 @@
<Add option="-Wmissing-include-dirs" />
<Add option="-Wswitch-enum" />
<Add option="-Wmain" />
- <Add option="-std=c++0x" />
+ <Add option="-std=c++11" />
<Add option="-Wall" />
<Add option="-pipe" />
<Add option="-mthreads" />
@@ -160,6 +167,7 @@
<Unit filename="lib\dir_lock.cpp" />
<Unit filename="lib\dir_lock.h" />
<Unit filename="lib\ffs_paths.h" />
+ <Unit filename="lib\generate_logfile.h" />
<Unit filename="lib\gtest\main.cpp">
<Option target="Unit Test" />
</Unit>
@@ -456,6 +464,8 @@
<Option target="Release" />
<Option target="Debug-DLL" />
</Unit>
+ <Unit filename="wx+\zlib_wrap.cpp" />
+ <Unit filename="wx+\zlib_wrap.h" />
<Unit filename="zen\assert_static.h" />
<Unit filename="zen\base64.h" />
<Unit filename="zen\build_info.h" />
@@ -476,7 +486,6 @@
<Unit filename="zen\file_io.h" />
<Unit filename="zen\file_traverser.cpp" />
<Unit filename="zen\file_traverser.h" />
- <Unit filename="zen\file_update_handle.h" />
<Unit filename="zen\fixed_list.h" />
<Unit filename="zen\guid.h" />
<Unit filename="zen\i18n.h" />
@@ -497,7 +506,6 @@
<Unit filename="zen\symlink_target.h" />
<Unit filename="zen\thread.h" />
<Unit filename="zen\tick_count.h" />
- <Unit filename="zen\utf8.h" />
<Unit filename="zen\warn_static.h" />
<Unit filename="zen\win.h" />
<Unit filename="zen\zstring.cpp" />
diff --git a/FreeFileSync.vcxproj b/FreeFileSync.vcxproj
index 5f3018cb..cc6b4203 100644
--- a/FreeFileSync.vcxproj
+++ b/FreeFileSync.vcxproj
@@ -35,7 +35,7 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v110</PlatformToolset>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@@ -101,7 +101,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_dll\mswud;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x86_debug_dll\mswud;.</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -115,7 +115,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>wxmsw28ud_aui.lib;wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxbase28ud_net.lib;wxbase28ud.lib;wxpngd.lib;wxzlibd.lib;comctl32.lib;ws2_32.lib;Rpcrt4.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets\lib\vc_dll;C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x86_debug_dll</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -128,7 +128,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include;C:\Program Files\C++\wxWidgets-x64-VC11\lib\vc_dll\mswud;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x64_debug_dll\mswud;.</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -143,12 +143,14 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>wxbase28ud.lib;wxmsw28ud_core.lib;wxmsw28ud_adv.lib;wxmsw28ud_aui.lib;wxbase28ud_net.lib;wxpngd.lib;wxzlibd.lib;comctl32.lib;ws2_32.lib;Rpcrt4.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\lib\vc_dll;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x64_debug_dll</AdditionalLibraryDirectories>
<LinkStatus>
</LinkStatus>
+ <ManifestFile>
+ </ManifestFile>
</Link>
<ResourceCompile>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
@@ -159,7 +161,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x86_release_lib\mswu;.</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -173,7 +175,7 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wxmsw28u_aui.lib;wxmsw28u_adv.lib;wxmsw28u_core.lib;wxbase28u.lib;wxpng.lib;wxzlib.lib;wxbase28u_net.lib;comctl32.lib;ws2_32.lib;winmm.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets\lib\vc_lib;C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x86_release_lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -190,7 +192,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x64_release_lib\mswu;.</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -204,10 +206,10 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wxmsw28u_aui.lib;wxmsw28u_adv.lib;wxmsw28u_core.lib;wxbase28u.lib;wxpng.lib;wxzlib.lib;wxbase28u_net.lib;comctl32.lib;ws2_32.lib;winmm.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x64_release_lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
</ResourceCompile>
<PostBuildEvent>
@@ -216,8 +218,8 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="algorithm.cpp">
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Use</PrecompiledHeader>
</ClCompile>
<ClCompile Include="application.cpp" />
<ClCompile Include="comparison.cpp" />
@@ -258,11 +260,16 @@
<ClCompile Include="ui\tray_icon.cpp" />
<ClCompile Include="ui\tree_view.cpp" />
<ClCompile Include="wx+\button.cpp" />
+ <ClCompile Include="wx+\create_pch.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ </ClCompile>
<ClCompile Include="wx+\format_unit.cpp" />
<ClCompile Include="wx+\graph.cpp" />
<ClCompile Include="wx+\grid.cpp" />
<ClCompile Include="wx+\mouse_move_dlg.cpp" />
<ClCompile Include="wx+\tooltip.cpp" />
+ <ClCompile Include="wx+\zlib_wrap.cpp" />
<ClCompile Include="zenxml\unit_test.cpp" />
<ClCompile Include="zen\dst_hack.cpp" />
<ClCompile Include="zen\file_handling.cpp" />
diff --git a/Makefile b/Makefile
index e981b48a..ded925f3 100644
--- a/Makefile
+++ b/Makefile
@@ -10,12 +10,12 @@ COMMON_LINK_FLAGS = -pthread -lrt
#default build
CPPFLAGS = $(COMMON_COMPILE_FLAGS) `wx-config --cxxflags --debug=no --unicode=yes`
-LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs std,aui --debug=no --unicode=yes` -lboost_thread
+LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs std,aui --debug=no --unicode=yes` -lboost_thread -lboost_system
#static std library linkage used for precompiled release
ifeq ($(BUILD),release)
CPPFLAGS = $(COMMON_COMPILE_FLAGS) `wx-config --cxxflags --debug=no --unicode=yes --static=yes`
-LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs std,aui --debug=no --unicode=yes --static=yes` /usr/local/lib/libboost_thread.a
+LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs std,aui --debug=no --unicode=yes --static=yes` /usr/local/lib/libboost_thread.a /usr/local/lib/libboost_system.a
endif
#####################################################################################################
@@ -87,6 +87,7 @@ CPP_LIST+=wx+/button.cpp
CPP_LIST+=wx+/format_unit.cpp
CPP_LIST+=wx+/graph.cpp
CPP_LIST+=wx+/tooltip.cpp
+CPP_LIST+=wx+/zlib_wrap.cpp
#list of all *.o files
OBJECT_LIST=$(CPP_LIST:%.cpp=OBJ/FFS_Release_GCC_Make/%.o)
diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp
index 97ce1a5b..24aca825 100644
--- a/RealtimeSync/RealtimeSync.cbp
+++ b/RealtimeSync/RealtimeSync.cbp
@@ -17,7 +17,7 @@
<Compiler>
<Add option="-O3" />
<Add option="-DNDEBUG" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib\mswu" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_release_lib\mswu" />
</Compiler>
<Linker>
<Add option="-s" />
@@ -27,8 +27,10 @@
<Add library="libwxbase28u.a" />
<Add library="libwxpng.a" />
<Add library="libwxzlib.a" />
- <Add library="libboost_thread-mgw46-mt-s-1_49.a" />
- <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" />
+ <Add library="libboost_thread-mgw47-mt-s-1_50.a" />
+ <Add library="libboost_system-mgw47-mt-s-1_50.a" />
+ <Add library="libboost_chrono-mgw47-mt-s-1_50.a" />
+ <Add directory="C:\Programme\C++\wxWidgets\lib\mingw_release_lib" />
</Linker>
<ExtraCommands>
<Add after='&quot;C:\Program Files\C++\CodeSigning\SignCode.cmd&quot; &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot;' />
@@ -46,7 +48,7 @@
<Add option="-Winvalid-pch" />
<Add option='-include &quot;../wx+/pch.h&quot;' />
<Add option="-D__WXDEBUG__" />
- <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll\mswud" />
+ <Add directory="C:\Program Files\C++\wxWidgets\lib\mingw_debug_dll\mswud" />
</Compiler>
<Linker>
<Add library="libwxmsw28ud_core.a" />
@@ -54,8 +56,10 @@
<Add library="libwxbase28ud.a" />
<Add library="libwxpngd.a" />
<Add library="libwxzlibd.a" />
- <Add library="libboost_thread-mgw46-mt-sd-1_49.a" />
- <Add directory="C:\Program Files\C++\wxWidgets\lib\gcc_dll" />
+ <Add library="libboost_thread-mgw47-mt-sd-1_50.a" />
+ <Add library="libboost_system-mgw47-mt-sd-1_50.a" />
+ <Add library="libboost_chrono-mgw47-mt-sd-1_50.a" />
+ <Add directory="C:\Program Files\C++\wxWidgets\lib\mingw_debug_dll" />
</Linker>
</Target>
</Build>
diff --git a/RealtimeSync/RealtimeSync.vcxproj b/RealtimeSync/RealtimeSync.vcxproj
index 8a062159..e652bedd 100644
--- a/RealtimeSync/RealtimeSync.vcxproj
+++ b/RealtimeSync/RealtimeSync.vcxproj
@@ -35,7 +35,7 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v110</PlatformToolset>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@@ -101,7 +101,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_dll\mswud;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x86_debug_dll\mswud;..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -115,7 +115,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxbase28ud.lib;wxpngd.lib;wxzlibd.lib;wxbase28ud_net.lib;comctl32.lib;ws2_32.lib;Rpcrt4.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets\lib\vc_dll;C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x86_debug_dll</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -128,7 +128,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;__WXDEBUG__;WXUSINGDLL</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include;C:\Program Files\C++\wxWidgets-x64-VC11\lib\vc_dll\mswud;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x64_debug_dll\mswud;..</AdditionalIncludeDirectories>
<PrecompiledHeaderFile>wx+/pch.h</PrecompiledHeaderFile>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -143,12 +143,12 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxbase28ud.lib;wxpngd.lib;wxzlibd.lib;wxbase28ud_net.lib;comctl32.lib;ws2_32.lib;Rpcrt4.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\lib\vc_dll;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x64_debug_dll</AdditionalLibraryDirectories>
<LinkStatus>
</LinkStatus>
</Link>
<ResourceCompile>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
@@ -159,7 +159,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc_lib\mswu;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x86_release_lib\mswu;..</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -173,7 +173,7 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wxbase28u.lib;wxmsw28u_adv.lib;wxmsw28u_core.lib;wxpng.lib;wxzlib.lib;wxbase28u_net.lib;comctl32.lib;ws2_32.lib;winmm.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets\lib\vc_lib;C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x86_release_lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
@@ -190,7 +190,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;ZEN_PLATFORM_WINDOWS;wxUSE_UNICODE;__WXMSW__;FFS_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64\include;C:\Program Files\C++\wxWidgets-x64\lib\vc_lib\mswu;C:\Program Files\C++\Boost;..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\Boost;C:\Program Files\C++\wxWidgets\include;C:\Program Files\C++\wxWidgets\lib\vc10_x64_release_lib\mswu;..</AdditionalIncludeDirectories>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4512</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -204,10 +204,10 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>wxmsw28u_adv.lib;wxmsw28u_core.lib;wxbase28u.lib;wxpng.lib;wxzlib.lib;wxbase28u_net.lib;comctl32.lib;ws2_32.lib;winmm.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
- <AdditionalLibraryDirectories>C:\Program Files\C++\wxWidgets-x64\lib\vc_lib;C:\Program Files\C++\Boost\stage64\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib;C:\Program Files\C++\wxWidgets\lib\vc10_x64_release_lib</AdditionalLibraryDirectories>
</Link>
<ResourceCompile>
- <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets-x64-VC11\include</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>C:\Program Files\C++\wxWidgets\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);WX_CPU_AMD64</PreprocessorDefinitions>
</ResourceCompile>
<PostBuildEvent>
@@ -223,6 +223,10 @@
<ClCompile Include="..\ui\dir_name.cpp" />
<ClCompile Include="..\ui\folder_history_box.cpp" />
<ClCompile Include="..\wx+\button.cpp" />
+ <ClCompile Include="..\wx+\create_pch.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ </ClCompile>
<ClCompile Include="..\wx+\format_unit.cpp" />
<ClCompile Include="..\wx+\mouse_move_dlg.cpp" />
<ClCompile Include="..\zen\dir_watcher.cpp" />
@@ -234,8 +238,8 @@
<ClCompile Include="..\zen\privilege.cpp" />
<ClCompile Include="..\zen\zstring.cpp" />
<ClCompile Include="application.cpp">
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Use</PrecompiledHeader>
</ClCompile>
<ClCompile Include="gui_generated.cpp" />
<ClCompile Include="main_dlg.cpp" />
diff --git a/RealtimeSync/application.cpp b/RealtimeSync/application.cpp
index e756675e..b136b720 100644
--- a/RealtimeSync/application.cpp
+++ b/RealtimeSync/application.cpp
@@ -7,15 +7,15 @@
#include "application.h"
#include "main_dlg.h"
#include <wx/event.h>
-#include "resources.h"
+#include <wx/log.h>
#include <wx/msgdlg.h>
-#include "../lib/localization.h"
-#include "xml_ffs.h"
-#include "../lib/ffs_paths.h"
-#include <wx/file.h>
+#include <wx+/serialize.h>
#include <wx+/string_conv.h>
-#include <wx/log.h>
#include <zen/file_handling.h>
+#include "resources.h"
+#include "xml_ffs.h"
+#include "../lib/localization.h"
+#include "../lib/ffs_paths.h"
#ifdef FFS_LINUX
#include <gtk/gtk.h>
@@ -97,27 +97,31 @@ bool Application::OnExceptionInMainLoop()
int Application::OnRun()
{
+
+ auto processException = [](const std::wstring& msg)
+ {
+ //it's not always possible to display a message box, e.g. corrupted stack, however low-level file output works!
+ try
+ {
+ saveBinStream(getConfigDir() + Zstr("LastError.txt"), utfCvrtTo<std::string>(msg)); //throw FileError
+ }
+ catch (const FileError&) {}
+
+ wxSafeShowMessage(_("An exception occurred!") + L" - FFS", msg);
+ };
+
try
{
wxApp::OnRun();
}
catch (const std::exception& e) //catch all STL exceptions
{
- //it's not always possible to display a message box, e.g. corrupted stack, however (non-stream) file output works!
- wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write);
- safeOutput.Write(utfCvrtTo<wxString>(e.what()));
-
- wxSafeShowMessage(_("An exception occurred!") + L" - RTS", utfCvrtTo<wxString>(e.what()));
+ processException(utfCvrtTo<std::wstring>(e.what()));
return -9;
}
catch (...) //catch the rest
{
- const wxString& msg = L"Unknown error.";
-
- wxFile safeOutput(toWx(getConfigDir()) + L"LastError.txt", wxFile::write);
- safeOutput.Write(msg);
-
- wxSafeShowMessage(_("An exception occurred!"), msg);
+ processException(L"Unknown error.");
return -9;
}
diff --git a/RealtimeSync/gui_generated.cpp b/RealtimeSync/gui_generated.cpp
index 8d656e74..645249fe 100644
--- a/RealtimeSync/gui_generated.cpp
+++ b/RealtimeSync/gui_generated.cpp
@@ -20,7 +20,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_menuFile->Append( m_menuItem13 );
wxMenuItem* m_menuItem14;
- m_menuItem14 = new wxMenuItem( m_menuFile, wxID_SAVE, wxString( _("&Save...") ) + wxT('\t') + wxT("CTRL+S"), wxEmptyString, wxITEM_NORMAL );
+ m_menuItem14 = new wxMenuItem( m_menuFile, wxID_SAVEAS, wxString( _("Save &As...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuFile->Append( m_menuItem14 );
m_menuFile->AppendSeparator();
@@ -190,8 +190,8 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDlgGenerated::OnClose ) );
- this->Connect( m_menuItem13->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnLoadConfig ) );
- this->Connect( m_menuItem14->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnSaveConfig ) );
+ 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::OnQuit ) );
this->Connect( m_menuItemContent->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnShowHelp ) );
this->Connect( m_menuItemAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuAbout ) );
@@ -205,8 +205,8 @@ MainDlgGenerated::~MainDlgGenerated()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDlgGenerated::OnClose ) );
- this->Disconnect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnLoadConfig ) );
- this->Disconnect( wxID_SAVE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnSaveConfig ) );
+ this->Disconnect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigLoad ) );
+ this->Disconnect( wxID_SAVEAS, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnConfigSave ) );
this->Disconnect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnQuit ) );
this->Disconnect( wxID_HELP, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnShowHelp ) );
this->Disconnect( wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuAbout ) );
diff --git a/RealtimeSync/gui_generated.h b/RealtimeSync/gui_generated.h
index 50ffea2b..2afd5244 100644
--- a/RealtimeSync/gui_generated.h
+++ b/RealtimeSync/gui_generated.h
@@ -75,8 +75,8 @@ protected:
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
- virtual void OnLoadConfig( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSaveConfig( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnConfigLoad( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnConfigSave( wxCommandEvent& event ) { event.Skip(); }
virtual void OnQuit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnShowHelp( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuAbout( wxCommandEvent& event ) { event.Skip(); }
diff --git a/RealtimeSync/main_dlg.cpp b/RealtimeSync/main_dlg.cpp
index 40852056..7eb3be59 100644
--- a/RealtimeSync/main_dlg.cpp
+++ b/RealtimeSync/main_dlg.cpp
@@ -173,7 +173,7 @@ void MainDialog::OnStart(wxCommandEvent& event)
}
-void MainDialog::OnSaveConfig(wxCommandEvent& event)
+void MainDialog::OnConfigSave(wxCommandEvent& event)
{
wxString defaultFileName = currentConfigFileName.empty() ? L"Realtime.ffs_real" : currentConfigFileName;
//attention: currentConfigFileName may be an imported *.ffs_batch file! We don't want to overwrite it with a GUI config!
@@ -243,7 +243,7 @@ void MainDialog::setLastUsedConfig(const wxString& filename)
}
-void MainDialog::OnLoadConfig(wxCommandEvent& event)
+void MainDialog::OnConfigLoad(wxCommandEvent& event)
{
wxFileDialog filePicker(this, wxEmptyString, wxEmptyString, wxEmptyString,
wxString(L"RealtimeSync (*.ffs_real;*.ffs_batch)|*.ffs_real;*.ffs_batch") + L"|" +_("All files") + L" (*.*)|*",
diff --git a/RealtimeSync/main_dlg.h b/RealtimeSync/main_dlg.h
index edc66c47..50b90cc7 100644
--- a/RealtimeSync/main_dlg.h
+++ b/RealtimeSync/main_dlg.h
@@ -53,8 +53,8 @@ private:
virtual void OnRemoveTopFolder(wxCommandEvent& event);
virtual void OnKeyPressed (wxKeyEvent& event);
virtual void OnStart (wxCommandEvent& event);
- virtual void OnSaveConfig (wxCommandEvent& event);
- virtual void OnLoadConfig (wxCommandEvent& event);
+ virtual void OnConfigSave (wxCommandEvent& event);
+ virtual void OnConfigLoad (wxCommandEvent& event);
void setConfiguration(const xmlAccess::XmlRealConfig& cfg);
xmlAccess::XmlRealConfig getConfiguration();
diff --git a/RealtimeSync/makefile b/RealtimeSync/makefile
index 9f0ae16a..84f617f6 100644
--- a/RealtimeSync/makefile
+++ b/RealtimeSync/makefile
@@ -7,12 +7,12 @@ COMMON_LINK_FLAGS = -pthread -lrt
#default build
CPPFLAGS = $(COMMON_COMPILE_FLAGS) `wx-config --cxxflags --debug=no --unicode=yes`
-LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs --debug=no --unicode=yes` -lboost_thread
+LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs --debug=no --unicode=yes` -lboost_thread -lboost_system
#static std library linkage used for precompiled release
ifeq ($(BUILD),release)
CPPFLAGS = $(COMMON_COMPILE_FLAGS) `wx-config --cxxflags --debug=no --unicode=yes --static=yes`
-LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs --debug=no --unicode=yes --static=yes` /usr/local/lib/libboost_thread.a
+LINKFLAGS = $(COMMON_LINK_FLAGS) `wx-config --libs --debug=no --unicode=yes --static=yes` /usr/local/lib/libboost_thread.a /usr/local/lib/libboost_system.a
endif
#####################################################################################################
diff --git a/RealtimeSync/resource.rc b/RealtimeSync/resource.rc
index bad326e1..8716dabd 100644
--- a/RealtimeSync/resource.rc
+++ b/RealtimeSync/resource.rc
@@ -1,9 +1,16 @@
#define IDR_VERSION1 1
-#include "Winver.h"
-#include "wx/msw/wx.rc"
+#include <Winver.h>
#include "../version/version.rc"
+//beginning with VC11 we get linking error "CVTRES : fatal error CVT1100: duplicate resource. type:MANIFEST, name:1, language:0x0409"
+//due to "#define wxMANIFEST_ID 1" in wx.rc. Using another number doesn't integrate the manifest correctly for VC2010 compilers.
+//However tests indicate we do not need this manifest at all:
+//#define wxUSE_NO_MANIFEST 1 //VC11 screws up if not set to an integer, unbelievable
+//we can't #ifdef _MSC_VER: not known by resource compiler!
+//see also: http://blog.m-ri.de/index.php/2010/11/26/combobox-dropdown-hoehe-wird-nicht-mehr-durch-die-ressourcen-definiert/
+#include <wx/msw/wx.rc>
+
A_PROGRAM_ICON ICON DISCARDABLE "RealtimeSync.ico"
IDR_VERSION1 VERSIONINFO
diff --git a/RealtimeSync/tray_menu.cpp b/RealtimeSync/tray_menu.cpp
index 942a6100..1a3898d6 100644
--- a/RealtimeSync/tray_menu.cpp
+++ b/RealtimeSync/tray_menu.cpp
@@ -333,7 +333,7 @@ rts::AbortReason rts::startDirectoryMonitor(const xmlAccess::XmlRealConfig& conf
}
if (dirList.empty() || std::any_of(dirList.begin(), dirList.end(), [](Zstring str) -> bool { trim(str); return str.empty(); }))
{
- wxMessageBox(_("An input folder name is empty."), _("Error"), wxOK | wxICON_ERROR);
+ wxMessageBox(_("A folder input field is empty."), _("Error"), wxOK | wxICON_ERROR);
return SHOW_GUI;
}
diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp
index 301c9c64..a0893382 100644
--- a/RealtimeSync/watcher.cpp
+++ b/RealtimeSync/watcher.cpp
@@ -60,7 +60,7 @@ rts::WaitResult rts::waitForChanges(const std::vector<Zstring>& dirNamesNonFmt,
{
const std::vector<Zstring> dirNamesFmt = getFormattedDirs(dirNamesNonFmt); //throw FileError
if (dirNamesFmt.empty()) //pathological case, but check is needed nevertheless
- throw zen::FileError(_("An input folder name is empty.")); //should have been checked by caller!
+ throw zen::FileError(_("A folder input field is empty.")); //should have been checked by caller!
//detect when volumes are removed/are not available anymore
std::vector<std::pair<Zstring, std::shared_ptr<DirWatcher>>> watches;
diff --git a/algorithm.cpp b/algorithm.cpp
index 771fcaea..6de28baa 100644
--- a/algorithm.cpp
+++ b/algorithm.cpp
@@ -14,7 +14,6 @@
#include <zen/recycler.h>
#include <wx/msgdlg.h>
#include "lib/norm_filter.h"
-#include <wx+/string_conv.h>
#include "lib/db_file.h"
#include <zen/scope_guard.h>
#include "lib/cmp_filetime.h"
@@ -31,8 +30,10 @@ void zen::swapGrids(const MainConfiguration& config, FolderComparison& folderCmp
redetermineSyncDirection(config, folderCmp, [](const std::wstring&) {});
}
-
//----------------------------------------------------------------------------------------------
+
+namespace
+{
class Redetermine
{
public:
@@ -77,17 +78,15 @@ private:
fileObj.setSyncDir(dirCfg.different);
break;
case FILE_CONFLICT:
+ case FILE_DIFFERENT_METADATA: //use setting from "conflict/cannot categorize"
if (dirCfg.conflict == SYNC_DIR_NONE)
- fileObj.setSyncDirConflict(fileObj.getCatConflict()); //take over category conflict
+ fileObj.setSyncDirConflict(getCategoryDescription(fileObj)); //take over category conflict
else
fileObj.setSyncDir(dirCfg.conflict);
break;
case FILE_EQUAL:
fileObj.setSyncDir(SYNC_DIR_NONE);
break;
- case FILE_DIFFERENT_METADATA:
- fileObj.setSyncDir(dirCfg.conflict); //use setting from "conflict/cannot categorize"
- break;
}
}
@@ -108,8 +107,9 @@ private:
linkObj.setSyncDir(dirCfg.rightNewer);
break;
case SYMLINK_CONFLICT:
+ case SYMLINK_DIFFERENT_METADATA: //use setting from "conflict/cannot categorize"
if (dirCfg.conflict == SYNC_DIR_NONE)
- linkObj.setSyncDirConflict(linkObj.getCatConflict()); //take over category conflict
+ linkObj.setSyncDirConflict(getCategoryDescription(linkObj)); //take over category conflict
else
linkObj.setSyncDir(dirCfg.conflict);
break;
@@ -119,10 +119,6 @@ private:
case SYMLINK_EQUAL:
linkObj.setSyncDir(SYNC_DIR_NONE);
break;
- case SYMLINK_DIFFERENT_METADATA:
- linkObj.setSyncDir(dirCfg.conflict); //use setting from "conflict/cannot categorize"
- break;
-
}
}
@@ -139,8 +135,11 @@ private:
case DIR_EQUAL:
dirObj.setSyncDir(SYNC_DIR_NONE);
break;
- case DIR_DIFFERENT_METADATA:
- dirObj.setSyncDir(dirCfg.conflict); //use setting from "conflict/cannot categorize"
+ case DIR_DIFFERENT_METADATA: //use setting from "conflict/cannot categorize"
+ if (dirCfg.conflict == SYNC_DIR_NONE)
+ dirObj.setSyncDirConflict(getCategoryDescription(dirObj)); //take over category conflict
+ else
+ dirObj.setSyncDir(dirCfg.conflict);
break;
}
@@ -171,210 +170,137 @@ struct AllEqual //test if non-equal items exist in scanned data
}); //directories
}
};
-
+}
bool zen::allElementsEqual(const FolderComparison& folderCmp)
{
return std::all_of(begin(folderCmp), end(folderCmp), AllEqual());
}
-//---------------------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------------------
-class DataSetFile
+namespace
{
-public:
- DataSetFile() {}
+template <SelectedSide side> inline
+const FileDescriptor& getDescriptor(const InSyncFile& dbFile) { return dbFile.left; }
- DataSetFile(const Zstring& name, const FileDescriptor& fileDescr)
- {
- shortName = name;
- lastWriteTime = fileDescr.lastWriteTimeRaw;
- fileSize = fileDescr.fileSize;
- }
+template <> inline
+const FileDescriptor& getDescriptor<RIGHT_SIDE>(const InSyncFile& dbFile) { return dbFile.right; }
- DataSetFile(const FileMapping& fileObj, Int2Type<LEFT_SIDE>)
- {
- init<LEFT_SIDE>(fileObj);
- }
- DataSetFile(const FileMapping& fileObj, Int2Type<RIGHT_SIDE>)
- {
- init<RIGHT_SIDE>(fileObj);
- }
+//check whether database entry and current item match: *irrespective* of current comparison settings
+template <SelectedSide side> inline
+bool isEqual(const FileMapping& fileObj, const InSyncDir::FileList::value_type* dbFile)
+{
+ if (fileObj.isEmpty<side>())
+ return !dbFile;
+ else if (!dbFile)
+ return false;
+
+ const Zstring& shortNameDb = dbFile->first;
+ const FileDescriptor& descrDb = getDescriptor<side>(dbFile->second);
+
+ return fileObj.getShortName<side>() == shortNameDb && //detect changes in case (windows)
+ //respect 2 second FAT/FAT32 precision! copying a file to a FAT32 drive changes it's modification date by up to 2 seconds
+ sameFileTime(fileObj.getLastWriteTime<side>(), descrDb.lastWriteTimeRaw, 2) &&
+ fileObj.getFileSize<side>() == descrDb.fileSize;
+ //note: we do *not* consider FileId here, but are only interested in *visual* changes. Consider user moving data to some other medium, this is not a change!
+}
- inline friend
- bool operator==(const DataSetFile& lhs, const DataSetFile& rhs)
- {
- if (lhs.shortName.empty())
- return rhs.shortName.empty();
- else if (rhs.shortName.empty())
- return false;
-
- return lhs.shortName == rhs.shortName && //detect changes in case (windows)
- //respect 2 second FAT/FAT32 precision! copying a file to a FAT32 drive changes it's modification date by up to 2 seconds
- sameFileTime(lhs.lastWriteTime, rhs.lastWriteTime, 2) &&
- lhs.fileSize == rhs.fileSize;
- }
-private:
- template <SelectedSide side>
- void init(const FileMapping& fileObj)
- {
- if (!fileObj.isEmpty<side>())
- {
- shortName = fileObj.getShortName<side>();
- lastWriteTime = fileObj.getLastWriteTime<side>();
- fileSize = fileObj.getFileSize<side>();
- }
+//check whether database entry is in sync considering *current* comparison settings
+inline
+bool stillInSync(const InSyncFile& dbFile, CompareVariant compareVar, size_t fileTimeTolerance)
+{
+ switch (compareVar)
+ {
+ case CMP_BY_TIME_SIZE:
+ return dbFile.inSyncType == InSyncFile::IN_SYNC_BINARY_EQUAL || //special rule: this is already "good enough" for CMP_BY_TIME_SIZE!
+ //case-sensitive short name match is a database invariant!
+ (CmpFileTime::getResult(dbFile.left.lastWriteTimeRaw, dbFile.right.lastWriteTimeRaw, fileTimeTolerance) == CmpFileTime::TIME_EQUAL &&
+ dbFile.left.fileSize == dbFile.right.fileSize);
+
+ case CMP_BY_CONTENT:
+ //case-sensitive short name match is a database invariant!
+ return dbFile.inSyncType == InSyncFile::IN_SYNC_BINARY_EQUAL;
+ //in contrast to comparison, we don't care about modification time here!
}
+ assert(false);
+ return false;
+}
- Zstring shortName; //empty if object not existing
- zen::Int64 lastWriteTime;
- zen::UInt64 fileSize;
-
- //note: we do *not* consider FileId here, but are only interested in *visual* changes. Consider user moving data to some other medium, this is not a change!
-};
+//--------------------------------------------------------------------
+template <SelectedSide side> inline
+const LinkDescriptor& getDescriptor(const InSyncSymlink& dbLink) { return dbLink.left; }
-//--------------------------------------------------------------------
-class DataSetSymlink
-{
-public:
- DataSetSymlink()
-#ifdef FFS_WIN
- : type(LinkDescriptor::TYPE_FILE) //dummy value
-#endif
- {}
+template <> inline
+const LinkDescriptor& getDescriptor<RIGHT_SIDE>(const InSyncSymlink& dbLink) { return dbLink.right; }
- DataSetSymlink(const Zstring& name, const LinkDescriptor& linkDescr)
- {
- shortName = name;
- lastWriteTime = linkDescr.lastWriteTimeRaw;
- targetPath = linkDescr.targetPath;
-#ifdef FFS_WIN //type of symbolic link is relevant for Windows only
- type = linkDescr.type;
-#endif
- }
- DataSetSymlink(const SymLinkMapping& linkObj, Int2Type<LEFT_SIDE>)
- {
- init<LEFT_SIDE>(linkObj);
- }
+//check whether database entry and current item match: *irrespective* of current comparison settings
+template <SelectedSide side> inline
+bool isEqual(const SymLinkMapping& linkObj, const InSyncDir::LinkList::value_type* dbLink)
+{
+ if (linkObj.isEmpty<side>())
+ return !dbLink;
+ else if (!dbLink)
+ return false;
- DataSetSymlink(const SymLinkMapping& linkObj, Int2Type<RIGHT_SIDE>)
- {
- init<RIGHT_SIDE>(linkObj);
- }
+ const Zstring& shortNameDb = dbLink->first;
+ const LinkDescriptor& descrDb = getDescriptor<side>(dbLink->second);
- inline friend
- bool operator==(const DataSetSymlink& lhs, const DataSetSymlink& rhs)
- {
- if (lhs.shortName.empty()) //test if object is existing at all
- return rhs.shortName.empty();
- else if (rhs.shortName.empty())
- return false;
-
- return lhs.shortName == rhs.shortName &&
- //respect 2 second FAT/FAT32 precision! copying a file to a FAT32 drive changes it's modification date by up to 2 seconds
- sameFileTime(lhs.lastWriteTime, rhs.lastWriteTime, 2) &&
+ return linkObj.getShortName<side>() == shortNameDb &&
+ //respect 2 second FAT/FAT32 precision! copying a file to a FAT32 drive changes it's modification date by up to 2 seconds
+ sameFileTime(linkObj.getLastWriteTime<side>(), descrDb.lastWriteTimeRaw, 2) &&
#ifdef FFS_WIN //comparison of symbolic link type is relevant for Windows only
- lhs.type == rhs.type &&
+ linkObj.getLinkType<side>() == descrDb.type &&
#endif
- lhs.targetPath == rhs.targetPath;
- }
+ linkObj.getTargetPath<side>() == descrDb.targetPath;
+}
-private:
- template <SelectedSide side>
- void init(const SymLinkMapping& linkObj)
- {
-#ifdef FFS_WIN
- type = LinkDescriptor::TYPE_FILE; //always initialize
-#endif
- if (!linkObj.isEmpty<side>())
- {
- shortName = linkObj.getShortName<side>();
- lastWriteTime = linkObj.getLastWriteTime<side>();
- targetPath = linkObj.getTargetPath<side>();
+//check whether database entry is in sync considering *current* comparison settings
+inline
+bool stillInSync(const InSyncSymlink& dbLink, CompareVariant compareVar)
+{
+ return !dbLink.left .targetPath.empty() && //if one of these is empty, we can't make a statement whether both sides are in sync
+ !dbLink.right.targetPath.empty() && //
#ifdef FFS_WIN //type of symbolic link is relevant for Windows only
- type = linkObj.getLinkType<side>();
+ dbLink.left.type == dbLink.right.type &&
#endif
- }
- }
+ dbLink.left.targetPath == dbLink.right.targetPath;
+ //case-sensitive short name match is a database invariant!
+ //in contrast to comparison, we don't care about modification time!
+}
- Zstring shortName; //empty if object not existing
- zen::Int64 lastWriteTime;
- Zstring targetPath;
-#ifdef FFS_WIN
- LinkDescriptor::LinkType type;
-#endif
-};
//--------------------------------------------------------------------
-
-class DataSetDir
+//check whether database entry and current item match: *irrespective* of current comparison settings
+template <SelectedSide side> inline
+bool isEqual(const DirMapping& dirObj, const InSyncDir::DirList::value_type* dbDir)
{
-public:
- DataSetDir() {}
-
- DataSetDir(const Zstring& name) :
- shortName(name) {}
+ if (dirObj.isEmpty<side>())
+ return !dbDir || dbDir->second.status == InSyncDir::STATUS_STRAW_MAN;
+ else if (!dbDir || dbDir->second.status == InSyncDir::STATUS_STRAW_MAN)
+ return false;
- DataSetDir(const DirMapping& dirObj, Int2Type<LEFT_SIDE>) :
- shortName(dirObj.getShortName<LEFT_SIDE>()) {}
+ const Zstring& shortNameDb = dbDir->first;
- DataSetDir(const DirMapping& dirObj, Int2Type<RIGHT_SIDE>) :
- shortName(dirObj.getShortName<RIGHT_SIDE>()) {}
-
- inline friend
- bool operator==(const DataSetDir& lhs, const DataSetDir& rhs)
- {
- return lhs.shortName == rhs.shortName;
- }
-
-private:
- Zstring shortName; //empty if object not existing
-};
-//--------------------------------------------------------------------------------------------------------
-
-DataSetFile retrieveDataSetFile(const Zstring& objShortName, const DirContainer* dbDirectory)
-{
- if (dbDirectory)
- {
- DirContainer::FileList::const_iterator iter = dbDirectory->files.find(objShortName);
- if (iter != dbDirectory->files.end())
- return DataSetFile(iter->first, iter->second);
- }
-
- return DataSetFile(); //object not found
-}
-
-DataSetSymlink retrieveDataSetSymlink(const Zstring& objShortName, const DirContainer* dbDirectory)
-{
- if (dbDirectory)
- {
- DirContainer::LinkList::const_iterator iter = dbDirectory->links.find(objShortName);
- if (iter != dbDirectory->links.end())
- return DataSetSymlink(iter->first, iter->second);
- }
-
- return DataSetSymlink(); //object not found
+ return dirObj.getShortName<side>() == shortNameDb;
}
-std::pair<DataSetDir, const DirContainer*> retrieveDataSetDir(const Zstring& objShortName, const DirContainer* dbDirectory)
+inline
+bool stillInSync(const InSyncDir& dbDir)
{
- if (dbDirectory)
- {
- DirContainer::DirList::const_iterator iter = dbDirectory->dirs.find(objShortName);
- if (iter != dbDirectory->dirs.end())
- return std::make_pair(DataSetDir(iter->first), &iter->second);
- }
-
- return std::make_pair(DataSetDir(), nullptr); //object not found
+ //case-sensitive short name match is a database invariant!
+ //InSyncDir::STATUS_STRAW_MAN considered
+ return true;
}
//----------------------------------------------------------------------------------------------
+
class RedetermineAuto
{
public:
@@ -387,17 +313,17 @@ private:
RedetermineAuto(BaseDirMapping& baseDirectory, std::function<void(const std::wstring&)> reportWarning) :
txtBothSidesChanged(_("Both sides have changed since last synchronization!")),
txtNoSideChanged(_("Cannot determine sync-direction:") + L" \n" + _("No change since last synchronization!")),
- txtFilterChanged(_("Cannot determine sync-direction:") + L" \n" + _("Filter settings have changed!")),
- txtLastSyncFail (_("Cannot determine sync-direction:") + L" \n" + _("The file was not processed by last synchronization!")),
+ txtDbNotInSync(_("Cannot determine sync-direction:") + L" \n" + _("The corresponding database entries are not in sync considering current settings.")),
+ cmpVar(baseDirectory.getCompVariant()),
+ fileTimeTolerance(baseDirectory.getFileTimeTolerance()),
reportWarning_(reportWarning)
{
if (AllEqual()(baseDirectory)) //nothing to do: abort and don't show any nag-screens
return;
//try to load sync-database files
- std::pair<DirInfoPtr, DirInfoPtr> dirInfo = loadDBFile(baseDirectory);
- if (dirInfo.first.get() == nullptr ||
- dirInfo.second.get() == nullptr)
+ std::shared_ptr<InSyncDir> lastSyncState = loadDBFile(baseDirectory);
+ if (!lastSyncState)
{
//set conservative "two-way" directions
DirectionSet twoWayCfg = getTwoWaySet();
@@ -406,48 +332,24 @@ private:
return;
}
- const DirInformation& dirInfoLeft = *dirInfo.first;
- const DirInformation& dirInfoRight = *dirInfo.second;
-
//-> considering filter not relevant:
//if narrowing filter: all ok; if widening filter (if file ex on both sides -> conflict, fine; if file ex. on one side: copy to other side: fine)
- /*
- //save db filter (if it needs to be considered only):
- if (respectFiltering(baseDirectory, dirInfoLeft))
- dbFilterLeft = dirInfoLeft.filter.get();
-
- if (respectFiltering(baseDirectory, dirInfoRight))
- dbFilterRight = dirInfoRight.filter.get();
- */
- recurse(baseDirectory,
- &dirInfoLeft.baseDirContainer,
- &dirInfoRight.baseDirContainer);
+
+ recurse(baseDirectory, &*lastSyncState);
//----------- detect renamed files -----------------
if (!exLeftOnly.empty() && !exRightOnly.empty())
{
- findEqualDbEntries(dirInfoLeft .baseDirContainer, //fill map "onceEqual"
- dirInfoRight.baseDirContainer);
-
+ collectEqualDbEntries(*lastSyncState); //fill map "onceEqual"
detectRenamedFiles();
}
}
- /*
- static bool respectFiltering(const BaseDirMapping& baseDirectory, const DirInformation& dirInfo)
- {
- //respect filtering if sync-DB filter is active && different from baseDir's filter:
- // in all other cases "view on files" is smaller for baseDirectory(current) than it was for dirInfo(old)
- // => dirInfo can be queried as if it were a scan without filters
- return !dirInfo.filter->isNull() && *dirInfo.filter != *baseDirectory.getFilter();
- }
- */
-
- std::pair<DirInfoPtr, DirInfoPtr> loadDBFile(const BaseDirMapping& baseDirectory) //return nullptr on failure
+ std::shared_ptr<InSyncDir> loadDBFile(const BaseDirMapping& baseMap) //return nullptr on failure
{
try
{
- return loadFromDisk(baseDirectory);
+ return loadLastSynchronousState(baseMap); //throw FileError, FileErrorDatabaseNotExisting
}
catch (FileErrorDatabaseNotExisting&) {} //let's ignore these errors for now...
catch (FileError& error) //e.g. incompatible database version
@@ -455,43 +357,17 @@ private:
reportWarning_(error.toString() + L" \n\n" +
_("Setting default synchronization directions: Old files will be overwritten with newer files."));
}
- return std::pair<DirInfoPtr, DirInfoPtr>();
+ return nullptr;
}
- /*
- bool filterFileConflictFound(const Zstring& relativeName) const
- {
- //if filtering would have excluded file during database creation, then we can't say anything about its former state
- return (dbFilterLeft && !dbFilterLeft ->passFileFilter(relativeName)) ||
- (dbFilterRight && !dbFilterRight->passFileFilter(relativeName));
- }
-
-
- bool filterDirConflictFound(const Zstring& relativeName) const
- {
- //if filtering would have excluded directory during database creation, then we can't say anything about its former state
- return (dbFilterLeft && !dbFilterLeft ->passDirFilter(relativeName, nullptr)) ||
- (dbFilterRight && !dbFilterRight->passDirFilter(relativeName, nullptr));
- }
- */
-
- void recurse(HierarchyObject& hierObj,
- const DirContainer* dbDirectoryLeft,
- const DirContainer* dbDirectoryRight)
+ void recurse(HierarchyObject& hierObj, const InSyncDir* dbContainer)
{
- std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(),
- [&](FileMapping& fileMap) { processFile(fileMap, dbDirectoryLeft, dbDirectoryRight); });
-
- std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(),
- [&](SymLinkMapping& linkMap) { processSymlink(linkMap, dbDirectoryLeft, dbDirectoryRight); });
-
- std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(),
- [&](DirMapping& dirMap) { processDir(dirMap, dbDirectoryLeft, dbDirectoryRight); });
+ std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](FileMapping& fileMap) { processFile (fileMap, dbContainer); });
+ std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](SymLinkMapping& linkMap) { processSymlink(linkMap, dbContainer); });
+ std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](DirMapping& dirMap) { processDir (dirMap, dbContainer); });
}
- void processFile(FileMapping& fileObj,
- const DirContainer* dbDirectoryLeft,
- const DirContainer* dbDirectoryRight)
+ void processFile(FileMapping& fileObj, const InSyncDir* dbContainer)
{
const CompareFilesResult cat = fileObj.getCategory();
if (cat == FILE_EQUAL)
@@ -511,245 +387,138 @@ private:
//----------------------------------------------------------------------
//##################### schedule old temporary files for deletion ####################
- if (cat == FILE_LEFT_SIDE_ONLY && endsWith(fileObj.getShortName<LEFT_SIDE>(), zen::TEMP_FILE_ENDING))
+ if (cat == FILE_LEFT_SIDE_ONLY && endsWith(fileObj.getShortName<LEFT_SIDE>(), TEMP_FILE_ENDING))
{
fileObj.setSyncDir(SYNC_DIR_LEFT);
return;
}
- else if (cat == FILE_RIGHT_SIDE_ONLY && endsWith(fileObj.getShortName<RIGHT_SIDE>(), zen::TEMP_FILE_ENDING))
+ else if (cat == FILE_RIGHT_SIDE_ONLY && endsWith(fileObj.getShortName<RIGHT_SIDE>(), TEMP_FILE_ENDING))
{
fileObj.setSyncDir(SYNC_DIR_RIGHT);
return;
}
//####################################################################################
- /*
- if (filterFileConflictFound(fileObj.getObjRelativeName()))
- {
- if (cat == FILE_LEFT_SIDE_ONLY)
- fileObj.setSyncDir(SYNC_DIR_RIGHT);
- else if (cat == FILE_RIGHT_SIDE_ONLY)
- fileObj.setSyncDir(SYNC_DIR_LEFT);
- else
- fileObj.setSyncDirConflict(txtFilterChanged);
- return;
- }
- */
-
- //determine datasets for change detection
- const DataSetFile dataDbLeft = retrieveDataSetFile(fileObj.getObjShortName(), dbDirectoryLeft);
- const DataSetFile dataDbRight = retrieveDataSetFile(fileObj.getObjShortName(), dbDirectoryRight);
-
- const DataSetFile dataCurrentLeft (fileObj, Int2Type<LEFT_SIDE >());
- const DataSetFile dataCurrentRight(fileObj, Int2Type<RIGHT_SIDE>());
+ //try to find corresponding database entry
+ const InSyncDir::FileList::value_type* dbEntry = nullptr;
+ if (dbContainer)
+ {
+ auto iter = dbContainer->files.find(fileObj.getObjShortName());
+ if (iter != dbContainer->files.end())
+ dbEntry = &*iter;
+ }
//evaluation
- const bool changeOnLeft = dataDbLeft != dataCurrentLeft;
- const bool changeOnRight = dataDbRight != dataCurrentRight;
+ const bool changeOnLeft = !isEqual<LEFT_SIDE >(fileObj, dbEntry);
+ const bool changeOnRight = !isEqual<RIGHT_SIDE>(fileObj, dbEntry);
- if (dataDbLeft == dataDbRight) //we have a "last synchronous state" => last sync seems to have been successful
+ if (changeOnLeft != changeOnRight)
{
- if (changeOnLeft)
- {
- if (changeOnRight)
- fileObj.setSyncDirConflict(txtBothSidesChanged);
- else
- fileObj.setSyncDir(SYNC_DIR_RIGHT);
- }
+ //if database entry not in sync according to current settings! -> do not set direction based on async status!
+ if (dbEntry && !stillInSync(dbEntry->second, cmpVar, fileTimeTolerance))
+ fileObj.setSyncDirConflict(txtDbNotInSync);
else
- {
- if (changeOnRight)
- fileObj.setSyncDir(SYNC_DIR_LEFT);
- else
- fileObj.setSyncDirConflict(txtNoSideChanged);
- }
+ fileObj.setSyncDir(changeOnLeft ? SYNC_DIR_RIGHT : SYNC_DIR_LEFT);
}
- else //object did not complete last sync: important check: user may have changed comparison variant, so what was in sync according to last variant is not any longer!
+ else
{
- if (changeOnLeft && changeOnRight)
+ if (changeOnLeft)
fileObj.setSyncDirConflict(txtBothSidesChanged);
else
- {
- // if (cat == FILE_LEFT_SIDE_ONLY)
- // fileObj.setSyncDir(SYNC_DIR_RIGHT);
- // else if (cat == FILE_RIGHT_SIDE_ONLY)
- // fileObj.setSyncDir(SYNC_DIR_LEFT);
- // else
- fileObj.setSyncDirConflict(txtLastSyncFail);
- }
+ fileObj.setSyncDirConflict(txtNoSideChanged);
}
}
-
- void processSymlink(SymLinkMapping& linkObj,
- const DirContainer* dbDirectoryLeft,
- const DirContainer* dbDirectoryRight)
+ void processSymlink(SymLinkMapping& linkObj, const InSyncDir* dbContainer)
{
const CompareSymlinkResult cat = linkObj.getLinkCategory();
if (cat == SYMLINK_EQUAL)
return;
- /*
- if (filterFileConflictFound(linkObj.getObjRelativeName())) //always use file filter: Link type may not be "stable" on Linux!
- {
- if (cat == SYMLINK_LEFT_SIDE_ONLY)
- linkObj.setSyncDir(SYNC_DIR_RIGHT);
- else if (cat == SYMLINK_RIGHT_SIDE_ONLY)
- linkObj.setSyncDir(SYNC_DIR_LEFT);
- else
- linkObj.setSyncDirConflict(txtFilterChanged);
- return;
- }
- */
-
- //determine datasets for change detection
- const DataSetSymlink dataDbLeft = retrieveDataSetSymlink(linkObj.getObjShortName(), dbDirectoryLeft);
- const DataSetSymlink dataDbRight = retrieveDataSetSymlink(linkObj.getObjShortName(), dbDirectoryRight);
-
- const DataSetSymlink dataCurrentLeft( linkObj, Int2Type<LEFT_SIDE>());
- const DataSetSymlink dataCurrentRight(linkObj, Int2Type<RIGHT_SIDE>());
+ //try to find corresponding database entry
+ const InSyncDir::LinkList::value_type* dbEntry = nullptr;
+ if (dbContainer)
+ {
+ auto iter = dbContainer->symlinks.find(linkObj.getObjShortName());
+ if (iter != dbContainer->symlinks.end())
+ dbEntry = &*iter;
+ }
//evaluation
- const bool changeOnLeft = dataDbLeft != dataCurrentLeft;
- const bool changeOnRight = dataDbRight != dataCurrentRight;
+ const bool changeOnLeft = !isEqual<LEFT_SIDE >(linkObj, dbEntry);
+ const bool changeOnRight = !isEqual<RIGHT_SIDE>(linkObj, dbEntry);
- if (dataDbLeft == dataDbRight) //last sync seems to have been successful
+ if (changeOnLeft != changeOnRight)
{
- if (changeOnLeft)
- {
- if (changeOnRight)
- linkObj.setSyncDirConflict(txtBothSidesChanged);
- else
- linkObj.setSyncDir(SYNC_DIR_RIGHT);
- }
+ //if database entry not in sync according to current settings! -> do not set direction based on async status!
+ if (dbEntry && !stillInSync(dbEntry->second, cmpVar))
+ linkObj.setSyncDirConflict(txtDbNotInSync);
else
- {
- if (changeOnRight)
- linkObj.setSyncDir(SYNC_DIR_LEFT);
- else
- linkObj.setSyncDirConflict(txtNoSideChanged);
- }
+ linkObj.setSyncDir(changeOnLeft ? SYNC_DIR_RIGHT : SYNC_DIR_LEFT);
}
- else //object did not complete last sync
+ else
{
- if (changeOnLeft && changeOnRight)
+ if (changeOnLeft)
linkObj.setSyncDirConflict(txtBothSidesChanged);
else
- linkObj.setSyncDirConflict(txtLastSyncFail);
+ linkObj.setSyncDirConflict(txtNoSideChanged);
}
}
-
- void processDir(DirMapping& dirObj,
- const DirContainer* dbDirectoryLeft,
- const DirContainer* dbDirectoryRight)
+ void processDir(DirMapping& dirObj, const InSyncDir* dbContainer)
{
const CompareDirResult cat = dirObj.getDirCategory();
- /*
- if (filterDirConflictFound(dirObj.getObjRelativeName()))
- {
- switch (cat)
- {
- case DIR_LEFT_SIDE_ONLY:
- dirObj.setSyncDir(SYNC_DIR_RIGHT);
- break;
- case DIR_RIGHT_SIDE_ONLY:
- dirObj.setSyncDir(SYNC_DIR_LEFT);
- break;
- case DIR_EQUAL:
- ;
- }
-
- SetDirChangedFilter().recurse(dirObj); //filter issue for this directory => treat subfiles/-dirs the same
- return;
- }
- */
- //determine datasets for change detection
- const std::pair<DataSetDir, const DirContainer*> dataDbLeftStuff = retrieveDataSetDir(dirObj.getObjShortName(), dbDirectoryLeft);
- const std::pair<DataSetDir, const DirContainer*> dataDbRightStuff = retrieveDataSetDir(dirObj.getObjShortName(), dbDirectoryRight);
+ //try to find corresponding database entry
+ const InSyncDir::DirList::value_type* dbEntry = nullptr;
+ if (dbContainer)
+ {
+ auto iter = dbContainer->dirs.find(dirObj.getObjShortName());
+ if (iter != dbContainer->dirs.end())
+ dbEntry = &*iter;
+ }
if (cat != DIR_EQUAL)
{
- const DataSetDir dataCurrentLeft( dirObj, Int2Type<LEFT_SIDE>());
- const DataSetDir dataCurrentRight(dirObj, Int2Type<RIGHT_SIDE>());
-
//evaluation
- const bool changeOnLeft = dataDbLeftStuff.first != dataCurrentLeft;
- const bool changeOnRight = dataDbRightStuff.first != dataCurrentRight;
+ const bool changeOnLeft = !isEqual<LEFT_SIDE >(dirObj, dbEntry);
+ const bool changeOnRight = !isEqual<RIGHT_SIDE>(dirObj, dbEntry);
- if (dataDbLeftStuff.first == dataDbRightStuff.first) //last sync seems to have been successful
+ if (changeOnLeft != changeOnRight)
{
- if (changeOnLeft)
- {
- if (changeOnRight)
- dirObj.setSyncDirConflict(txtBothSidesChanged);
- else
- dirObj.setSyncDir(SYNC_DIR_RIGHT);
- }
+ //if database entry not in sync according to current settings! -> do not set direction based on async status!
+ if (dbEntry && !stillInSync(dbEntry->second))
+ dirObj.setSyncDirConflict(txtDbNotInSync);
else
- {
- if (changeOnRight)
- dirObj.setSyncDir(SYNC_DIR_LEFT);
- else
- {
- assert(false);
- dirObj.setSyncDirConflict(txtNoSideChanged);
- }
- }
+ dirObj.setSyncDir(changeOnLeft ? SYNC_DIR_RIGHT : SYNC_DIR_LEFT);
}
- else //object did not complete last sync
+ else
{
- if (changeOnLeft && changeOnRight)
+ if (changeOnLeft)
dirObj.setSyncDirConflict(txtBothSidesChanged);
else
- {
- // switch (cat)
- // {
- // case DIR_LEFT_SIDE_ONLY:
- // dirObj.setSyncDir(SYNC_DIR_RIGHT);
- // break;
- // case DIR_RIGHT_SIDE_ONLY:
- // dirObj.setSyncDir(SYNC_DIR_LEFT);
- // break;
- // case DIR_EQUAL:
- // assert(false);
- // }
-
- dirObj.setSyncDirConflict(txtLastSyncFail);
- }
+ dirObj.setSyncDirConflict(txtNoSideChanged);
}
}
- recurse(dirObj, dataDbLeftStuff.second, dataDbRightStuff.second); //recursion
+ recurse(dirObj, dbEntry ? &dbEntry->second : nullptr); //recursion
}
-
- void findEqualDbEntries(const DirContainer& dbDirectoryLeft,
- const DirContainer& dbDirectoryRight)
+ void collectEqualDbEntries(const InSyncDir& container)
{
//note: we cannot integrate this traversal into "recurse()" since it may take a *slightly* different path: e.g. file renamed on both sides
- std::for_each(dbDirectoryLeft.files.begin(), dbDirectoryLeft.files.end(),
- [&](const DirContainer::FileList::value_type& entryLeft)
+ std::for_each(container.files.begin(), container.files.end(),
+ [&](const std::pair<Zstring, InSyncFile>& filePair)
{
- auto iterRight = dbDirectoryRight.files.find(entryLeft.first);
- if (iterRight != dbDirectoryRight.files.end())
- {
- if (entryLeft. second.id != FileId() &&
- iterRight->second.id != FileId() &&
- DataSetFile(entryLeft.first, entryLeft.second) == DataSetFile(iterRight->first, iterRight->second))
- onceEqual.insert(std::make_pair(getFileIdKey(entryLeft.second), getFileIdKey(iterRight->second)));
- }
+ if (filePair.second.left .id != FileId() &&
+ filePair.second.right.id != FileId() &&
+ stillInSync(filePair.second, cmpVar, fileTimeTolerance))
+ onceEqual.insert(std::make_pair(getFileIdKey(filePair.second.left), getFileIdKey(filePair.second.right)));
});
- std::for_each(dbDirectoryLeft.dirs.begin(), dbDirectoryLeft.dirs.end(),
- [&](const DirContainer::DirList::value_type& entryLeft)
- {
- auto iterRight = dbDirectoryRight.dirs.find(entryLeft.first);
- if (iterRight != dbDirectoryRight.dirs.end())
- findEqualDbEntries(entryLeft.second, iterRight->second);
- });
+ std::for_each(container.dirs.begin(), container.dirs.end(),
+ [&](const std::pair<Zstring, InSyncDir>& dirPair) { collectEqualDbEntries(dirPair.second); });
}
typedef std::tuple<Int64, UInt64, FileId> FileIdKey; //(date, size, file ID)
@@ -793,11 +562,12 @@ private:
});
}
-
const std::wstring txtBothSidesChanged;
const std::wstring txtNoSideChanged;
- const std::wstring txtFilterChanged;
- const std::wstring txtLastSyncFail;
+ const std::wstring txtDbNotInSync;
+
+ const CompareVariant cmpVar;
+ const size_t fileTimeTolerance;
std::function<void(const std::wstring&)> reportWarning_;
@@ -849,12 +619,31 @@ private:
FAT caveat: File Ids are generally not stable when file is either moved or renamed!
=> 1. Move/rename operations on FAT cannot be detected reliably.
- => 2. database generally contains wrong file ID on FAT after renaming from .ffs_tmp files => correct file Ids in database after next sync
+ => 2. database generally contains wrong file ID on FAT after renaming from .ffs_tmp files => correct file Ids in database only after next sync
+ => 3. even exFAT screws up (but less than FAT) and changes IDs after file move. Did they learn nothing from the past?
+
+ Possible refinement
+ -------------------
+ If the file ID is wrong (FAT) or not available, we could at least allow direct association by name, instead of breaking the chain completely: support NTFS -> FAT
+
+ 1. find equal entries in database:
+ std::hash_map: DB* |-> DB* onceEqual
+
+ 2. build alternative mappings if file Id is available for database entries:
+ std::map: FielId |-> DB* leftIdToDbRight
+ std::map: FielId |-> DB* rightIdToDbRight
+
+ 3. collect files on one side during determination of sync directions:
+ std::vector<FileMapping*, DB*> exLeftOnlyToDbRight -> first try to use file Id, if failed associate via file name instead
+ std::hash_map<DB*, FileMapping*> dbRightToexRightOnly ->
+
+ 4. find renamed pairs
*/
};
-
+}
//---------------------------------------------------------------------------------------------------------------
+
std::vector<DirectionConfig> zen::extractDirectionCfg(const MainConfiguration& mainCfg)
{
//merge first and additional pairs
@@ -1415,7 +1204,7 @@ void deleteFromGridAndHDOneSide(InputIterator first, InputIterator last,
{
if (useRecycleBin)
{
- if (zen::moveToRecycleBin(fsObj.getFullName<side>())) //throw FileError
+ if (zen::recycleOrDelete(fsObj.getFullName<side>())) //throw FileError
statusHandler.notifyDeletion(fsObj.getFullName<side>());
}
else
diff --git a/comparison.cpp b/comparison.cpp
index 5940e458..4c188a92 100644
--- a/comparison.cpp
+++ b/comparison.cpp
@@ -9,14 +9,13 @@
#include <numeric>
#include <zen/perf.h>
#include <zen/scope_guard.h>
-#include <wx+/string_conv.h>
#include <wx+/format_unit.h>
+#include "algorithm.h"
#include "lib/parallel_scan.h"
#include "lib/resolve_path.h"
#include "lib/dir_exist_async.h"
#include "lib/binary.h"
#include "lib/cmp_filetime.h"
-#include "algorithm.h"
#include "lib/status_handler_impl.h"
using namespace zen;
@@ -38,8 +37,7 @@ std::vector<FolderPairCfg> zen::extractCompareCfg(const MainConfiguration& mainC
const Zstring leftDirFmt = getFormattedDirectoryName(enhPair.leftDirectory); //ensure they end with FILE_NAME_SEPARATOR and replace macros
const Zstring rightDirFmt = getFormattedDirectoryName(enhPair.rightDirectory); //
- return FolderPairCfg(leftDirFmt,
- rightDirFmt,
+ return FolderPairCfg(leftDirFmt, rightDirFmt,
enhPair.altCmpConfig.get() ? enhPair.altCmpConfig->compareVar : mainCfg.cmpConfig.compareVar,
enhPair.altCmpConfig.get() ? enhPair.altCmpConfig->handleSymlinks : mainCfg.cmpConfig.handleSymlinks,
@@ -71,7 +69,7 @@ void checkForIncompleteInput(const std::vector<FolderPairCfg>& folderPairsForm,
tryReportingError([&]
{
if (havePartialPair == haveFullPair) //error if: all empty or exist both full and partial pairs -> support single-dir scenario
- throw FileError(_("An input folder name is empty.") + L" \n\n" +
+ throw FileError(_("A folder input field is empty.") + L" \n\n" +
_("You can ignore this error to consider the folder as empty."));
}, procCallback);
}
@@ -208,7 +206,9 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& cfgLi
checkForIncompleteInput(cfgList, procCallback);
- std::set<Zstring, LessFilename> dirnamesExisting; //list of directories that are *expected* to be existent (and need to be scanned)!
+ std::set<Zstring, LessFilename> dirnamesExisting;
+ //list of directories that are *expected* to be existent (and need to be scanned)!
+ //directory existence only checked *once* to avoid race conditions!
{
std::set<Zstring, LessFilename> dirnames;
std::for_each(cfgList.begin(), cfgList.end(),
@@ -231,7 +231,6 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& cfgLi
//-------------------end of basic checks------------------------------------------
-
try
{
//------------------- fill directory buffer ---------------------------------------------------
@@ -298,10 +297,14 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPairCfg>& cfgLi
std::for_each(cfgList.begin(), cfgList.end(),
[&](const FolderPairCfg& fpCfg)
{
- output_tmp.push_back(std::make_shared<BaseDirMapping>(fpCfg.leftDirectoryFmt,
- dirAvailable(fpCfg.leftDirectoryFmt),
- fpCfg.rightDirectoryFmt,
- dirAvailable(fpCfg.rightDirectoryFmt)));
+ //a pity VC11 screws up on std::make_shared with 7 arguments...
+ output_tmp.push_back(std::shared_ptr<BaseDirMapping>(new BaseDirMapping(fpCfg.leftDirectoryFmt,
+ dirAvailable(fpCfg.leftDirectoryFmt),
+ fpCfg.rightDirectoryFmt,
+ dirAvailable(fpCfg.rightDirectoryFmt),
+ fpCfg.filter.nameFilter,
+ fpCfg.compareVar,
+ fileTimeTolerance)));
switch (fpCfg.compareVar)
{
case CMP_BY_TIME_SIZE:
@@ -350,7 +353,7 @@ std::wstring getConflictInvalidDate(const Zstring& fileNameFull, Int64 utcTime)
{
return _("Conflict detected:") + L"\n" +
replaceCpy(_("File %x has an invalid date!"), L"%x", fmtFileName(fileNameFull)) + L"\n\n" +
- _("Date") + L": " + utcToLocalTimeString(utcTime);
+ _("Date:") + L" " + utcToLocalTimeString(utcTime);
}
@@ -361,45 +364,35 @@ std::wstring getConflictSameDateDiffSize(const FileMapping& fileObj)
{
return _("Conflict detected:") + L"\n" +
replaceCpy(_("Files %x have the same date but a different size!"), L"%x", fmtFileName(fileObj.getObjRelativeName())) + L"\n\n" +
- L"<-- " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime<LEFT_SIDE >()) + L" " + _("Size") + L": " + toGuiString(fileObj.getFileSize<LEFT_SIDE>()) + L"\n" +
- L"--> " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime<RIGHT_SIDE>()) + L" " + _("Size") + L": " + toGuiString(fileObj.getFileSize<RIGHT_SIDE>());
+ L"<-- " + _("Date:") + L" " + utcToLocalTimeString(fileObj.getLastWriteTime<LEFT_SIDE >()) + L" " + _("Size:") + L" " + toGuiString(fileObj.getFileSize<LEFT_SIDE>()) + L"\n" +
+ L"--> " + _("Date:") + L" " + utcToLocalTimeString(fileObj.getLastWriteTime<RIGHT_SIDE>()) + L" " + _("Size:") + L" " + toGuiString(fileObj.getFileSize<RIGHT_SIDE>());
}
}
-
//-----------------------------------------------------------------------------
+
void CompareProcess::categorizeSymlinkByTime(SymLinkMapping& linkObj) const
{
- const CmpFileTime timeCmp(fileTimeTolerance);
-
//categorize symlinks that exist on both sides
- if ( //special handling: if symlinks have the same "content" they are seen as equal while other metadata is ignored
-#ifdef FFS_WIN //type of symbolic link is relevant for Windows only
- linkObj.getLinkType<LEFT_SIDE>() == linkObj.getLinkType<RIGHT_SIDE>() &&
-#endif
- !linkObj.getTargetPath<LEFT_SIDE>().empty() &&
- linkObj.getTargetPath<LEFT_SIDE>() == linkObj.getTargetPath<RIGHT_SIDE>())
- {
- //symlinks have same "content"
- if (linkObj.getShortName<LEFT_SIDE>() == linkObj.getShortName<RIGHT_SIDE>() &&
- timeCmp.getResult(linkObj.getLastWriteTime<LEFT_SIDE>(),
- linkObj.getLastWriteTime<RIGHT_SIDE>()) == CmpFileTime::TIME_EQUAL)
- linkObj.setCategory<SYMLINK_EQUAL>();
- else
- linkObj.setCategory<SYMLINK_DIFFERENT_METADATA>();
- return;
- }
-
- switch (timeCmp.getResult(linkObj.getLastWriteTime<LEFT_SIDE>(),
- linkObj.getLastWriteTime<RIGHT_SIDE>()))
+ switch (CmpFileTime::getResult(linkObj.getLastWriteTime<LEFT_SIDE>(),
+ linkObj.getLastWriteTime<RIGHT_SIDE>(), fileTimeTolerance))
{
case CmpFileTime::TIME_EQUAL:
- if (
+ if (linkObj.getTargetPath<LEFT_SIDE>().empty())
+ linkObj.setCategoryConflict(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkObj.getFullName<LEFT_SIDE>())));
+ else if (linkObj.getTargetPath<RIGHT_SIDE>().empty())
+ linkObj.setCategoryConflict(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkObj.getFullName<RIGHT_SIDE>())));
+
+ else if (
#ifdef FFS_WIN //type of symbolic link is relevant for Windows only
linkObj.getLinkType<LEFT_SIDE>() == linkObj.getLinkType<RIGHT_SIDE>() &&
#endif
- linkObj.getTargetPath<LEFT_SIDE>() == linkObj.getTargetPath<RIGHT_SIDE>()) //may both be empty if following link failed
+ linkObj.getTargetPath<LEFT_SIDE>() == linkObj.getTargetPath<RIGHT_SIDE>()) //may both be empty if reading link content failed
{
+ //Caveat:
+ //1. SYMLINK_EQUAL may only be set if short names match in case: InSyncDir's mapping tables use short name as a key! see db_file.cpp
+ //2. harmonize with "bool stillInSync()" in algorithm.cpp
+
if (linkObj.getShortName<LEFT_SIDE>() == linkObj.getShortName<RIGHT_SIDE>())
linkObj.setCategory<SYMLINK_EQUAL>();
else
@@ -441,17 +434,19 @@ void CompareProcess::compareByTimeSize(const FolderPairCfg& fpConfig, BaseDirMap
[&](SymLinkMapping* linkMap) { this->categorizeSymlinkByTime(*linkMap); });
//categorize files that exist on both sides
- const CmpFileTime timeCmp(fileTimeTolerance);
-
std::for_each(uncategorizedFiles.begin(), uncategorizedFiles.end(),
[&](FileMapping* fileObj)
{
- switch (timeCmp.getResult(fileObj->getLastWriteTime<LEFT_SIDE>(),
- fileObj->getLastWriteTime<RIGHT_SIDE>()))
+ switch (CmpFileTime::getResult(fileObj->getLastWriteTime<LEFT_SIDE>(),
+ fileObj->getLastWriteTime<RIGHT_SIDE>(), fileTimeTolerance))
{
case CmpFileTime::TIME_EQUAL:
if (fileObj->getFileSize<LEFT_SIDE>() == fileObj->getFileSize<RIGHT_SIDE>())
{
+ //Caveat:
+ //1. FILE_EQUAL may only be set if short names match in case: InSyncDir's mapping tables use short name as a key! see db_file.cpp
+ //2. harmonize with "bool stillInSync()" in algorithm.cpp
+
if (fileObj->getShortName<LEFT_SIDE>() == fileObj->getShortName<RIGHT_SIDE>())
fileObj->setCategory<FILE_EQUAL>();
else
@@ -484,18 +479,27 @@ void CompareProcess::compareByTimeSize(const FolderPairCfg& fpConfig, BaseDirMap
void CompareProcess::categorizeSymlinkByContent(SymLinkMapping& linkObj) const
{
//categorize symlinks that exist on both sides
- const CmpFileTime timeCmp(fileTimeTolerance);
+ if (linkObj.getTargetPath<LEFT_SIDE>().empty())
+ linkObj.setCategoryConflict(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkObj.getFullName<LEFT_SIDE>())));
+ else if (linkObj.getTargetPath<RIGHT_SIDE>().empty())
+ linkObj.setCategoryConflict(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkObj.getFullName<RIGHT_SIDE>())));
+ //if one of these is empty it's handled like reading "file content" failed
- if (
+ else if (
#ifdef FFS_WIN //type of symbolic link is relevant for Windows only
linkObj.getLinkType<LEFT_SIDE>() == linkObj.getLinkType<RIGHT_SIDE>() &&
#endif
- linkObj.getTargetPath<LEFT_SIDE>() == linkObj.getTargetPath<RIGHT_SIDE>())
+ linkObj.getTargetPath<LEFT_SIDE>() == linkObj.getTargetPath<RIGHT_SIDE>()) //may both be empty if determination failed!!!
{
+ //Caveat:
+ //1. SYMLINK_EQUAL may only be set if short names match in case: InSyncDir's mapping tables use short name as a key! see db_file.cpp
+ //2. harmonize with "bool stillInSync()" in algorithm.cpp
+
//symlinks have same "content"
if (linkObj.getShortName<LEFT_SIDE>() == linkObj.getShortName<RIGHT_SIDE>() &&
- timeCmp.getResult(linkObj.getLastWriteTime<LEFT_SIDE>(),
- linkObj.getLastWriteTime<RIGHT_SIDE>()) == CmpFileTime::TIME_EQUAL)
+ CmpFileTime::getResult(linkObj.getLastWriteTime<LEFT_SIDE>(),
+ linkObj.getLastWriteTime<RIGHT_SIDE>(),
+ fileTimeTolerance) == CmpFileTime::TIME_EQUAL)
linkObj.setCategory<SYMLINK_EQUAL>();
else
linkObj.setCategory<SYMLINK_DIFFERENT_METADATA>();
@@ -550,8 +554,6 @@ void CompareProcess::compareByContent(std::vector<std::pair<FolderPairCfg, BaseD
to<Int64>(bytesTotal),
ProcessCallback::PHASE_COMPARING_CONTENT);
- const CmpFileTime timeCmp(fileTimeTolerance);
-
const std::wstring txtComparingContentOfFiles = replaceCpy(_("Comparing content of files %x"), L"%x", L"\n%x", false);
//compare files (that have same size) bytewise...
@@ -569,9 +571,14 @@ void CompareProcess::compareByContent(std::vector<std::pair<FolderPairCfg, BaseD
fileObj->getFileSize<LEFT_SIDE >(),
procCallback))
{
+ //Caveat:
+ //1. FILE_EQUAL may only be set if short names match in case: InSyncDir's mapping tables use short name as a key! see db_file.cpp
+ //2. harmonize with "bool stillInSync()" in algorithm.cpp
+
if (fileObj->getShortName<LEFT_SIDE>() == fileObj->getShortName<RIGHT_SIDE>() &&
- timeCmp.getResult(fileObj->getLastWriteTime<LEFT_SIDE>(),
- fileObj->getLastWriteTime<RIGHT_SIDE>()) == CmpFileTime::TIME_EQUAL)
+ CmpFileTime::getResult(fileObj->getLastWriteTime<LEFT_SIDE >(),
+ fileObj->getLastWriteTime<RIGHT_SIDE>(),
+ fileTimeTolerance) == CmpFileTime::TIME_EQUAL)
fileObj->setCategory<FILE_EQUAL>();
else
fileObj->setCategory<FILE_DIFFERENT_METADATA>();
@@ -740,7 +747,7 @@ void processFilteredDirs(HierarchyObject& hierObj, const HardFilter& filterProc)
});
//remove superfluous directories -> note: this does not invalidate "std::vector<FileMapping*>& undefinedFiles", since we delete folders only
- //and there is no side-effect for memory positions of FileMapping and SymlinkMapping thanks to std::list!
+ //and there is no side-effect for memory positions of FileMapping and SymlinkMapping thanks to zen::FixedList!
subDirs.remove_if([](DirMapping& dirObj)
{
return !dirObj.isActive() &&
diff --git a/file_hierarchy.h b/file_hierarchy.h
index 3a8c079a..c9ef75a4 100644
--- a/file_hierarchy.h
+++ b/file_hierarchy.h
@@ -18,7 +18,7 @@
#include <zen/int64.h>
#include <zen/file_id_def.h>
#include "structures.h"
-
+#include "lib/hard_filter.h"
namespace zen
{
@@ -32,9 +32,9 @@ struct FileDescriptor
fileSize(fileSizeIn),
id(idIn) {}
- Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long)
+ Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long)
UInt64 fileSize;
- FileId id; //optional! (however, always set on Linux, and *generally* available on Windows)
+ FileId id; //optional! (however, always set on Linux, and *generally* available on Windows)
};
@@ -55,7 +55,7 @@ struct LinkDescriptor
type(lt) {}
Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long)
- Zstring targetPath; //symlink "content", may be empty if determination failed
+ Zstring targetPath; //optional: symlink "content", may be empty if determination failed
LinkType type; //type is required for Windows only! On Linux there is no such thing => consider this when comparing Symbolic Links!
};
@@ -86,9 +86,9 @@ class FileSystemObject;
//------------------------------------------------------------------
/*
ERD:
- DirContainer 1 -----> 0..n DirContainer
- DirContainer 1 -----> 0..n FileDescriptor
- DirContainer 1 -----> 0..n LinkDescriptor
+ DirContainer 1 --> 0..n DirContainer
+ DirContainer 1 --> 0..n FileDescriptor
+ DirContainer 1 --> 0..n LinkDescriptor
*/
struct DirContainer
@@ -99,9 +99,9 @@ struct DirContainer
typedef std::map<Zstring, LinkDescriptor, LessFilename> LinkList; //
//------------------------------------------------------------------
- DirList dirs; //contained directories
- FileList files; //contained files
- LinkList links; //contained symlinks (note: only symlinks that are not treated as their target are placed here!)
+ DirList dirs;
+ FileList files;
+ LinkList links; //non-followed symlinks
//convenience
DirContainer& addSubDir(const Zstring& shortName)
@@ -141,11 +141,11 @@ class HierarchyObject
friend class DirMapping;
friend class FileSystemObject;
+public:
typedef zen::FixedList<FileMapping> SubFileVec; //MergeSides::execute() requires a structure that doesn't invalidate pointers after push_back()
typedef zen::FixedList<SymLinkMapping> SubLinkVec; //Note: deque<> has circular dependency in VCPP!
typedef zen::FixedList<DirMapping> SubDirVec;
-public:
DirMapping& addSubDir(const Zstring& shortNameLeft,
const Zstring& shortNameRight);
@@ -184,6 +184,8 @@ public:
BaseDirMapping& getRoot() { return root_; }
+ const Zstring& getObjRelativeNamePf() const { return objRelNamePf; } //postfixed or empty!
+
protected:
HierarchyObject(const Zstring& relativeNamePf,
BaseDirMapping& baseMap) :
@@ -202,8 +204,6 @@ private:
HierarchyObject(const HierarchyObject&); //this class is referenced by it's child elements => make it non-copyable/movable!
HierarchyObject& operator=(const HierarchyObject&); //
- const Zstring& getObjRelativeNamePf() const { return objRelNamePf; }
-
SubFileVec subFiles; //contained file maps
SubLinkVec subLinks; //contained symbolic link maps
SubDirVec subDirs; //contained directory maps
@@ -220,7 +220,10 @@ public:
BaseDirMapping(const Zstring& dirPostfixedLeft,
bool dirExistsLeft,
const Zstring& dirPostfixedRight,
- bool dirExistsRight) :
+ bool dirExistsRight,
+ const HardFilter::FilterRef& filter,
+ CompareVariant cmpVar,
+ size_t fileTimeTolerance) :
#ifdef _MSC_VER
#pragma warning(disable : 4355) //"The this pointer is valid only within nonstatic member functions. It cannot be used in the initializer list for a base class."
#endif
@@ -228,6 +231,7 @@ public:
#ifdef _MSC_VER
#pragma warning(default : 4355)
#endif
+ filter_(filter), cmpVar_(cmpVar), fileTimeTolerance_(fileTimeTolerance),
baseDirPfL (dirPostfixedLeft ),
baseDirPfR (dirPostfixedRight),
dirExistsLeft_ (dirExistsLeft ),
@@ -238,12 +242,21 @@ public:
template <SelectedSide side> bool wasExisting() const; //status of directory existence at the time of comparison!
+ //get settings which were used while creating BaseDirMapping
+ const HardFilter& getFilter() const { return *filter_; }
+ CompareVariant getCompVariant() const { return cmpVar_; }
+ size_t getFileTimeTolerance() const { return fileTimeTolerance_; }
+
virtual void flip();
private:
BaseDirMapping(const BaseDirMapping&); //this class is referenced by HierarchyObject => make it non-copyable/movable!
BaseDirMapping& operator=(const BaseDirMapping&); //
+ HardFilter::FilterRef filter_; //filter used while scanning directory: represents sub-view of actual files!
+ CompareVariant cmpVar_;
+ size_t fileTimeTolerance_;
+
Zstring baseDirPfL; //base sync dir postfixed
Zstring baseDirPfR; //
diff --git a/lib/cmp_filetime.h b/lib/cmp_filetime.h
index afc97b9d..eb595ace 100644
--- a/lib/cmp_filetime.h
+++ b/lib/cmp_filetime.h
@@ -24,8 +24,6 @@ static const long oneYearFromNow = wxGetUTCTime() + 365 * 24 * 3600; //init at p
class CmpFileTime
{
public:
- CmpFileTime(size_t tolerance) : tolerance_(tolerance) {}
-
enum Result
{
TIME_EQUAL,
@@ -35,9 +33,9 @@ public:
TIME_RIGHT_INVALID
};
- Result getResult(const Int64& lhs, const Int64& rhs) const
+ static Result getResult(const Int64& lhs, const Int64& rhs, size_t tolerance)
{
- if (sameFileTime(lhs, rhs, tolerance_)) //last write time may differ by up to 2 seconds (NTFS vs FAT32)
+ if (sameFileTime(lhs, rhs, tolerance)) //last write time may differ by up to 2 seconds (NTFS vs FAT32)
return TIME_EQUAL;
//check for erroneous dates
@@ -53,9 +51,6 @@ public:
else
return TIME_LEFT_NEWER;
}
-
-private:
- const size_t tolerance_;
};
}
diff --git a/lib/db_file.cpp b/lib/db_file.cpp
index 33c83a0e..787325e2 100644
--- a/lib/db_file.cpp
+++ b/lib/db_file.cpp
@@ -5,17 +5,21 @@
// **************************************************************************
#include "db_file.h"
-#include <wx/wfstream.h>
-#include <wx/zstream.h>
-#include <wx/mstream.h>
#include <zen/file_error.h>
-#include <wx+/string_conv.h>
#include <zen/file_handling.h>
-#include <wx+/serialize.h>
-#include <zen/file_io.h>
#include <zen/scope_guard.h>
#include <zen/guid.h>
#include <zen/utf.h>
+#include <wx+/zlib_wrap.h>
+#include <wx+/serialize.h>
+
+#ifdef FFS_WIN
+warn_static("get rid of wx headers")
+#endif
+#include <wx/wfstream.h>
+#include <wx/zstream.h>
+#include <wx/mstream.h>
+#include <zen/perf.h>
#ifdef FFS_WIN
#include <zen/win.h> //includes "windows.h"
@@ -29,13 +33,11 @@ namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
const char FILE_FORMAT_DESCR[] = "FreeFileSync";
-const int FILE_FORMAT_VER = 8;
+const int FILE_FORMAT_VER = 9;
//-------------------------------------------------------------------------------------------------------------------------------
typedef std::string UniqueId;
-typedef Zbase<char> MemoryStream; //ref-counted byte stream representing DirInformation
-typedef std::map<UniqueId, MemoryStream> StreamMapping; //list of streams ordered by session UUID
-
+typedef std::map<UniqueId, BinaryStream> StreamMapping; //list of streams ordered by session UUID
//-----------------------------------------------------------------------------------
//| ensure 32/64 bit portability: use fixed size data types only e.g. std::uint32_t |
@@ -48,7 +50,7 @@ Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false)
//Linux and Windows builds are binary incompatible: different file id?, problem with case sensitivity?
//however 32 and 64 bit db files *are* designed to be binary compatible!
//Give db files different names.
- //make sure they end with ".ffs_db". These files will not be included into comparison
+ //make sure they end with ".ffs_db". These files will be excluded from comparison
#ifdef FFS_WIN
Zstring dbname = Zstring(Zstr("sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
#elif defined FFS_LINUX
@@ -59,65 +61,77 @@ Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false)
return baseMap.getBaseDirPf<side>() + dbname;
}
+//#######################################################################################################################################
-class CheckedDbReader : public CheckedReader
+//save/load streams
+void saveStreams(const StreamMapping& streamList, const Zstring& filename) //throw FileError
{
-public:
- CheckedDbReader(wxInputStream& stream, const Zstring& errorObjName) : CheckedReader(stream), errorObjName_(errorObjName) {}
+ BinStreamOut streamOut;
-private:
- virtual void throwException() const { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(errorObjName_))); }
+ //write FreeFileSync file identifier
+ writeArray(streamOut, FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR));
- const Zstring errorObjName_;
-};
+ //save file format version
+ writeNumber<std::int32_t>(streamOut, FILE_FORMAT_VER);
+ //save stream list
+ writeNumber<std::uint32_t>(streamOut, static_cast<std::uint32_t>(streamList.size())); //number of streams, one for each sync-pair
-class CheckedDbWriter : public CheckedWriter
-{
-public:
- CheckedDbWriter(wxOutputStream& stream, const Zstring& errorObjName) : CheckedWriter(stream), errorObjName_(errorObjName) {}
+ for (auto iter = streamList.begin(); iter != streamList.end(); ++iter)
+ {
+ writeContainer<std::string >(streamOut, iter->first );
+ writeContainer<BinaryStream>(streamOut, iter->second);
+ }
-private:
- virtual void throwException() const { throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(errorObjName_))); }
+ saveBinStream(filename, streamOut.get()); //throw FileError
- const Zstring errorObjName_;
-};
+#ifdef FFS_WIN
+ ::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); //(try to) hide database file
+#endif
+}
+#ifdef FFS_WIN
+warn_static("remove after migration")
+#endif
-StreamMapping loadStreams(const Zstring& filename) //throw FileError
+StreamMapping loadStreams_v8(const Zstring& filename); //throw FileError
+
+
+StreamMapping loadStreams(const Zstring& filename) //throw FileError, FileErrorDatabaseNotExisting
{
try
{
- //read format description (uncompressed)
- FileInputStream rawStream(filename); //throw FileError, ErrorNotExisting
+ BinStreamIn streamIn = loadBinStream<BinaryStream>(filename); //throw FileError, ErrorNotExisting
//read FreeFileSync file identifier
char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {};
- rawStream.Read(formatDescr, sizeof(formatDescr)); //throw FileError
+ readArray(streamIn, formatDescr, sizeof(formatDescr)); //throw UnexpectedEndOfStreamError
if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr))
throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
- wxZlibInputStream decompressed(rawStream, wxZLIB_ZLIB);
+ const int version = readNumber<std::int32_t>(streamIn); //throw UnexpectedEndOfStreamError
+ if (version != FILE_FORMAT_VER) //read file format version#
+ //throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
+ return loadStreams_v8(filename);
- CheckedDbReader cr(decompressed, filename);
+ #ifdef FFS_WIN
+warn_static("fix after migration")
+#endif
- std::int32_t version = cr.readPOD<std::int32_t>();
- if (version != FILE_FORMAT_VER) //read file format version#
- throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
//read stream lists
StreamMapping output;
- std::uint32_t dbCount = cr.readPOD<std::uint32_t>(); //number of databases: one for each sync-pair
+ size_t dbCount = readNumber<std::uint32_t>(streamIn); //number of streams, one for each sync-pair
while (dbCount-- != 0)
{
//DB id of partner databases
- const std::string sessionID = cr.readString<std::string>();
- const MemoryStream stream = cr.readString<MemoryStream>(); //read db-entry stream (containing DirInformation)
+ std::string sessionID = readContainer<std::string >(streamIn); //throw UnexpectedEndOfStreamError
+ BinaryStream stream = readContainer<BinaryStream>(streamIn); //
- output.insert(std::make_pair(sessionID, stream));
+ output[sessionID] = std::move(stream);
}
return output;
}
@@ -126,303 +140,553 @@ StreamMapping loadStreams(const Zstring& filename) //throw FileError
throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" +
replaceCpy(_("Database file %x does not yet exist."), L"%x", fmtFileName(filename)));
}
- catch (const std::bad_alloc& e)
+ catch (UnexpectedEndOfStreamError&)
{
- throw FileError(_("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filename));
+ }
+ catch (const std::bad_alloc& e) //still required?
+ {
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filename) + L"\n\n" +
+ _("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
}
}
+//#######################################################################################################################################
-class StreamParser : private CheckedDbReader
+#ifdef FFS_WIN
+warn_static("remove v8Compatibilty after migration")
+#endif
+
+class StreamGenerator //for db-file back-wards compatibility we stick with two output streams until further
{
public:
- static DirInfoPtr execute(const MemoryStream& stream, const Zstring& fileName) //throw FileError -> return value always bound!
+ static void execute(const InSyncDir& dir, //throw FileError
+ const Zstring& filenameL, //used for diagnostics only
+ const Zstring& filenameR,
+ BinaryStream& streamL,
+ BinaryStream& streamR,
+ bool v8Compatibilty)
{
- try
+ StreamGenerator generator;
+
+ //PERF_START
+ generator.recurse(dir);
+ //PERF_STOP
+
+ auto compStream = [](const BinaryStream& stream, const Zstring& filename) -> BinaryStream //throw FileError
{
- //read streams into DirInfo
- auto dirInfo = std::make_shared<DirInformation>();
- wxMemoryInputStream buffer(&*stream.begin(), stream.size()); //convert char-array to inputstream: no copying, ownership not transferred
- StreamParser(buffer, fileName, *dirInfo); //throw FileError
- return dirInfo;
- }
- catch (const std::bad_alloc& e)
+ try
+ {
+ /* Zlib: optimal level - testcase 1 million files
+ level/size [MB]/time [ms]
+ 0 49.54 272 (uncompressed)
+ 1 14.53 1013
+ 2 14.13 1106
+ 3 13.76 1288 - best compromise between speed and compression
+ 4 13.20 1526
+ 5 12.73 1916
+ 6 12.58 2765
+ 7 12.54 3633
+ 8 12.51 9032
+ 9 12.50 19698 (maximal compression) */
+ return compress(stream, 3); //throw ZlibInternalError
+ }
+ catch (ZlibInternalError&)
+ {
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename)) + L" (zlib error)");
+ }
+ };
+
+ const BinaryStream tmpL = compStream(generator.outputLeft .get(), filenameL);
+ const BinaryStream tmpR = compStream(generator.outputRight.get(), filenameR);
+ const BinaryStream tmpB = compStream(generator.outputBoth .get(), filenameL + Zstr("/") + filenameR);
+
+ //distribute "outputBoth" over left and right streams:
+ BinStreamOut outL;
+ BinStreamOut outR;
+ writeNumber<bool>(outL, true); //this side contains first part of "outputBoth"
+ writeNumber<bool>(outR, false);
+
+ size_t size1stPart = tmpB.size() / 2;
+ size_t size2ndPart = tmpB.size() - size1stPart;
+
+ if (v8Compatibilty)
{
- throw FileError(_("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
+ size1stPart = tmpB.size();
+ size2ndPart = 0;
}
+
+ writeNumber<std::uint64_t>(outL, size1stPart);
+ writeNumber<std::uint64_t>(outR, size2ndPart);
+
+ writeArray(outL, &*tmpB.begin(), size1stPart);
+ writeArray(outR, &*tmpB.begin() + size1stPart, size2ndPart);
+
+ //write streams corresponding to one side only
+ writeContainer<BinaryStream>(outL, tmpL);
+ writeContainer<BinaryStream>(outR, tmpR);
+
+ streamL = outL.get();
+ streamR = outR.get();
}
private:
- StreamParser(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : CheckedDbReader(stream, errorObjName)
+ void recurse(const InSyncDir& container)
{
- recurse(dirInfo.baseDirContainer);
+ // for (const auto& filePair : container.files) { processFile(filePair); }); !
+
+ writeNumber<std::uint32_t>(outputBoth, static_cast<std::uint32_t>(container.files.size()));
+ std::for_each(container.files.begin(), container.files.end(), [&](const std::pair<Zstring, InSyncFile>& filePair) { this->process(filePair); });
+
+ writeNumber<std::uint32_t>(outputBoth, static_cast<std::uint32_t>(container.symlinks.size()));
+ std::for_each(container.symlinks.begin(), container.symlinks.end(), [&](const std::pair<Zstring, InSyncSymlink>& symlinkPair) { this->process(symlinkPair); });
+
+ writeNumber<std::uint32_t>(outputBoth, static_cast<std::uint32_t>(container.dirs.size()));
+ std::for_each(container.dirs.begin(), container.dirs.end(), [&](const std::pair<Zstring, InSyncDir>& dirPair) { this->process(dirPair); });
}
- Zstring readStringUtf8() const
+ static void writeUtf8(BinStreamOut& output, const Zstring& str) { writeContainer(output, utfCvrtTo<Zbase<char>>(str)); }
+
+ static void write(BinStreamOut& output, const FileDescriptor& descr)
{
- return utfCvrtTo<Zstring>(readString<Zbase<char>>());
+ writeNumber<std:: int64_t>(output, to<std:: int64_t>(descr.lastWriteTimeRaw));
+ writeNumber<std::uint64_t>(output, to<std::uint64_t>(descr.fileSize));
+ writeNumber<std::uint64_t>(output, descr.id.first ); //device id
+ writeNumber<std::uint64_t>(output, descr.id.second); //file id
+ assert_static(sizeof(descr.id.first ) <= sizeof(std::uint64_t));
+ assert_static(sizeof(descr.id.second) <= sizeof(std::uint64_t));
}
- FileId readFileId() const
+ static void write(BinStreamOut& output, const LinkDescriptor& descr)
{
- assert_static(sizeof(FileId().first ) <= sizeof(std::uint64_t));
- assert_static(sizeof(FileId().second) <= sizeof(std::uint64_t));
+ writeNumber<std::int64_t>(output, to<std:: int64_t>(descr.lastWriteTimeRaw));
+ writeUtf8(output, descr.targetPath);
+ writeNumber<std::int32_t>(output, descr.type);
+ }
- const auto deviceId = static_cast<decltype(FileId().first )>(readPOD<std::uint64_t>()); //
- const auto fileId = static_cast<decltype(FileId().second)>(readPOD<std::uint64_t>()); //silence "loss of precision" compiler warnings
- return std::make_pair(deviceId, fileId);
+ static void write(BinStreamOut& output, const InSyncDir::InSyncStatus& status)
+ {
+ writeNumber<std::int32_t>(output, status);
}
- void recurse(DirContainer& dirCont) const
+ void process(const std::pair<Zstring, InSyncFile>& filePair)
{
- while (readPOD<bool>()) //files
- {
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringUtf8(); //file name
+ writeUtf8(outputBoth, filePair.first);
+ writeNumber<std::int32_t>(outputBoth, filePair.second.inSyncType);
- const std::int64_t modTime = readPOD<std::int64_t>();
- const std::uint64_t fileSize = readPOD<std::uint64_t>();
- const FileId fileID = readFileId();
+ write(outputLeft, filePair.second.left);
+ write(outputRight, filePair.second.right);
+ }
- dirCont.addSubFile(shortName,
- FileDescriptor(modTime, fileSize, fileID));
- }
+ void process(const std::pair<Zstring, InSyncSymlink>& symlinkPair)
+ {
+ writeUtf8(outputBoth, symlinkPair.first);
+ write(outputLeft, symlinkPair.second.left);
+ write(outputRight, symlinkPair.second.right);
+ }
- while (readPOD<bool>()) //symlinks
- {
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringUtf8(); //file name
- const std::int64_t modTime = readPOD<std::int64_t>();
- const Zstring targetPath = readStringUtf8(); //file name
- const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readPOD<std::int32_t>());
-
- dirCont.addSubLink(shortName,
- LinkDescriptor(modTime, targetPath, linkType));
- }
+ void process(const std::pair<Zstring, InSyncDir>& dirPair)
+ {
+ writeUtf8(outputBoth, dirPair.first);
+ write(outputBoth, dirPair.second.status);
- while (readPOD<bool>()) //directories
- {
- const Zstring shortName = readStringUtf8(); //directory name
- DirContainer& subDir = dirCont.addSubDir(shortName);
- recurse(subDir);
- }
+ recurse(dirPair.second);
}
+
+ BinStreamOut outputLeft; //data related to one side only
+ BinStreamOut outputRight; //
+ BinStreamOut outputBoth; //data concerning both sides
};
-//save/load DirContainer
-void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw FileError
+class StreamParser //for db-file back-wards compatibility we stick with two output streams until further
{
+public:
+ static std::shared_ptr<InSyncDir> execute(const BinaryStream& streamL, //throw FileError
+ const BinaryStream& streamR,
+ const Zstring& filenameL, //used for diagnostics only
+ const Zstring& filenameR)
{
- FileOutputStream rawStream(filename); //throw FileError
+ auto decompStream = [](const BinaryStream& stream, const Zstring& filename) -> BinaryStream //throw FileError
+ {
+ try
+ {
+ return decompress(stream); //throw ZlibInternalError
+ }
+ catch (ZlibInternalError&)
+ {
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(filename)) + L" (zlib error)");
+ }
+ };
+
+ try
+ {
+ BinStreamIn inL(streamL);
+ BinStreamIn inR(streamR);
+
+ bool has1stPartL = readNumber<bool>(inL); //throw UnexpectedEndOfStreamError
+ bool has1stPartR = readNumber<bool>(inR); //
+
+#ifdef FFS_WIN
+warn_static("restore check after migration!")
+#endif
- //write FreeFileSync file identifier
- rawStream.Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw FileError
+ //if (has1stPartL == has1stPartR)
+ // throw UnexpectedEndOfStreamError();
- wxZlibOutputStream compressed(rawStream, 4, wxZLIB_ZLIB);
- /* 4 - best compromise between speed and compression: (scanning 200.000 objects)
- 0 (uncompressed) 8,95 MB - 422 ms
- 2 2,07 MB - 470 ms
- 4 1,87 MB - 500 ms
- 6 1,77 MB - 613 ms
- 9 (maximal compression) 1,74 MB - 3330 ms */
+ BinStreamIn& in1stPart = has1stPartL ? inL : inR;
+ BinStreamIn& in2ndPart = has1stPartL ? inR : inL;
- CheckedDbWriter cw(compressed, filename);
+ const size_t size1stPart = readNumber<std::uint64_t>(in1stPart);
+ const size_t size2ndPart = readNumber<std::uint64_t>(in2ndPart);
- //save file format version
- cw.writePOD<std::int32_t>(FILE_FORMAT_VER);
+ BinaryStream tmpB;
+ tmpB.resize(size1stPart + size2ndPart);
+ readArray(in1stPart, &*tmpB.begin(), size1stPart);
+ readArray(in2ndPart, &*tmpB.begin() + size1stPart, size2ndPart);
- //save stream list
- cw.writePOD<std::uint32_t>(static_cast<std::uint32_t>(streamList.size())); //number of database records: one for each sync-pair
+ const BinaryStream tmpL = readContainer<BinaryStream>(inL);
+ const BinaryStream tmpR = readContainer<BinaryStream>(inR);
- for (auto iter = streamList.begin(); iter != streamList.end(); ++iter)
+ auto output = std::make_shared<InSyncDir>(InSyncDir::STATUS_IN_SYNC);
+ StreamParser(decompStream(tmpL, filenameL),
+ decompStream(tmpR, filenameR),
+ decompStream(tmpB, filenameL + Zstr("/") + filenameR),
+ *output); //throw UnexpectedEndOfStreamError
+ return output;
+ }
+ catch (const UnexpectedEndOfStreamError&)
{
- cw.writeString<std::string >(iter->first ); //sync session id
- cw.writeString<MemoryStream>(iter->second); //DirInformation stream
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filenameL) + L"\n" + fmtFileName(filenameR));
+ }
+ catch (const std::bad_alloc& e) //still required?
+ {
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filenameL) + L"\n" + fmtFileName(filenameR) + L"\n\n" +
+ _("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
}
}
-#ifdef FFS_WIN
- ::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); //(try to) hide database file
-#endif
-}
+private:
+ StreamParser(const BinaryStream& bufferL,
+ const BinaryStream& bufferR,
+ const BinaryStream& bufferB,
+ InSyncDir& container) :
+ inputLeft (bufferL),
+ inputRight(bufferR),
+ inputBoth (bufferB) { recurse(container); }
-template <SelectedSide side>
-class StreamGenerator : private CheckedDbWriter
-{
-public:
- static MemoryStream execute(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName)
+ static Zstring readUtf8(BinStreamIn& input) { return utfCvrtTo<Zstring>(readContainer<Zbase<char>>(input)); } //throw UnexpectedEndOfStreamError
+
+ static void read(BinStreamIn& input, FileDescriptor& descr)
{
- wxMemoryOutputStream buffer;
- StreamGenerator(baseMapping, oldDirInfo, errorObjName, buffer);
+ //attention: order of function argument evaluation is undefined! So do it one after the other...
+ descr.lastWriteTimeRaw = readNumber<std::int64_t>(input); //throw UnexpectedEndOfStreamError
+ descr.fileSize = readNumber<std::uint64_t>(input);
+ descr.id.first = static_cast<decltype(descr.id.first )>(readNumber<std::uint64_t>(input)); //
+ descr.id.second = static_cast<decltype(descr.id.second)>(readNumber<std::uint64_t>(input)); //silence "loss of precision" compiler warnings
+ }
- MemoryStream output;
- output.resize(buffer.GetSize());
- buffer.CopyTo(&*output.begin(), buffer.GetSize());
- return output;
+ static void read(BinStreamIn& input, LinkDescriptor& descr)
+ {
+ descr.lastWriteTimeRaw = readNumber<std::int64_t>(input);
+ descr.targetPath = readUtf8(input); //file name
+ descr.type = static_cast<LinkDescriptor::LinkType>(readNumber<std::int32_t>(input));
}
-private:
- StreamGenerator(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : CheckedDbWriter(stream, errorObjName)
+ static void read(BinStreamIn& input, InSyncDir::InSyncStatus& status)
{
- recurse(baseMapping, oldDirInfo);
+ status = static_cast<InSyncDir::InSyncStatus>(readNumber<std::int32_t>(input));
}
- void recurse(const HierarchyObject& hierObj, const DirContainer* oldDirInfo)
+ void recurse(InSyncDir& container)
{
- // for (const auto& fileMap : hierObj.refSubFiles()) { processFile(fileMap, oldDirInfo); }); !
+ size_t fileCount = readNumber<std::uint32_t>(inputBoth);
+ while (fileCount-- != 0) //files
+ {
+ const Zstring shortName = readUtf8(inputBoth);
+ const auto inSyncType = static_cast<InSyncFile::InSyncType>(readNumber<std::int32_t>(inputBoth));
+
+ FileDescriptor dataL;
+ FileDescriptor dataR;
+ read(inputLeft, dataL);
+ read(inputRight, dataR);
+
+ container.addFile(shortName, dataL, dataR, inSyncType);
+ }
+
+ size_t linkCount = readNumber<std::uint32_t>(inputBoth);
+ while (linkCount-- != 0) //files
+ {
+ const Zstring shortName = readUtf8(inputBoth);
+
+ LinkDescriptor dataL;
+ LinkDescriptor dataR;
+ read(inputLeft, dataL);
+ read(inputRight, dataR);
+
+ container.addSymlink(shortName, dataL, dataR);
+ }
+
+ size_t dirCount = readNumber<std::uint32_t>(inputBoth);
+ while (dirCount-- != 0) //files
+ {
+ const Zstring shortName = readUtf8(inputBoth);
- std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](const FileMapping& fileMap) { this->processFile(fileMap, oldDirInfo); });
- writePOD<bool>(false); //mark last entry
- std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](const SymLinkMapping& linkObj) { this->processLink(linkObj, oldDirInfo); });
- writePOD<bool>(false); //mark last entry
- std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](const DirMapping& dirMap) { this->processDir (dirMap, oldDirInfo); });
- writePOD<bool>(false); //mark last entry
+ InSyncDir::InSyncStatus status = InSyncDir::STATUS_STRAW_MAN;
+ read(inputBoth, status);
+
+ InSyncDir& subDir = container.addDir(shortName, status);
+ recurse(subDir);
+ }
}
- void writeStringUtf8(const Zstring& str) { writeString(utfCvrtTo<Zbase<char>>(str)); }
+ BinStreamIn inputLeft; //data related to one side only
+ BinStreamIn inputRight; //
+ BinStreamIn inputBoth; //data concerning both sides
+};
- void writeFileId(const FileId& id)
+//#######################################################################################################################################
+
+class UpdateLastSynchronousState
+{
+ /*
+ 1. filter by file name does *not* create a new hierarchy, but merely gives a different *view* on the existing file hierarchy
+ => only update database entries matching this view!
+ 2. Symlink handling *does* create a new (asymmetric) hierarchies during comparison
+ => update all database entries!
+ */
+public:
+ static void execute(const BaseDirMapping& baseMapping, InSyncDir& dir)
{
- writePOD<std::uint64_t>(id.first ); //device id
- writePOD<std::uint64_t>(id.second); //file id
+ bool binaryComparison = false;
+ switch (baseMapping.getCompVariant())
+ {
+ case CMP_BY_TIME_SIZE:
+ break;
+ case CMP_BY_CONTENT:
+ binaryComparison = true;
+ break;
+ }
+
+ UpdateLastSynchronousState updater(baseMapping.getFilter(), binaryComparison);
+ updater.recurse(baseMapping, dir);
}
-#ifdef _MSC_VER
- warn_static("support multiple folder pairs that differ in hard filter only?")
-#endif
+private:
+ UpdateLastSynchronousState(const HardFilter& filter, bool binaryComparison) :
+ filter_(filter),
+ binaryComparison_(binaryComparison) {}
- void processFile(const FileMapping& fileMap, const DirContainer* oldParentDir)
+ void recurse(const HierarchyObject& hierObj, InSyncDir& dir)
{
- if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state
+ process(hierObj.refSubFiles(), hierObj.getObjRelativeNamePf(), dir.files);
+ process(hierObj.refSubLinks(), hierObj.getObjRelativeNamePf(), dir.symlinks);
+ process(hierObj.refSubDirs (), hierObj.getObjRelativeNamePf(), dir.dirs);
+ }
+
+ template <class M, class V>
+ static V& updateItem(M& map, const Zstring& key, const V& value) //efficient create or update without "default-constructible" requirement (Effective STL, item 24)
+ {
+ auto iter = map.lower_bound(key);
+ if (iter != map.end() && !(map.key_comp()(key, iter->first)))
{
- if (!fileMap.isEmpty<side>())
+#ifdef FFS_WIN //caveat: key might need to be updated, too, if there is a change in short name case!!!
+ if (iter->first != key)
{
- writePOD<bool>(true); //mark beginning of entry
- writeStringUtf8(fileMap.getShortName<side>()); //save respecting case! (Windows)
- writePOD<std:: int64_t>(to<std:: int64_t>(fileMap.getLastWriteTime<side>()));
- writePOD<std::uint64_t>(to<std::uint64_t>(fileMap.getFileSize<side>()));
- writeFileId(fileMap.getFileId<side>());
+ map.erase(iter); //don't fiddle with decrementing "iter"! - you might lose while optimizing pointlessly
+ return map.insert(typename M::value_type(key, value)).first->second;
}
- }
- else //not in sync: reuse last synchronous state
- {
- if (oldParentDir) //no data is also a "synchronous state"!
+ else
+#endif
{
- auto iter = oldParentDir->files.find(fileMap.getObjShortName());
- if (iter != oldParentDir->files.end())
- {
- writePOD<bool>(true); //mark beginning of entry
- writeStringUtf8(iter->first); //save respecting case! (Windows)
- writePOD<std:: int64_t>(to<std:: int64_t>(iter->second.lastWriteTimeRaw));
- writePOD<std::uint64_t>(to<std::uint64_t>(iter->second.fileSize));
- writeFileId(iter->second.id);
- }
+ iter->second = value;
+ return iter->second;
}
}
+ return map.insert(iter, typename M::value_type(key, value))->second;
}
- void processLink(const SymLinkMapping& linkObj, const DirContainer* oldParentDir)
+ void process(const HierarchyObject::SubFileVec& currentFiles, const Zstring& parentRelativeNamePf, InSyncDir::FileList& dbFiles)
{
- if (linkObj.getLinkCategory() == SYMLINK_EQUAL) //data in sync: write current state
- {
- if (!linkObj.isEmpty<side>())
- {
- writePOD<bool>(true); //mark beginning of entry
- writeStringUtf8(linkObj.getShortName<side>()); //save respecting case! (Windows)
- writePOD<std::int64_t>(to<std::int64_t>(linkObj.getLastWriteTime<side>()));
- writeStringUtf8(linkObj.getTargetPath<side>());
- writePOD<std::int32_t>(linkObj.getLinkType<side>());
- }
- }
- else //not in sync: reuse last synchronous state
+ hash_set<const InSyncFile*> toPreserve; //referencing fixed-in-memory std::map elements
+ std::for_each(currentFiles.begin(), currentFiles.end(), [&](const FileMapping& fileMap)
{
- if (oldParentDir) //no data is also a "synchronous state"!
+ if (!fileMap.isEmpty())
{
- auto iter = oldParentDir->links.find(linkObj.getObjShortName());
- if (iter != oldParentDir->links.end())
+ if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state
{
- writePOD<bool>(true); //mark beginning of entry
- writeStringUtf8(iter->first); //save respecting case! (Windows)
- writePOD<std::int64_t>(to<std::int64_t>(iter->second.lastWriteTimeRaw));
- writeStringUtf8(iter->second.targetPath);
- writePOD<std::int32_t>(iter->second.type);
+ //create or update new "in-sync" state
+ InSyncFile& file = updateItem(dbFiles, fileMap.getObjShortName(),
+ InSyncFile(FileDescriptor(fileMap.getLastWriteTime<LEFT_SIDE>(),
+ fileMap.getFileSize <LEFT_SIDE>(),
+ fileMap.getFileId <LEFT_SIDE>()),
+ FileDescriptor(fileMap.getLastWriteTime<RIGHT_SIDE>(),
+ fileMap.getFileSize <RIGHT_SIDE>(),
+ fileMap.getFileId <RIGHT_SIDE>()),
+ binaryComparison_ ?
+ InSyncFile::IN_SYNC_BINARY_EQUAL :
+ InSyncFile::IN_SYNC_ATTRIBUTES_EQUAL)); //efficient add or update (Effective STL, item 24)
+ //Caveat: If FILE_EQUAL, we *implicitly* assume equal left and right short names matching case: InSyncDir's mapping tables use short name as a key!
+ //This makes us silently dependent from code in algorithm.h!!!
+ toPreserve.insert(&file);
+ }
+ else //not in sync: preserve last synchronous state
+ {
+ auto iter = dbFiles.find(fileMap.getObjShortName());
+ if (iter != dbFiles.end())
+ toPreserve.insert(&iter->second);
}
}
- }
+ });
+
+ //delete removed items (= "in-sync") from database
+ map_remove_if(dbFiles, [&](const InSyncDir::FileList::value_type& v) -> bool
+ {
+ if (toPreserve.find(&v.second) != toPreserve.end())
+ return false;
+ //all items not existing in "currentFiles" have either been deleted meanwhile or been excluded via filter:
+ const Zstring& shortName = v.first;
+ return filter_.passFileFilter(parentRelativeNamePf + shortName);
+ });
}
- void processDir(const DirMapping& dirMap, const DirContainer* oldParentDir)
+ void process(const HierarchyObject::SubLinkVec& currentLinks, const Zstring& parentRelativeNamePf, InSyncDir::LinkList& dbLinks)
{
- const DirContainer* oldDir = nullptr;
- const Zstring* oldDirName = nullptr;
- if (oldParentDir) //no data is also a "synchronous state"!
+ hash_set<const InSyncSymlink*> toPreserve;
+ std::for_each(currentLinks.begin(), currentLinks.end(), [&](const SymLinkMapping& linkMap)
{
- auto iter = oldParentDir->dirs.find(dirMap.getObjShortName());
- if (iter != oldParentDir->dirs.end())
+ if (!linkMap.isEmpty())
{
- oldDirName = &iter->first;
- oldDir = &iter->second;
+ if (linkMap.getLinkCategory() == SYMLINK_EQUAL) //data in sync: write current state
+ {
+ //create or update new "in-sync" state
+ InSyncSymlink& link = updateItem(dbLinks, linkMap.getObjShortName(),
+ InSyncSymlink(LinkDescriptor(linkMap.getLastWriteTime<LEFT_SIDE>(),
+ linkMap.getTargetPath <LEFT_SIDE>(),
+ linkMap.getLinkType <LEFT_SIDE>()),
+ LinkDescriptor(linkMap.getLastWriteTime<RIGHT_SIDE>(),
+ linkMap.getTargetPath <RIGHT_SIDE>(),
+ linkMap.getLinkType <RIGHT_SIDE>()))); //efficient add or update (Effective STL, item 24)
+ toPreserve.insert(&link);
+ }
+ else //not in sync: preserve last synchronous state
+ {
+ auto iter = dbLinks.find(linkMap.getObjShortName());
+ if (iter != dbLinks.end())
+ toPreserve.insert(&iter->second);
+ }
}
- }
+ });
- CompareDirResult cat = dirMap.getDirCategory();
-
- if (cat == DIR_EQUAL) //data in sync: write current state
+ //delete removed items (= "in-sync") from database
+ map_remove_if(dbLinks, [&](const InSyncDir::LinkList::value_type& v) -> bool
{
- if (!dirMap.isEmpty<side>())
- {
- writePOD<bool>(true); //mark beginning of entry
- writeStringUtf8(dirMap.getShortName<side>()); //save respecting case! (Windows)
- recurse(dirMap, oldDir);
- }
- }
- else //not in sync: reuse last synchronous state
- {
- if (oldDir)
- {
- writePOD<bool>(true); //mark beginning of entry
- writeStringUtf8(*oldDirName); //save respecting case! (Windows)
- recurse(dirMap, oldDir);
- return;
- }
- //no data is also a "synchronous state"!
+ if (toPreserve.find(&v.second) != toPreserve.end())
+ return false;
+ //all items not existing in "currentLinks" have either been deleted meanwhile or been excluded via filter:
+ const Zstring& shortName = v.first;
+ return filter_.passFileFilter(parentRelativeNamePf + shortName);
+ });
+ }
- //else: not in sync AND no "last synchronous state"
- //we cannot simply skip the whole directory, since sub-items might be in sync
- //Example: directories on left and right differ in case while sub-files are equal
- switch (cat)
+ void process(const HierarchyObject::SubDirVec& currentDirs, const Zstring& parentRelativeNamePf, InSyncDir::DirList& dbDirs)
+ {
+ hash_set<const InSyncDir*> toPreserve;
+ std::for_each(currentDirs.begin(), currentDirs.end(), [&](const DirMapping& dirMap)
+ {
+ if (!dirMap.isEmpty())
{
- case DIR_LEFT_SIDE_ONLY: //sub-items cannot be in sync
- break;
- case DIR_RIGHT_SIDE_ONLY: //sub-items cannot be in sync
+ switch (dirMap.getDirCategory())
+ {
+ case DIR_EQUAL:
+ {
+ //update directory entry only (shallow), but do *not touch* exising child elements!!!
+ const Zstring& key = dirMap.getObjShortName();
+ auto insertResult = dbDirs.insert(std::make_pair(key, InSyncDir(InSyncDir::STATUS_IN_SYNC))); //get or create
+ auto iter = insertResult.first;
+
+#ifdef FFS_WIN //caveat: key might need to be updated, too, if there is a change in short name case!!!
+ const bool alreadyExisting = !insertResult.second;
+ if (alreadyExisting && iter->first != key)
+ {
+ auto oldValue = std::move(iter->second);
+ dbDirs.erase(iter); //don't fiddle with decrementing "iter"! - you might lose while optimizing pointlessly
+ iter = dbDirs.insert(InSyncDir::DirList::value_type(key, std::move(oldValue))).first;
+ }
+#endif
+ InSyncDir& dir = iter->second;
+ dir.status = InSyncDir::STATUS_IN_SYNC; //update immediate directory entry
+ toPreserve.insert(&dir);
+ recurse(dirMap, dir);
+ }
break;
- case DIR_EQUAL:
- assert(false);
+
+ case DIR_DIFFERENT_METADATA:
+ //if DIR_DIFFERENT_METADATA and no old database entry yet: we have to insert a new (bogus) database entry:
+ //we cannot simply skip the whole directory, since sub-items might be in sync!
+ //Example: directories on left and right differ in case while sub-files are equal
+ {
+ //reuse last "in-sync" if available or insert strawman entry (do not try to update thereby removing child elements!!!)
+ InSyncDir& dir = dbDirs.insert(std::make_pair(dirMap.getObjShortName(), InSyncDir(InSyncDir::STATUS_STRAW_MAN))).first->second;
+ toPreserve.insert(&dir);
+ recurse(dirMap, dir);
+ }
break;
- case DIR_DIFFERENT_METADATA:
- writePOD<bool>(true);
- writeStringUtf8(dirMap.getShortName<side>());
- //ATTENTION: strictly this is a violation of the principle of reporting last synchronous state!
- //however in this case this will result in "last sync unsuccessful" for this directory within <automatic> algorithm, which is fine
- recurse(dirMap, oldDir); //recurse and save sub-items which are in sync
+
+ //not in sync: reuse last synchronous state:
+ case DIR_LEFT_SIDE_ONLY:
+ case DIR_RIGHT_SIDE_ONLY:
+ {
+ auto iter = dbDirs.find(dirMap.getObjShortName());
+ if (iter != dbDirs.end())
+ {
+ toPreserve.insert(&iter->second);
+ recurse(dirMap, iter->second); //although existing sub-items cannot be in sync, items deleted on both sides *are* in-sync!!!
+ }
+ }
break;
+ }
}
- }
+ });
+
+ //delete removed items (= "in-sync") from database
+ map_remove_if(dbDirs, [&](const InSyncDir::DirList::value_type& v) -> bool
+ {
+ if (toPreserve.find(&v.second) != toPreserve.end())
+ return false;
+ //all items not existing in "currentDirs" have either been deleted meanwhile or been excluded via filter:
+ const Zstring& shortName = v.first;
+ return filter_.passDirFilter(parentRelativeNamePf + shortName, nullptr);
+ //if directory is not included in "currentDirs", it is either not existing anymore, in which case it should be deleted from database
+ //or it was excluded via filter, in which case the database entry should be preserved -> we can't tell and need to preserve the old db entry
+ });
}
+
+ const HardFilter& filter_; //filter used while scanning directory: generates view on actual files!
+ const bool binaryComparison_;
};
}
-//#######################################################################################################################################
+//#######################################################################################################################################
-std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw FileError
+std::shared_ptr<InSyncDir> zen::loadLastSynchronousState(const BaseDirMapping& baseMapping) //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
{
const Zstring fileNameLeft = getDBFilename<LEFT_SIDE >(baseMapping);
const Zstring fileNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
+ if (!baseMapping.wasExisting<LEFT_SIDE >() ||
+ !baseMapping.wasExisting<RIGHT_SIDE>())
+ {
+ //avoid race condition with directory existence check: reading sync.ffs_db may succeed although first dir check had failed => conflicts!
+ //https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3531351&group_id=234430
+ const Zstring filename = !baseMapping.wasExisting<LEFT_SIDE>() ? fileNameLeft : fileNameRight;
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" + //it could be due to a to-be-created target directory not yet existing => FileErrorDatabaseNotExisting
+ replaceCpy(_("Database file %x does not yet exist."), L"%x", fmtFileName(filename)));
+ }
+
//read file data: list of session ID + DirInfo-stream
- const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError
- const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError
+ const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError, FileErrorDatabaseNotExisting
+ const StreamMapping streamListRight = ::loadStreams(fileNameRight); //
//find associated session: there can be at most one session within intersection of left and right ids
for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
@@ -430,20 +694,18 @@ std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMa
auto iterRight = streamListRight.find(iterLeft->first);
if (iterRight != streamListRight.end())
{
- //read streams into DirInfo
- DirInfoPtr dirInfoLeft = StreamParser::execute(iterLeft ->second, fileNameLeft); //throw FileError
- DirInfoPtr dirInfoRight = StreamParser::execute(iterRight->second, fileNameRight); //throw FileError
-
- return std::make_pair(dirInfoLeft, dirInfoRight);
+ return StreamParser::execute(iterLeft ->second, //throw FileError
+ iterRight->second,
+ fileNameLeft,
+ fileNameRight);
}
}
-
throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" +
_("Database files do not share a common session."));
}
-void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError
+void zen::saveLastSynchronousState(const BaseDirMapping& baseMapping) //throw FileError
{
//transactional behaviour! write to tmp files first
const Zstring dbNameLeftTmp = getDBFilename<LEFT_SIDE >(baseMapping, true);
@@ -468,72 +730,252 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError
//if error occurs: just overwrite old file! User is already informed about issues right after comparing!
//find associated session: there can be at most one session within intersection of left and right ids
- auto streamLeftOld = streamListLeft .cend();
- auto streamRightOld = streamListRight.cend();
+ auto streamIterLeftOld = streamListLeft .cend();
+ auto streamIterRightOld = streamListRight.cend();
for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
{
auto iterRight = streamListRight.find(iterLeft->first);
if (iterRight != streamListRight.end())
{
- streamLeftOld = iterLeft;
- streamRightOld = iterRight;
+ streamIterLeftOld = iterLeft;
+ streamIterRightOld = iterRight;
break;
}
}
- //(try to) read old DirInfo
- DirInfoPtr dirInfoLeftOld;
- DirInfoPtr dirInfoRightOld;
- if (streamLeftOld != streamListLeft .end() &&
- streamRightOld != streamListRight.end())
+ //load last synchrounous state
+ std::shared_ptr<InSyncDir> lastSyncState = std::make_shared<InSyncDir>(InSyncDir::STATUS_IN_SYNC);
+ if (streamIterLeftOld != streamListLeft .end() &&
+ streamIterRightOld != streamListRight.end())
try
{
- dirInfoLeftOld = StreamParser::execute(streamLeftOld ->second, dbNameLeft ); //throw FileError
- dirInfoRightOld = StreamParser::execute(streamRightOld->second, dbNameRight); //throw FileError
- }
- catch (FileError&)
- {
- //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- dirInfoLeftOld .reset(); //read both or none!
- dirInfoRightOld.reset(); //
+ lastSyncState = StreamParser::execute(streamIterLeftOld ->second, //throw FileError
+ streamIterRightOld->second,
+ dbNameLeft,
+ dbNameRight);
}
+ catch (FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- //create new database entries
- MemoryStream rawStreamLeftNew = StreamGenerator<LEFT_SIDE >::execute(baseMapping, dirInfoLeftOld .get() ? &dirInfoLeftOld ->baseDirContainer : nullptr, dbNameLeft);
- MemoryStream rawStreamRightNew = StreamGenerator<RIGHT_SIDE>::execute(baseMapping, dirInfoRightOld.get() ? &dirInfoRightOld->baseDirContainer : nullptr, dbNameRight);
+ //update last synchrounous state
+ UpdateLastSynchronousState::execute(baseMapping, *lastSyncState);
+
+ //serialize again
+ BinaryStream updatedStreamLeft;
+ BinaryStream updatedStreamRight;
+ StreamGenerator::execute(*lastSyncState,
+ dbNameLeft,
+ dbNameRight,
+ updatedStreamLeft,
+ updatedStreamRight, false); //throw FileError
//check if there is some work to do at all
- if (streamLeftOld != streamListLeft .end() && rawStreamLeftNew == streamLeftOld ->second &&
- streamRightOld != streamListRight.end() && rawStreamRightNew == streamRightOld->second)
+ if (streamIterLeftOld != streamListLeft .end() && updatedStreamLeft == streamIterLeftOld ->second &&
+ streamIterRightOld != streamListRight.end() && updatedStreamRight == streamIterRightOld->second)
return; //some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed
//erase old session data
- if (streamLeftOld != streamListLeft.end())
- streamListLeft.erase(streamLeftOld);
- if (streamRightOld != streamListRight.end())
- streamListRight.erase(streamRightOld);
+ if (streamIterLeftOld != streamListLeft.end())
+ streamListLeft.erase(streamIterLeftOld);
+ if (streamIterRightOld != streamListRight.end())
+ streamListRight.erase(streamIterRightOld);
//create/update DirInfo-streams
const std::string sessionID = zen::generateGUID();
//fill in new
- streamListLeft .insert(std::make_pair(sessionID, rawStreamLeftNew));
- streamListRight.insert(std::make_pair(sessionID, rawStreamRightNew));
+ streamListLeft [sessionID] = std::move(updatedStreamLeft);
+ streamListRight[sessionID] = std::move(updatedStreamRight);
//write (temp-) files...
zen::ScopeGuard guardTempFileLeft = zen::makeGuard([&] {zen::removeFile(dbNameLeftTmp); });
- saveFile(streamListLeft, dbNameLeftTmp); //throw FileError
+ saveStreams(streamListLeft, dbNameLeftTmp); //throw FileError
zen::ScopeGuard guardTempFileRight = zen::makeGuard([&] {zen::removeFile(dbNameRightTmp); });
- saveFile(streamListRight, dbNameRightTmp); //throw FileError
+ saveStreams(streamListRight, dbNameRightTmp); //throw FileError
//operation finished: rename temp files -> this should work transactionally:
//if there were no write access, creation of temp files would have failed
- removeFile(dbNameLeft);
- removeFile(dbNameRight);
- renameFile(dbNameLeftTmp, dbNameLeft); //throw FileError;
- renameFile(dbNameRightTmp, dbNameRight); //throw FileError;
+ removeFile(dbNameLeft); //
+ removeFile(dbNameRight); //throw FileError
+ renameFile(dbNameLeftTmp, dbNameLeft); //
+ renameFile(dbNameRightTmp, dbNameRight); //
guardTempFileLeft. dismiss(); //no need to delete temp file anymore
guardTempFileRight.dismiss(); //
}
+
+#ifdef FFS_WIN
+warn_static("remove after migration")
+#endif
+
+namespace
+{
+class CheckedDbReader : public CheckedReader
+{
+public:
+ CheckedDbReader(wxInputStream& stream, const Zstring& errorObjName) : CheckedReader(stream), errorObjName_(errorObjName) {}
+
+private:
+ virtual void throwException() const { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(errorObjName_))); }
+
+ const Zstring errorObjName_;
+};
+
+
+class StreamParser_v8 //for db-file back-wards compatibility we stick with two output streams until further
+{
+public:
+ static std::shared_ptr<InSyncDir> execute(const BinaryStream& streamL, const BinaryStream& streamR, //throw FileError
+ const Zstring& filenameL, //used for diagnostics only
+ const Zstring& filenameR)
+ {
+ try
+ {
+ auto output = std::make_shared<InSyncDir>(InSyncDir::STATUS_IN_SYNC);
+ StreamParser_v8 parser(streamL, streamR); //throw UnexpectedEndOfStreamError, std::bad_alloc
+ parser.recurse(*output);
+ return output;
+ }
+ catch (const UnexpectedEndOfStreamError&)
+ {
+ throw FileError(_("Database file is corrupt:") + L"\n" + fmtFileName(filenameL) + L"\n" + fmtFileName(filenameR));
+ }
+ catch (const std::bad_alloc& e)
+ {
+ throw FileError(_("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
+ }
+ }
+
+private:
+ StreamParser_v8(const BinaryStream& bufferL,
+ const BinaryStream& bufferR) :
+ inputLeft (bufferL), //input is referenced only!
+ inputRight(bufferR) {}
+
+ static Zstring readUtf8(BinStreamIn& input) { return utfCvrtTo<Zstring>(readContainer<Zbase<char>>(input)); } //throw UnexpectedEndOfStreamError
+
+ static void read(BinStreamIn& input, Zstring& shortName, FileDescriptor& descr)
+ {
+ //attention: order of function argument evaluation is undefined! So do it one after the other...
+ shortName = readUtf8(input);
+ descr.lastWriteTimeRaw = readNumber<std::int64_t>(input); //throw UnexpectedEndOfStreamError
+ descr.fileSize = readNumber<std::uint64_t>(input);
+ descr.id.first = static_cast<decltype(descr.id.first )>(readNumber<std::uint64_t>(input)); //
+ descr.id.second = static_cast<decltype(descr.id.second)>(readNumber<std::uint64_t>(input)); //silence "loss of precision" compiler warnings
+ }
+
+ static void read(BinStreamIn& input, Zstring& shortName, LinkDescriptor& descr)
+ {
+ shortName = readUtf8(input);
+ descr.lastWriteTimeRaw = readNumber<std::int64_t>(input);
+ descr.targetPath = readUtf8(input); //file name
+ descr.type = static_cast<LinkDescriptor::LinkType>(readNumber<std::int32_t>(input));
+ }
+
+ void recurse(InSyncDir& dir)
+ {
+ for (;;) //files
+ {
+ bool haveItemL = readNumber<bool>(inputLeft ); //remove redundancy in next db format
+ bool haveItemR = readNumber<bool>(inputRight); //
+ assert(haveItemL == haveItemR);
+ if (!haveItemL || !haveItemR) break;
+
+ Zstring shortName;
+ FileDescriptor dataL;
+ FileDescriptor dataR;
+ read(inputLeft, shortName, dataL);
+ read(inputRight, shortName, dataR);
+
+ dir.addFile(shortName, dataL, dataR, InSyncFile::IN_SYNC_ATTRIBUTES_EQUAL);
+ }
+
+ for (;;) //symlinks
+ {
+ bool haveItemL = readNumber<bool>(inputLeft );
+ bool haveItemR = readNumber<bool>(inputRight);
+ assert(haveItemL == haveItemR);
+ if (!haveItemL || !haveItemR) break;
+
+ Zstring shortName;
+ LinkDescriptor dataL;
+ LinkDescriptor dataR;
+ read(inputLeft, shortName, dataL);
+ read(inputRight, shortName, dataR);
+
+ dir.addSymlink(shortName, dataL, dataR);
+ }
+
+ for (;;) //directories
+ {
+ bool haveItemL = readNumber<bool>(inputLeft );
+ bool haveItemR = readNumber<bool>(inputRight);
+ assert(haveItemL == haveItemR);
+ if (!haveItemL || !haveItemR) break;
+
+ Zstring shortName = readUtf8(inputLeft);
+ shortName = readUtf8(inputRight);
+ InSyncDir& subDir = dir.addDir(shortName, InSyncDir::STATUS_IN_SYNC);
+ recurse(subDir);
+ }
+ }
+
+ BinStreamIn inputLeft;
+ BinStreamIn inputRight;
+};
+
+
+StreamMapping loadStreams_v8(const Zstring& filename) //throw FileError
+{
+ try
+ {
+ //read format description (uncompressed)
+ FileInputStream rawStream(filename); //throw FileError, ErrorNotExisting
+
+ //read FreeFileSync file identifier
+ char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {};
+ rawStream.Read(formatDescr, sizeof(formatDescr)); //throw FileError
+
+ if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr))
+ throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
+
+ wxZlibInputStream decompressed(rawStream, wxZLIB_ZLIB);
+
+ CheckedDbReader cr(decompressed, filename);
+
+ std::int32_t version = cr.readPOD<std::int32_t>();
+ if (version != 8) //read file format version#
+ throw FileError(replaceCpy(_("Database file %x is incompatible."), L"%x", fmtFileName(filename)));
+
+ //read stream lists
+ StreamMapping output;
+
+ std::uint32_t dbCount = cr.readPOD<std::uint32_t>(); //number of databases: one for each sync-pair
+ while (dbCount-- != 0)
+ {
+ //DB id of partner databases
+ std::string sessionID = cr.readString<std::string>();
+ BinaryStream stream = cr.readString<BinaryStream>(); //read db-entry stream (containing DirInformation)
+
+ //convert streams
+ std::shared_ptr<InSyncDir> lastSyncState = StreamParser_v8::execute(stream, stream, filename, filename); //throw FileError
+
+ //serialize again
+ BinaryStream strL;
+ BinaryStream strR;
+ StreamGenerator::execute(*lastSyncState, filename, filename, strL, strR, true); //throw FileError
+ output[sessionID] = std::move(strL);
+ }
+ return output;
+ }
+ catch (ErrorNotExisting&)
+ {
+ throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n" +
+ replaceCpy(_("Database file %x does not yet exist."), L"%x", fmtFileName(filename)));
+ }
+ catch (const std::bad_alloc& e)
+ {
+ throw FileError(_("Out of memory!") + L" " + utfCvrtTo<std::wstring>(e.what()));
+ }
+}
+}
diff --git a/lib/db_file.h b/lib/db_file.h
index e5ae7b50..4425f52c 100644
--- a/lib/db_file.h
+++ b/lib/db_file.h
@@ -14,17 +14,75 @@ namespace zen
{
const Zstring SYNC_DB_FILE_ENDING = Zstr(".ffs_db");
-struct DirInformation
+//artificial hierarchy of last synchronous state:
+struct InSyncFile
{
- DirContainer baseDirContainer; //hierarchical directory information
+ enum InSyncType
+ {
+ IN_SYNC_BINARY_EQUAL, //checked file content
+ IN_SYNC_ATTRIBUTES_EQUAL, //only "looks" like they're equal
+ };
+
+ InSyncFile(const FileDescriptor& l, const FileDescriptor& r, InSyncType type) : left(l), right(r), inSyncType(type) {}
+ FileDescriptor left;
+ FileDescriptor right;
+ InSyncType inSyncType;
+};
+
+struct InSyncSymlink
+{
+ InSyncSymlink(const LinkDescriptor& l, const LinkDescriptor& r) : left(l), right(r) {}
+ LinkDescriptor left;
+ LinkDescriptor right;
+};
+
+struct InSyncDir
+{
+ //for directories we have a logical problem: we cannot have "not existent" as an indicator for "no last synchronous state" since this precludes
+ //child elements that may be in sync!
+ enum InSyncStatus
+ {
+ STATUS_IN_SYNC,
+ STATUS_STRAW_MAN //there is no last synchronous state, but used as container only
+ };
+ InSyncDir(InSyncStatus statusIn) : status(statusIn) {}
+
+ InSyncStatus status;
+
+ //------------------------------------------------------------------
+ typedef std::map<Zstring, InSyncDir, LessFilename> DirList; //
+ typedef std::map<Zstring, InSyncFile, LessFilename> FileList; // key: shortName
+ typedef std::map<Zstring, InSyncSymlink, LessFilename> LinkList; //
+ //------------------------------------------------------------------
+
+ DirList dirs;
+ FileList files;
+ LinkList symlinks; //non-followed symlinks
+
+ //convenience
+ InSyncDir& addDir(const Zstring& shortName, InSyncStatus statusIn)
+ {
+ //use C++11 emplace when available
+ return dirs.insert(std::make_pair(shortName, InSyncDir(statusIn))).first->second;
+ }
+
+ void addFile(const Zstring& shortName, const FileDescriptor& dataL, const FileDescriptor& dataR, InSyncFile::InSyncType type)
+ {
+ files.insert(std::make_pair(shortName, InSyncFile(dataL, dataR, type)));
+ }
+
+ void addSymlink(const Zstring& shortName, const LinkDescriptor& dataL, const LinkDescriptor& dataR)
+ {
+ symlinks.insert(std::make_pair(shortName, InSyncSymlink(dataL, dataR)));
+ }
};
-typedef std::shared_ptr<const DirInformation> DirInfoPtr;
+
DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting);
-std::pair<DirInfoPtr, DirInfoPtr> loadFromDisk(const BaseDirMapping& baseMapping); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
+std::shared_ptr<InSyncDir> loadLastSynchronousState(const BaseDirMapping& baseMapping); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
-void saveToDisk(const BaseDirMapping& baseMapping); //throw FileError
+void saveLastSynchronousState(const BaseDirMapping& baseMapping); //throw FileError
}
#endif // DBFILE_H_INCLUDED
diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp
index f41bbfa8..682612a7 100644
--- a/lib/dir_lock.cpp
+++ b/lib/dir_lock.cpp
@@ -9,17 +9,15 @@
#include <wx/log.h>
//#include <wx/msgdlg.h>
#include <memory>
-#include <wx+/string_conv.h>
#include <zen/last_error.h>
#include <zen/thread.h> //includes <boost/thread.hpp>
#include <zen/scope_guard.h>
#include <zen/guid.h>
-#include <zen/file_io.h>
#include <zen/tick_count.h>
#include <zen/assert_static.h>
-#include <wx+/serialize.h>
#include <zen/int64.h>
#include <zen/file_handling.h>
+#include <wx+/serialize.h>
#ifdef FFS_WIN
#include <tlhelp32.h>
@@ -161,27 +159,6 @@ Zstring deleteAbandonedLockName(const Zstring& lockfilename) //make sure to NOT
}
-class CheckedLockReader : public CheckedReader
-{
-public:
- CheckedLockReader(wxInputStream& stream, const Zstring& errorObjName) : CheckedReader(stream), errorObjName_(errorObjName) {}
- virtual void throwException() const { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(errorObjName_))); }
-
-private:
- const Zstring errorObjName_;
-};
-
-class CheckedLockWriter : public CheckedWriter
-{
-public:
- CheckedLockWriter(wxOutputStream& stream, const Zstring& errorObjName) : CheckedWriter(stream), errorObjName_(errorObjName) {}
- virtual void throwException() const { throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(errorObjName_))); }
-
-private:
- const Zstring errorObjName_;
-};
-
-
#ifdef FFS_WIN
std::wstring getLoginSid() //throw FileError
{
@@ -273,35 +250,35 @@ struct LockInformation //throw FileError
}
#endif
- explicit LockInformation(CheckedLockReader& reader)
+ explicit LockInformation(BinStreamIn& stream) //throw UnexpectedEndOfStreamError
{
char tmp[sizeof(LOCK_FORMAT_DESCR)] = {};
- reader.readArray(&tmp, sizeof(tmp)); //file format header
- const int lockFileVersion = reader.readPOD<boost::int32_t>(); //
+ readArray(stream, &tmp, sizeof(tmp)); //file format header
+ const int lockFileVersion = readNumber<boost::int32_t>(stream); //
if (!std::equal(std::begin(tmp), std::end(tmp), std::begin(LOCK_FORMAT_DESCR)) ||
lockFileVersion != LOCK_FORMAT_VER)
- reader.throwException();
+ throw UnexpectedEndOfStreamError(); //well, not really...!?
- reader.readString(lockId);
- reader.readString(computerName);
- reader.readString(userId);
- reader.readString(sessionId);
- processId = static_cast<decltype(processId)>(reader.readPOD<std::uint64_t>()); //[!] conversion
+ lockId = readContainer<std::string>(stream); //
+ computerName = readContainer<std::string>(stream); //UnexpectedEndOfStreamError
+ userId = readContainer<std::string>(stream); //
+ sessionId = readContainer<std::string>(stream); //
+ processId = static_cast<decltype(processId)>(readNumber<std::uint64_t>(stream)); //[!] conversion
}
- void toStream(CheckedLockWriter& writer) const
+ void toStream(BinStreamOut& stream) const //throw ()
{
- writer.writeArray(LOCK_FORMAT_DESCR, sizeof(LOCK_FORMAT_DESCR));
- writer.writePOD<boost::int32_t>(LOCK_FORMAT_VER);
+ writeArray(stream, LOCK_FORMAT_DESCR, sizeof(LOCK_FORMAT_DESCR));
+ writeNumber<boost::int32_t>(stream, LOCK_FORMAT_VER);
assert_static(sizeof(processId) <= sizeof(std::uint64_t)); //ensure portability
- writer.writeString(lockId);
- writer.writeString(computerName);
- writer.writeString(userId);
- writer.writeString(sessionId);
- writer.writePOD<std::uint64_t>(processId);
+ writeContainer(stream, lockId);
+ writeContainer(stream, computerName);
+ writeContainer(stream, userId);
+ writeContainer(stream, sessionId);
+ writeNumber<std::uint64_t>(stream, processId);
}
std::string lockId; //16 byte GUID - a universal identifier for this lock (no matter what the path is, considering symlinks, distributed network, etc.)
@@ -322,17 +299,23 @@ struct LockInformation //throw FileError
void writeLockInfo(const Zstring& lockfilename) //throw FileError
{
- FileOutputStream stream(lockfilename); //throw FileError
- CheckedLockWriter writer(stream, lockfilename);
- LockInformation(FromCurrentProcess()).toStream(writer); //throw FileError
+ BinStreamOut streamOut;
+ LockInformation(FromCurrentProcess()).toStream(streamOut);
+ saveBinStream(lockfilename, streamOut.get()); //throw FileError
}
LockInformation retrieveLockInfo(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
{
- FileInputStream stream(lockfilename); //throw FileError, ErrorNotExisting
- CheckedLockReader reader(stream, lockfilename);
- return LockInformation(reader); //throw FileError
+ BinStreamIn streamIn = loadBinStream<BinaryStream>(lockfilename); //throw FileError, ErrorNotExisting
+ try
+ {
+ return LockInformation(streamIn); //throw UnexpectedEndOfStreamError
+ }
+ catch (UnexpectedEndOfStreamError&)
+ {
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(lockfilename)));
+ }
}
diff --git a/lib/ffs_paths.h b/lib/ffs_paths.h
index 9376825b..d7987195 100644
--- a/lib/ffs_paths.h
+++ b/lib/ffs_paths.h
@@ -42,7 +42,7 @@ namespace impl
inline
const Zstring& getBinaryDir() //directory containing executable WITH path separator at end
{
- static Zstring instance = beforeLast(toZ(wxStandardPaths::Get().GetExecutablePath()), FILE_NAME_SEPARATOR) + Zstring(FILE_NAME_SEPARATOR); //extern linkage!
+ static Zstring instance = beforeLast(utfCvrtTo<Zstring>(wxStandardPaths::Get().GetExecutablePath()), FILE_NAME_SEPARATOR) + Zstring(FILE_NAME_SEPARATOR); //extern linkage!
return instance;
}
@@ -102,7 +102,7 @@ Zstring getConfigDir()
if (!dirExists(userDirectory))
try
{
- createDirectory(userDirectory); //only top directory needs to be created: no recursion necessary
+ makeDirectory(userDirectory); //only top directory needs to be created: no recursion necessary
}
catch (const FileError&) {}
diff --git a/lib/generate_logfile.h b/lib/generate_logfile.h
new file mode 100644
index 00000000..8feb696a
--- /dev/null
+++ b/lib/generate_logfile.h
@@ -0,0 +1,138 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef GEN_LOGFILE_H_93172643216748973216458732165415
+#define GEN_LOGFILE_H_93172643216748973216458732165415
+
+#include <zen/error_log.h>
+#include <zen/file_io.h>
+#include <wx+/format_unit.h>
+#include <wx+/serialize.h>
+#include "ffs_paths.h"
+
+
+namespace zen
+{
+Utf8String generateLogStream(const ErrorLog& log,
+ const std::wstring& jobName, //may be empty
+ const std::wstring& finalStatus,
+ int itemsSynced, Int64 dataSynced,
+ int itemsTotal, Int64 dataTotal,
+ long totalTime); //unit: [sec]
+
+void saveToLastSyncsLog(const Utf8String& logstream); //throw FileError
+
+
+
+
+
+
+
+//####################### implementation #######################
+namespace
+{
+Utf8String generateLogStream_impl(const ErrorLog& log,
+ const std::wstring& jobName, //may be empty
+ const std::wstring& finalStatus,
+ int itemsSynced, Int64 dataSynced,
+ int itemsTotal, Int64 dataTotal,
+ long totalTime) //unit: [sec]
+{
+ Utf8String output;
+
+ //write header
+ std::wstring headerLine = _("Batch execution") + L" - " + formatTime<std::wstring>(FORMAT_DATE);
+ if (!jobName.empty())
+ headerLine += L" - " + jobName;
+
+ //output += utfCvrtTo<MemoryStream>(headerLine);
+ //output += '\n';
+
+ //for (size_t i = 0; i < headerLine.size(); ++i) //well, this considers UTF-16 only, not true Unicode...
+ // output += '=';
+ //output += '\n';
+
+ //assemble results box
+ std::vector<std::wstring> results;
+ results.push_back(headerLine);
+ results.push_back(L"");
+ results.push_back(finalStatus);
+ results.push_back(L"");
+ if (itemsTotal != 0 || dataTotal != 0) //=: sync phase was reached and there were actual items to sync
+ {
+ results.push_back(L" " + _("Items processed:") + L" " + toGuiString(itemsSynced) + L" (" + filesizeToShortString(dataSynced) + L")");
+
+ if (itemsSynced != itemsTotal ||
+ dataSynced != dataTotal)
+ results.push_back(L" " + _("Items remaining:") + L" " + toGuiString(itemsTotal - itemsSynced) + L" (" + filesizeToShortString(dataTotal - dataSynced) + L")");
+ }
+ results.push_back(L" " + _("Total time:") + L" " + copyStringTo<std::wstring>(wxTimeSpan::Seconds(totalTime).Format()));
+
+ //calculate max width, this considers UTF-16 only, not true Unicode...
+ size_t sepLineLen = 0;
+ std::for_each(results.begin(), results.end(), [&](const std::wstring& str) { sepLineLen = std::max(sepLineLen, str.size()); });
+
+ for (size_t i = 0; i < sepLineLen; ++i) output += '_';
+ output += "\n";
+
+ std::for_each(results.begin(), results.end(), [&](const std::wstring& str) { output += utfCvrtTo<Utf8String>(str); output += '\n'; });
+
+ for (size_t i = 0; i < sepLineLen; ++i) output += '_';
+ output += "\n\n";
+
+ //write log items
+ const auto& entries = log.getEntries();
+ for (auto iter = entries.begin(); iter != entries.end(); ++iter)
+ {
+ output += utfCvrtTo<Utf8String>(formatMessage(*iter));
+ output += '\n';
+ }
+
+ return replaceCpy(output, '\n', LINE_BREAK); //don't replace line break any earlier
+}
+}
+
+
+inline
+Utf8String generateLogStream(const ErrorLog& log,
+ const std::wstring& jobName, //may be empty
+ const std::wstring& finalStatus,
+ int itemsSynced, Int64 dataSynced,
+ int itemsTotal, Int64 dataTotal,
+ long totalTime) //unit: [sec]
+{
+ return generateLogStream_impl(log, jobName, finalStatus, itemsSynced, dataSynced, itemsTotal, dataTotal, totalTime);
+}
+
+
+inline
+void saveToLastSyncsLog(const Utf8String& logstream) //throw FileError
+{
+ const Zstring filename = getConfigDir() + Zstr("LastSyncs.log");
+
+ Utf8String oldStream;
+ try
+ {
+ oldStream = loadBinStream<Utf8String>(filename); //throw FileError, ErrorNotExisting
+ }
+ catch (const ErrorNotExisting&) {}
+
+ Utf8String newStream = logstream;
+ if (!oldStream.empty())
+ {
+ newStream += LINE_BREAK;
+ newStream += LINE_BREAK;
+ newStream += oldStream;
+ }
+
+ //limit file size: 128 kB (but do not truncate new log)
+ newStream.resize(std::min(newStream.size(), std::max<size_t>(logstream.size(), 128 * 1024)));
+
+ saveBinStream(filename, newStream); //throw FileError
+}
+}
+
+#endif //GEN_LOGFILE_H_93172643216748973216458732165415
diff --git a/lib/hard_filter.cpp b/lib/hard_filter.cpp
index 603d27b0..d66fc665 100644
--- a/lib/hard_filter.cpp
+++ b/lib/hard_filter.cpp
@@ -5,14 +5,12 @@
// **************************************************************************
#include "hard_filter.h"
-#include <zen/zstring.h>
-#include <wx/string.h>
#include <set>
#include <stdexcept>
#include <vector>
-#include "../structures.h"
-#include <wx+/serialize.h>
#include <typeinfo>
+#include <iterator>
+//#include "../structures.h"
using namespace zen;
@@ -30,31 +28,31 @@ bool zen::operator<(const HardFilter& lhs, const HardFilter& rhs)
}
-void HardFilter::saveFilter(wxOutputStream& stream) const //serialize derived object
-{
- //save type information
- writeString(stream, uniqueClassIdentifier());
-
- //save actual object
- save(stream);
-}
-
-
-HardFilter::FilterRef HardFilter::loadFilter(wxInputStream& stream)
-{
- //read type information
- const Zstring uniqueClassId = readString<Zstring>(stream);
-
- //read actual object
- if (uniqueClassId == Zstr("NullFilter"))
- return NullFilter::load(stream);
- else if (uniqueClassId == Zstr("NameFilter"))
- return NameFilter::load(stream);
- else if (uniqueClassId == Zstr("CombinedFilter"))
- return CombinedFilter::load(stream);
- else
- throw std::logic_error("Programming Error: Unknown filter!");
-}
+//void HardFilter::saveFilter(ZstreamOut& stream) const //serialize derived object
+//{
+// //save type information
+// writeString(stream, uniqueClassIdentifier());
+//
+// //save actual object
+// save(stream);
+//}
+
+
+//HardFilter::FilterRef HardFilter::loadFilter(ZstreamIn& stream) //throw UnexpectedEndOfStreamError
+//{
+// //read type information
+// const std::string uniqueClassId = readString<std::string>(stream); //throw UnexpectedEndOfStreamError
+//
+// //read actual object
+// if (uniqueClassId == "NullFilter")
+// return NullFilter::load(stream);
+// else if (uniqueClassId == "NameFilter")
+// return NameFilter::load(stream);
+// else if (uniqueClassId == "CombinedFilter")
+// return CombinedFilter::load(stream);
+// else
+// throw std::logic_error("Programming Error: Unknown filter!");
+//}
namespace
@@ -240,7 +238,7 @@ std::vector<Zstring> splitByDelimiter(const Zstring& filterString)
//delimiters may be ';' or '\n'
std::vector<Zstring> output;
- const std::vector<Zstring> blocks = split(filterString, Zchar(';'));
+ const std::vector<Zstring> blocks = split(filterString, Zchar(';')); //split by less common delimiter first
std::for_each(blocks.begin(), blocks.end(),
[&](const Zstring& item)
{
@@ -377,23 +375,17 @@ bool NameFilter::cmpLessSameType(const HardFilter& other) const
}
-Zstring NameFilter::uniqueClassIdentifier() const
-{
- return Zstr("NameFilter");
-}
-
-
-void NameFilter::save(wxOutputStream& stream) const
-{
- writeString(stream, includeFilterTmp);
- writeString(stream, excludeFilterTmp);
-}
-
-
-HardFilter::FilterRef NameFilter::load(wxInputStream& stream) //"constructor"
-{
- const Zstring include = readString<Zstring>(stream);
- const Zstring exclude = readString<Zstring>(stream);
-
- return FilterRef(new NameFilter(include, exclude));
-}
+//void NameFilter::save(ZstreamOut& stream) const
+//{
+// writeString(stream, includeFilterTmp);
+// writeString(stream, excludeFilterTmp);
+//}
+//
+//
+//HardFilter::FilterRef NameFilter::load(ZstreamIn& stream) //throw UnexpectedEndOfStreamError
+//{
+// const Zstring include = readString<Zstring>(stream); //throw UnexpectedEndOfStreamError
+// const Zstring exclude = readString<Zstring>(stream); //
+//
+// return FilterRef(new NameFilter(include, exclude));
+//}
diff --git a/lib/hard_filter.h b/lib/hard_filter.h
index 1a9943a3..90cd33fc 100644
--- a/lib/hard_filter.h
+++ b/lib/hard_filter.h
@@ -9,15 +9,15 @@
#include <vector>
#include <memory>
-#include <wx/stream.h>
#include <zen/zstring.h>
+//#include <wx+/serialize.h>
namespace zen
{
//------------------------------------------------------------------
/*
Semantics of HardFilter:
-1. using it creates a NEW folder hierarchy! -> must be considered by <Automatic>-mode! (fortunately it turns out, doing nothing already has perfect semantics :)
+1. using it creates a NEW folder hierarchy! -> must be considered by <Automatic>-mode!
2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder!
class hierarchy:
@@ -45,14 +45,14 @@ public:
typedef std::shared_ptr<const HardFilter> FilterRef; //always bound by design!
//serialization
- void saveFilter(wxOutputStream& stream) const; //serialize derived object
- static FilterRef loadFilter(wxInputStream& stream); //CAVEAT!!! adapt this method for each new derivation!!!
+ // void saveFilter(ZstreamOut& stream) const; //serialize derived object
+ // static FilterRef loadFilter(ZstreamIn& stream); //throw UnexpectedEndOfStreamError; CAVEAT!!! adapt this method for each new derivation!!!
private:
- friend bool operator< (const HardFilter& lhs, const HardFilter& rhs);
+ friend bool operator<(const HardFilter& lhs, const HardFilter& rhs);
- virtual void save(wxOutputStream& stream) const = 0; //serialization
- virtual Zstring uniqueClassIdentifier() const = 0; //get identifier, used for serialization
+ // virtual void save(ZstreamOut& stream) const = 0; //serialization
+ virtual std::string uniqueClassIdentifier() const = 0; //get identifier, used for serialization
virtual bool cmpLessSameType(const HardFilter& other) const = 0; //typeid(*this) == typeid(other) in this context!
};
@@ -74,9 +74,9 @@ public:
private:
friend class HardFilter;
- virtual void save(wxOutputStream& stream) const {}
- virtual Zstring uniqueClassIdentifier() const;
- static FilterRef load(wxInputStream& stream); //"serial constructor"
+ // virtual void save(ZstreamOut& stream) const {}
+ virtual std::string uniqueClassIdentifier() const { return "NullFilter"; }
+ // static FilterRef load(ZstreamIn& stream); //throw UnexpectedEndOfStreamError
virtual bool cmpLessSameType(const HardFilter& other) const;
};
@@ -94,9 +94,9 @@ public:
private:
friend class HardFilter;
- virtual void save(wxOutputStream& stream) const;
- virtual Zstring uniqueClassIdentifier() const;
- static FilterRef load(wxInputStream& stream); //"serial constructor"
+ // virtual void save(ZstreamOut& stream) const;
+ virtual std::string uniqueClassIdentifier() const { return "NameFilter"; }
+ // static FilterRef load(ZstreamIn& stream); //throw UnexpectedEndOfStreamError
virtual bool cmpLessSameType(const HardFilter& other) const;
std::vector<Zstring> filterFileIn; //
@@ -120,9 +120,9 @@ public:
private:
friend class HardFilter;
- virtual void save(wxOutputStream& stream) const;
- virtual Zstring uniqueClassIdentifier() const;
- static FilterRef load(wxInputStream& stream); //"serial constructor"
+ // virtual void save(ZstreamOut& stream) const;
+ virtual std::string uniqueClassIdentifier() const { return "CombinedFilter"; }
+ // static FilterRef load(ZstreamIn& stream); //throw UnexpectedEndOfStreamError
virtual bool cmpLessSameType(const HardFilter& other) const;
const FilterRef first_;
@@ -147,11 +147,11 @@ private:
//---------------Inline Implementation---------------------------------------------------
-inline
-HardFilter::FilterRef NullFilter::load(wxInputStream& stream) //"serial constructor"
-{
- return FilterRef(new NullFilter);
-}
+//inline
+//HardFilter::FilterRef NullFilter::load(ZstreamIn& stream)
+//{
+// return FilterRef(new NullFilter);
+//}
inline
@@ -185,16 +185,9 @@ bool NullFilter::cmpLessSameType(const HardFilter& other) const
inline
-Zstring NullFilter::uniqueClassIdentifier() const
-{
- return Zstr("NullFilter");
-}
-
-
-inline
bool CombinedFilter::passFileFilter(const Zstring& relFilename) const
{
- return first_->passFileFilter(relFilename) && //short-circuit behavior
+ return first_ ->passFileFilter(relFilename) && //short-circuit behavior
second_->passFileFilter(relFilename);
}
@@ -202,8 +195,14 @@ bool CombinedFilter::passFileFilter(const Zstring& relFilename) const
inline
bool CombinedFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const
{
- return first_->passDirFilter(relDirname, subObjMightMatch) && //short-circuit behavior: subObjMightMatch handled correctly!
- second_->passDirFilter(relDirname, subObjMightMatch);
+ if (first_->passDirFilter(relDirname, subObjMightMatch))
+ return second_->passDirFilter(relDirname, subObjMightMatch);
+ else
+ {
+ if (subObjMightMatch && *subObjMightMatch)
+ second_->passDirFilter(relDirname, subObjMightMatch);
+ return false;
+ }
}
@@ -228,29 +227,22 @@ bool CombinedFilter::cmpLessSameType(const HardFilter& other) const
}
-inline
-Zstring CombinedFilter::uniqueClassIdentifier() const
-{
- return Zstr("CombinedFilter");
-}
-
-
-inline
-void CombinedFilter::save(wxOutputStream& stream) const
-{
- first_->saveFilter(stream);
- second_->saveFilter(stream);
-}
+//inline
+//void CombinedFilter::save(ZstreamOut& stream) const
+//{
+// first_ ->saveFilter(stream);
+// second_->saveFilter(stream);
+//}
-inline
-HardFilter::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor"
-{
- FilterRef first = loadFilter(stream);
- FilterRef second = loadFilter(stream);
-
- return combineFilters(first, second);
-}
+//inline
+//HardFilter::FilterRef CombinedFilter::load(ZstreamIn& stream) //throw UnexpectedEndOfStreamError
+//{
+// FilterRef first = loadFilter(stream); //throw UnexpectedEndOfStreamError
+// FilterRef second = loadFilter(stream); //
+//
+// return combineFilters(first, second);
+//}
inline
@@ -272,8 +264,6 @@ HardFilter::FilterRef combineFilters(const HardFilter::FilterRef& first,
return HardFilter::FilterRef(new CombinedFilter(first, second));
}
}
-
-
}
diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp
index daf32a86..2dc6f389 100644
--- a/lib/icon_buffer.cpp
+++ b/lib/icon_buffer.cpp
@@ -9,7 +9,6 @@
#include <set>
#include <zen/thread.h> //includes <boost/thread.hpp>
#include <zen/scope_guard.h>
-//#include <boost/thread/once.hpp>
#ifdef FFS_WIN
#include <zen/dll.h>
@@ -27,7 +26,7 @@ namespace
{
const size_t BUFFER_SIZE_MAX = 800; //maximum number of icons to buffer
-
+inline
int cvrtSize(IconBuffer::IconSize sz) //get size in pixel
{
switch (sz)
@@ -57,7 +56,7 @@ public:
typedef GdkPixbuf* HandleType;
#endif
- explicit IconHolder(HandleType handle = 0) : handle_(handle) {} //take ownership!
+ explicit IconHolder(HandleType handle = nullptr) : handle_(handle) {} //take ownership!
//icon holder has value semantics!
IconHolder(const IconHolder& other) : handle_(other.handle_ == nullptr ? nullptr :
@@ -104,31 +103,36 @@ public:
ICONINFO icoInfo = {};
if (::GetIconInfo(clone.handle_, &icoInfo))
{
- ::DeleteObject(icoInfo.hbmMask); //nice potential for a GDI leak!
- ZEN_ON_SCOPE_EXIT(::DeleteObject(icoInfo.hbmColor)); //
+ if (icoInfo.hbmMask) //VC11 static analyzer warns this could be null
+ ::DeleteObject(icoInfo.hbmMask); //nice potential for a GDI leak!
- BITMAP bmpInfo = {};
- if (::GetObject(icoInfo.hbmColor, //__in HGDIOBJ hgdiobj,
- sizeof(BITMAP), //__in int cbBuffer,
- &bmpInfo) != 0) // __out LPVOID lpvObject
+ if (icoInfo.hbmColor) //optional (for black and white bitmap)
{
- const int maxExtent = std::max(bmpInfo.bmWidth, bmpInfo.bmHeight);
- if (0 < expectedSize && expectedSize < maxExtent)
+ ZEN_ON_SCOPE_EXIT(::DeleteObject(icoInfo.hbmColor)); //
+
+ BITMAP bmpInfo = {};
+ if (::GetObject(icoInfo.hbmColor, //__in HGDIOBJ hgdiobj,
+ sizeof(BITMAP), //__in int cbBuffer,
+ &bmpInfo) != 0) // __out LPVOID lpvObject
{
- bmpInfo.bmWidth = bmpInfo.bmWidth * expectedSize / maxExtent; //scale those Vista jumbo 256x256 icons down!
- bmpInfo.bmHeight = bmpInfo.bmHeight * expectedSize / maxExtent; //
+ const int maxExtent = std::max(bmpInfo.bmWidth, bmpInfo.bmHeight);
+ if (0 < expectedSize && expectedSize < maxExtent)
+ {
+ bmpInfo.bmWidth = bmpInfo.bmWidth * expectedSize / maxExtent; //scale those Vista jumbo 256x256 icons down!
+ bmpInfo.bmHeight = bmpInfo.bmHeight * expectedSize / maxExtent; //
+ }
+ newIcon.SetSize(bmpInfo.bmWidth, bmpInfo.bmHeight); //wxIcon is stretched to this size
}
- newIcon.SetSize(bmpInfo.bmWidth, bmpInfo.bmHeight); //wxIcon is stretched to this size
}
}
}
//no stretching for now
- //newIcon.SetSize(defaultSize, defaultSize); //icon is stretched to this size if referenced HICON differs
+ //newIcon.SetSize(expectedSize, expectedSize); //icon is stretched to this size if referenced HICON differs
#elif defined FFS_LINUX //
newIcon.SetPixbuf(clone.handle_); // transfer ownership!!
#endif //
- clone.handle_ = nullptr; //
+ clone.handle_ = nullptr; //
return newIcon;
}
@@ -486,7 +490,7 @@ void WorkerThread::operator()() //thread entry
//2. Initialize system image list
typedef BOOL (WINAPI* FileIconInitFun)(BOOL fRestoreCache);
- const SysDllFun<FileIconInitFun> fileIconInit(L"Shell32.dll", reinterpret_cast<LPCSTR>(660));
+ const SysDllFun<FileIconInitFun> fileIconInit(L"Shell32.dll", reinterpret_cast<LPCSTR>(660)); //MS requires and documents this magic number
assert(fileIconInit);
if (fileIconInit)
fileIconInit(false); //TRUE to restore the system image cache from disk; FALSE otherwise.
diff --git a/lib/localization.cpp b/lib/localization.cpp
index 5f9a4750..5bbb31d1 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -9,7 +9,7 @@
#include <map>
#include <list>
#include <iterator>
-#include <wx/ffile.h>
+//#include <wx/ffile.h>
#include <wx/intl.h>
#include <wx/msgdlg.h>
#include "parse_plural.h"
@@ -18,7 +18,6 @@
#include <zen/string_tools.h>
#include <zen/file_traverser.h>
#include "ffs_paths.h"
-#include <wx+/string_conv.h>
#include <zenxml/io.h>
#include <zen/i18n.h>
diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp
index 435067b2..f49fdc3e 100644
--- a/lib/parallel_scan.cpp
+++ b/lib/parallel_scan.cpp
@@ -10,7 +10,6 @@
#include "lock_holder.h"
#include <zen/file_traverser.h>
#include <zen/file_error.h>
-#include <wx+/string_conv.h>
#include <zen/thread.h> //includes <boost/thread.hpp>
#include <zen/scope_guard.h>
#include <zen/fixed_list.h>
@@ -176,7 +175,7 @@ class AsyncCallback //actor pattern
{
public:
AsyncCallback() :
- notifyingThreadID(-1),
+ notifyingThreadID(0),
textScanning(_("Scanning:")),
itemsScanned(0),
activeWorker(0) {}
@@ -216,9 +215,9 @@ public:
}
}
- void setNotifyingThread(int threadID) { notifyingThreadID = threadID; } //context of main thread
+ void setNotifyingThread(size_t threadID) { notifyingThreadID = threadID; } //context of main thread
- void reportCurrentFile(const Zstring& filename, int threadID) //context of worker thread
+ void reportCurrentFile(const Zstring& filename, size_t threadID) //context of worker thread
{
if (threadID != notifyingThreadID) return; //only one thread at a time may report status
@@ -227,7 +226,7 @@ public:
currentStatus.clear();
}
- void reportCurrentStatus(const std::wstring& status, int threadID) //context of worker thread
+ void reportCurrentStatus(const std::wstring& status, size_t threadID) //context of worker thread
{
if (threadID != notifyingThreadID) return; //only one thread may report status
@@ -278,7 +277,7 @@ private:
std::unique_ptr<FillBufferCallback::HandleError> errorResponse;
//---- status updates ----
- volatile int notifyingThreadID; //theoretically racy, but there is nothing that could go wrong...
+ volatile size_t notifyingThreadID; //theoretically racy, but there is nothing that could go wrong...
//CAVEAT: do NOT use boost::thread::id as long as this showstopper exists: https://svn.boost.org/trac/boost/ticket/5754
boost::mutex lockCurrentStatus; //use a different lock for current file: continue traversing while some thread may process an error
Zstring currentFile; //only one of these two is filled at a time!
@@ -296,7 +295,7 @@ private:
struct TraverserShared
{
public:
- TraverserShared(int threadID,
+ TraverserShared(size_t threadID,
SymLinkHandling handleSymlinks,
const HardFilter::FilterRef& filter,
std::set<Zstring>& failedReads,
@@ -313,7 +312,7 @@ public:
std::set<Zstring>& failedReads_; //relative postfixed names of directories that could not be read (empty for root)
AsyncCallback& acb_;
- int threadID_;
+ size_t threadID_;
};
@@ -459,7 +458,7 @@ DirCallback::HandleError DirCallback::onError(const std::wstring& errorText)
class DstHackCallbackImpl : public DstHackCallback
{
public:
- DstHackCallbackImpl(AsyncCallback& acb, int threadID) :
+ DstHackCallbackImpl(AsyncCallback& acb, size_t threadID) :
acb_(acb),
threadID_(threadID),
textApplyingDstHack(replaceCpy(_("Encoding extended time information: %x"), L"%x", L"\n%x")) {}
@@ -471,7 +470,7 @@ private:
}
AsyncCallback& acb_;
- int threadID_;
+ size_t threadID_;
const std::wstring textApplyingDstHack;
};
#endif
@@ -481,7 +480,7 @@ private:
class WorkerThread
{
public:
- WorkerThread(int threadID,
+ WorkerThread(size_t threadID,
const std::shared_ptr<AsyncCallback>& acb,
const std::vector<std::pair<DirectoryKey, DirectoryValue*>>& workload) :
threadID_(threadID),
@@ -523,7 +522,7 @@ public:
}
private:
- int threadID_;
+ size_t threadID_;
std::shared_ptr<AsyncCallback> acb_;
std::vector<std::pair<DirectoryKey, DirectoryValue*>> workload_;
};
@@ -563,12 +562,12 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
workload.push_back(std::make_pair(key, &rv.first->second));
});
- const int threadId = iter - buckets.begin();
+ const size_t threadId = iter - buckets.begin();
worker.emplace_back(WorkerThread(threadId, acb, workload));
}
//wait until done
- int threadId = 0;
+ size_t threadId = 0;
for (auto iter = worker.begin(); iter != worker.end(); ++iter, ++threadId)
{
boost::thread& wt = *iter;
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index 677618b4..39b1520b 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -5,9 +5,9 @@
// **************************************************************************
#include "process_xml.h"
+#include <utility>
#include <zenxml/xml.h>
#include "ffs_paths.h"
-#include <wx+/string_conv.h>
#include <zen/file_handling.h>
#include <zen/file_io.h>
#include "xml_base.h"
@@ -15,6 +15,8 @@
using namespace zen;
using namespace xmlAccess; //functionally needed for correct overload resolution!!!
+using namespace std::rel_ops;
+
XmlType getXmlType(const zen::XmlDoc& doc) //throw()
{
@@ -181,7 +183,7 @@ xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<Zstring>& filenam
namespace
{
template <class XmlCfg>
-XmlCfg loadCfgImpl(const Zstring& filename, std::unique_ptr<xmlAccess::FfsXmlError>& exeption) //throw xmlAccess::FfsXmlError
+XmlCfg loadCfgImpl(const Zstring& filename, std::unique_ptr<xmlAccess::FfsXmlError>& warning) //throw xmlAccess::FfsXmlError
{
XmlCfg cfg;
try
@@ -193,7 +195,7 @@ XmlCfg loadCfgImpl(const Zstring& filename, std::unique_ptr<xmlAccess::FfsXmlErr
if (e.getSeverity() == xmlAccess::FfsXmlError::FATAL)
throw;
else
- exeption.reset(new xmlAccess::FfsXmlError(e));
+ warning.reset(new xmlAccess::FfsXmlError(e));
}
return cfg;
}
@@ -207,8 +209,7 @@ void mergeConfigFilesImpl(const std::vector<Zstring>& filenames, XmlCfg& config)
return;
std::vector<zen::MainConfiguration> mainCfgs;
- std::unique_ptr<FfsXmlError> savedException;
- Zstring invalidFile;
+ std::unique_ptr<FfsXmlError> savedWarning;
std::for_each(filenames.begin(), filenames.end(),
[&](const Zstring& filename)
@@ -216,23 +217,22 @@ void mergeConfigFilesImpl(const std::vector<Zstring>& filenames, XmlCfg& config)
switch (getXmlType(filename))
{
case XML_TYPE_GUI:
- mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(filename, savedException).mainCfg); //throw xmlAccess::FfsXmlError
+ mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(filename, savedWarning).mainCfg); //throw xmlAccess::FfsXmlError
break;
case XML_TYPE_BATCH:
- mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(filename, savedException).mainCfg); //throw xmlAccess::FfsXmlError
+ mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(filename, savedWarning).mainCfg); //throw xmlAccess::FfsXmlError
break;
case XML_TYPE_GLOBAL:
case XML_TYPE_OTHER:
- invalidFile = filename;
- break;
+ if (!fileExists(filename))
+ throw FfsXmlError(replaceCpy(_("Cannot find file %x."), L"%x", fmtFileName(filename)));
+ else
+ throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
}
});
- if (mainCfgs.empty())
- throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(invalidFile)));
-
try //...to init all non-"mainCfg" settings with first config file
{
xmlAccess::readConfig(filenames[0], config); //throw xmlAccess::FfsXmlError
@@ -241,8 +241,8 @@ void mergeConfigFilesImpl(const std::vector<Zstring>& filenames, XmlCfg& config)
config.mainCfg = merge(mainCfgs);
- if (savedException.get()) //"re-throw" exception
- throw* savedException;
+ if (savedWarning.get()) //"re-throw" exception
+ throw* savedWarning;
}
}
@@ -761,7 +761,8 @@ void readConfig(const XmlIn& in, FolderPairEnh& enhPair)
//###########################################################
//alternate filter configuration
- readConfig(in["LocalFilter"], enhPair.localFilter);
+ if (XmlIn inLocFilter = in["LocalFilter"])
+ readConfig(inLocFilter, enhPair.localFilter);
}
@@ -1019,7 +1020,6 @@ void writeConfigFolderPair(const FolderPairEnh& enhPair, XmlOut& out)
if (enhPair.altCmpConfig.get())
{
XmlOut outAlt = outPair["CompareConfig"];
-
writeConfig(*enhPair.altCmpConfig, outAlt);
}
//###########################################################
@@ -1027,14 +1027,16 @@ void writeConfigFolderPair(const FolderPairEnh& enhPair, XmlOut& out)
if (enhPair.altSyncConfig.get())
{
XmlOut outAltSync = outPair["SyncConfig"];
-
writeConfig(*enhPair.altSyncConfig, outAltSync);
}
//###########################################################
//alternate filter configuration
- XmlOut outFilter = outPair["LocalFilter"];
- writeConfig(enhPair.localFilter, outFilter);
+ if (enhPair.localFilter != FilterConfig()) //don't spam .ffs_gui file with default filter entries
+ {
+ XmlOut outFilter = outPair["LocalFilter"];
+ writeConfig(enhPair.localFilter, outFilter);
+ }
}
diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp
index bb0c1f3b..57f4ff30 100644
--- a/lib/resolve_path.cpp
+++ b/lib/resolve_path.cpp
@@ -27,7 +27,7 @@ using namespace zen;
namespace
{
#ifdef FFS_WIN
-Zstring resolveRelativePath(Zstring relativeName) //note: ::GetFullPathName() is documented not threadsafe!
+Zstring resolveRelativePath(const Zstring& relativeName) //note: ::GetFullPathName() is documented not threadsafe!
{
const DWORD bufferSize = 10000;
std::vector<wchar_t> buffer(bufferSize);
@@ -36,10 +36,10 @@ Zstring resolveRelativePath(Zstring relativeName) //note: ::GetFullPathName() is
bufferSize, //__in DWORD nBufferLength,
&buffer[0], //__out LPTSTR lpBuffer,
nullptr); //__out LPTSTR *lpFilePart
- if (charsWritten == 0 || charsWritten >= bufferSize) //theoretically, charsWritten can never be == bufferSize
+ if (charsWritten == 0 || charsWritten >= bufferSize) //theoretically, charsWritten cannot be == "bufferSize"
return relativeName; //ERROR! Don't do anything
- return Zstring(&buffer[0], charsWritten);
+ return removeLongPathPrefix(Zstring(&buffer[0], charsWritten)); //GetFullPathName() preserves long path prefix -> a low-level detail we don't want to leak out!
}
#elif defined FFS_LINUX
@@ -347,7 +347,6 @@ Zstring volumePathToName(const Zstring& volumePath) //return empty string on err
rv != DRIVE_CDROM)
{
std::vector<wchar_t> buffer(MAX_PATH + 1);
-
if (::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName,
&buffer[0], //__out LPTSTR lpVolumeNameBuffer,
static_cast<DWORD>(buffer.size()), //__in DWORD nVolumeNameSize,
diff --git a/lib/resources.cpp b/lib/resources.cpp
index 670f2cfd..0d86279b 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -10,7 +10,7 @@
#include <wx/zipstrm.h>
#include <wx/image.h>
#include <wx/mstream.h>
-#include <wx+/string_conv.h>
+//#include <wx+/string_conv.h>
#include "ffs_paths.h"
using namespace zen;
diff --git a/lib/xml_base.cpp b/lib/xml_base.cpp
index 8f8ee74d..db33059c 100644
--- a/lib/xml_base.cpp
+++ b/lib/xml_base.cpp
@@ -24,7 +24,7 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
const std::string xmlBegin = "<?xml version=";
std::vector<char> buffer(xmlBegin.size() + sizeof(zen::BYTE_ORDER_MARK_UTF8));
- FileInput inputFile(filename); //throw FileError;
+ FileInput inputFile(filename); //throw FileError
const size_t bytesRead = inputFile.read(&buffer[0], buffer.size()); //throw FileError
const std::string fileBegin(&buffer[0], bytesRead);
diff --git a/resource.rc b/resource.rc
index 093036e9..e4675de4 100644
--- a/resource.rc
+++ b/resource.rc
@@ -1,9 +1,15 @@
#define IDR_VERSION1 1
-#include "Winver.h"
-#include "wx/msw/wx.rc"
+#include <Winver.h>
#include "version/version.rc"
+//beginning with VC11 we get linking error "CVTRES : fatal error CVT1100: duplicate resource. type:MANIFEST, name:1, language:0x0409"
+//due to "#define wxMANIFEST_ID 1" in wx.rc. Using another number doesn't integrate the manifest correctly for VC2010 compilers.
+//However tests indicate we do not need this manifest at all:
+//#define wxUSE_NO_MANIFEST 1 //VC11 screws up if not set to an integer, unbelievable
+//we can't #ifdef _MSC_VER: not known by resource compiler!
+//see also: http://blog.m-ri.de/index.php/2010/11/26/combobox-dropdown-hoehe-wird-nicht-mehr-durch-die-ressourcen-definiert/
+#include <wx/msw/wx.rc>
A_PROGRAM_ICON ICON DISCARDABLE "lib/FreeFileSync.ico"
B_BATCH_ICON ICON DISCARDABLE "lib/Batch.ico"
diff --git a/structures.h b/structures.h
index 728e3213..09d11a60 100644
--- a/structures.h
+++ b/structures.h
@@ -48,7 +48,7 @@ enum CompareFilesResult
FILE_RIGHT_NEWER,
FILE_DIFFERENT,
FILE_EQUAL,
- FILE_DIFFERENT_METADATA, //both sides equal, but different metadata only
+ FILE_DIFFERENT_METADATA, //both sides equal, but different metadata only: short name case, modification time
FILE_CONFLICT
};
//attention make sure these /|\ \|/ three enums match!!!
@@ -57,7 +57,7 @@ enum CompareDirResult
DIR_LEFT_SIDE_ONLY = FILE_LEFT_SIDE_ONLY,
DIR_RIGHT_SIDE_ONLY = FILE_RIGHT_SIDE_ONLY,
DIR_EQUAL = FILE_EQUAL,
- DIR_DIFFERENT_METADATA = FILE_DIFFERENT_METADATA //both sides equal, but different metadata only
+ DIR_DIFFERENT_METADATA = FILE_DIFFERENT_METADATA //both sides equal, but different metadata only: short name case
};
enum CompareSymlinkResult
@@ -68,7 +68,7 @@ enum CompareSymlinkResult
SYMLINK_RIGHT_NEWER = FILE_RIGHT_NEWER,
SYMLINK_DIFFERENT = FILE_DIFFERENT,
SYMLINK_EQUAL = FILE_EQUAL,
- SYMLINK_DIFFERENT_METADATA = FILE_DIFFERENT_METADATA, //files are considered "equal" but different only in metadata
+ SYMLINK_DIFFERENT_METADATA = FILE_DIFFERENT_METADATA, //both sides equal, but different metadata only: short name case
SYMLINK_CONFLICT = FILE_CONFLICT
};
diff --git a/synchronization.cpp b/synchronization.cpp
index daa08284..9dd98776 100644
--- a/synchronization.cpp
+++ b/synchronization.cpp
@@ -9,7 +9,6 @@
#include <deque>
#include <stdexcept>
#include <wx/file.h> //get rid!?
-#include <wx+/string_conv.h>
#include <wx+/format_unit.h>
#include <zen/scope_guard.h>
#include <zen/file_handling.h>
@@ -51,7 +50,7 @@ void SyncStatistics::init()
updateRight = 0;
deleteLeft = 0;
deleteRight = 0;
- conflict = 0;
+ //conflict = 0;
rowsTotal = 0;
}
@@ -137,9 +136,9 @@ void SyncStatistics::calcStats(const FileMapping& fileObj)
break;
case SO_UNRESOLVED_CONFLICT:
- ++conflict;
- if (firstConflicts.size() < 3) //save the first 3 conflict texts
- firstConflicts.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict()));
+ //++conflict;
+ //if (conflictMsgs.size() < MAX_CONFLICTS) //save the first conflict texts
+ conflictMsgs.push_back(std::make_pair(fileObj.getObjRelativeName(), fileObj.getSyncOpConflict()));
break;
case SO_COPY_METADATA_TO_LEFT:
@@ -189,9 +188,9 @@ void SyncStatistics::calcStats(const SymLinkMapping& linkObj)
break;
case SO_UNRESOLVED_CONFLICT:
- ++conflict;
- if (firstConflicts.size() < 3) //save the first 3 conflict texts
- firstConflicts.push_back(std::make_pair(linkObj.getObjRelativeName(), linkObj.getSyncOpConflict()));
+ //++conflict;
+ //if (conflictMsgs.size() < MAX_CONFLICTS) //save the first conflict texts
+ conflictMsgs.push_back(std::make_pair(linkObj.getObjRelativeName(), linkObj.getSyncOpConflict()));
break;
case SO_MOVE_LEFT_SOURCE:
@@ -233,9 +232,9 @@ void SyncStatistics::calcStats(const DirMapping& dirObj)
break;
case SO_UNRESOLVED_CONFLICT:
- ++conflict;
- if (firstConflicts.size() < 3) //save the first 3 conflict texts
- firstConflicts.push_back(std::make_pair(dirObj.getObjRelativeName(), dirObj.getSyncOpConflict()));
+ //++conflict;
+ //if (conflictMsgs.size() < MAX_CONFLICTS) //save the first conflict texts
+ conflictMsgs.push_back(std::make_pair(dirObj.getObjRelativeName(), dirObj.getSyncOpConflict()));
break;
case SO_COPY_METADATA_TO_LEFT:
@@ -307,9 +306,7 @@ bool significantDifferenceDetected(const SyncStatistics& folderPairStat)
}
//#################################################################################################################
-#ifdef FFS_WIN
-warn_static("finish")
-#endif
+
/*
class PhysicalStatistics //counts *physical* operations, disk accesses and bytes transferred
{
@@ -455,7 +452,7 @@ public:
const Zstring& subdirShort, //
const Zstring& baseDirPf, //with separator postfix
ProcessCallback& procCallback);
- ~DeletionHandling(); //always (try to) clean up, even if synchronization is aborted!
+ ~DeletionHandling() { try { tryCleanup(); } catch (...) {} /*make sure this stays non-blocking!*/ } //always (try to) clean up, even if synchronization is aborted!
//clean-up temporary directory (recycle bin optimization)
void tryCleanup(); //throw FileError -> call this in non-exceptional coding, i.e. somewhere after sync!
@@ -466,22 +463,34 @@ public:
//in contrast to "removeFolder()" this function will update statistics!
const std::wstring& getTxtRemovingFile () const { return txtRemovingFile; } //
- const std::wstring& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //status text templates
+ const std::wstring& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //buffered status texts
const std::wstring& getTxtRemovingDir () const { return txtRemovingDirectory; } //
//evaluate whether a deletion will actually free space within a volume
bool deletionFreesSpace() const;
+#ifdef FFS_WIN
+ bool recyclerFallbackOnDelete() const { return recFallbackDelPermantently; }
+#endif
private:
void removeFolderInt(const Zstring& relativeName, const int* objectsExpected, const Int64* dataExpected) const; //throw FileError
- DeletionPolicy deletionType;
- ProcessCallback* procCallback_; //always bound! need assignment operator => not a reference
+ void setDeletionPolicy(DeletionPolicy newPolicy);
+
+ ProcessCallback* const procCallback_; //always bound! need assignment operator => not a reference
+ const Zstring baseDirPf_; //ends with path separator
+ const Zstring custDelDir_;
+ const Zstring recyclerTmpDirPf; //temporary folder to move files to, before moving whole folder to recycler (postfixed with file name separator)
+ const Zstring versioningDirPf; //timestamped versioning folder
+
+#ifdef FFS_WIN
+ bool recFallbackDelPermantently;
+#endif
- Zstring sessionDelDirPf; //full target deletion folder for current folder pair (with timestamp, ends with path separator)
- Zstring baseDirPf_; //ends with path separator
+ //magage three states: allow dynamic fallback from recycler to permanent deletion
+ DeletionPolicy deletionPolicy_;
- //preloaded status texts:
+ //buffer status texts:
std::wstring txtRemovingFile;
std::wstring txtRemovingSymlink;
std::wstring txtRemovingDirectory;
@@ -495,17 +504,35 @@ DeletionHandling::DeletionHandling(DeletionPolicy handleDel,
const Zstring& subdirShort, //
const Zstring& baseDirPf, //with separator postfix
ProcessCallback& procCallback) :
- deletionType(handleDel),
procCallback_(&procCallback),
baseDirPf_(baseDirPf),
+ custDelDir_(custDelDir),
+ recyclerTmpDirPf(!baseDirPf_.empty() ? appendSeparator(findUnusedName(baseDirPf_ + Zstr("FFS ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S")))) : Zstring()),
+ versioningDirPf (!custDelDir.empty() ? appendSeparator(findUnusedName(appendSeparator(custDelDir) + subdirShort)) : Zstring()),
+#ifdef FFS_WIN
+ recFallbackDelPermantently(false),
+#endif
+ deletionPolicy_(MOVE_TO_RECYCLE_BIN),
cleanedUp(false)
{
#ifdef FFS_WIN
- if (baseDirPf.empty() ||
- (deletionType == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDirPf) == STATUS_REC_MISSING))
- deletionType = DELETE_PERMANENTLY; //Windows' ::SHFileOperation() will do this anyway, but we have a better and faster deletion routine (e.g. on networks)
+ if (!baseDirPf.empty())
+ if (handleDel == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDirPf) != STATUS_REC_EXISTS)
+ {
+ handleDel = DELETE_PERMANENTLY; //Windows' ::SHFileOperation() will do this anyway, but we have a better and faster deletion routine (e.g. on networks)
+ recFallbackDelPermantently = true;
+ }
#endif
- switch (deletionType)
+
+ setDeletionPolicy(handleDel);
+}
+
+
+void DeletionHandling::setDeletionPolicy(DeletionPolicy newPolicy)
+{
+ deletionPolicy_ = newPolicy;
+
+ switch (deletionPolicy_)
{
case DELETE_PERMANENTLY:
txtRemovingFile = _("Deleting file %x" );
@@ -514,40 +541,27 @@ DeletionHandling::DeletionHandling(DeletionPolicy handleDel,
break;
case MOVE_TO_RECYCLE_BIN:
- if (!baseDirPf_.empty())
- sessionDelDirPf = appendSeparator(findUnusedName(baseDirPf_ + Zstr("FFS ") + formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"))));
-
txtRemovingFile = _("Moving file %x to recycle bin" );
txtRemovingDirectory = _("Moving folder %x to recycle bin" );
txtRemovingSymlink = _("Moving symbolic link %x to recycle bin");
break;
case MOVE_TO_CUSTOM_DIRECTORY:
- if (!custDelDir.empty())
- sessionDelDirPf = appendSeparator(findUnusedName(appendSeparator(custDelDir) + subdirShort));
-
- txtRemovingFile = replaceCpy(_("Moving file %x to %y" ), L"%y", fmtFileName(custDelDir));
- txtRemovingDirectory = replaceCpy(_("Moving folder %x to %y" ), L"%y", fmtFileName(custDelDir));
- txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to %y"), L"%y", fmtFileName(custDelDir));
+ txtRemovingFile = replaceCpy(_("Moving file %x to %y" ), L"%y", fmtFileName(custDelDir_));
+ txtRemovingDirectory = replaceCpy(_("Moving folder %x to %y" ), L"%y", fmtFileName(custDelDir_));
+ txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to %y"), L"%y", fmtFileName(custDelDir_));
break;
}
}
-DeletionHandling::~DeletionHandling()
-{
- //always (try to) clean up, even if synchronization is aborted!
- try { tryCleanup(); }
- catch (...) {} //make sure this stays non-blocking!
-}
-
-
void DeletionHandling::tryCleanup() //throw FileError
{
if (!cleanedUp)
{
- if (deletionType == MOVE_TO_RECYCLE_BIN) //clean-up temporary directory (recycle bin)
- zen::moveToRecycleBin(beforeLast(sessionDelDirPf, FILE_NAME_SEPARATOR)); //throw FileError
+ if (deletionPolicy_ == MOVE_TO_RECYCLE_BIN) //clean-up temporary directory (recycle bin)
+ if (!recyclerTmpDirPf.empty()) //empty folder input pair
+ recycleOrDelete(beforeLast(recyclerTmpDirPf, FILE_NAME_SEPARATOR)); //throw FileError
cleanedUp = true;
}
@@ -637,15 +651,16 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
{
const Zstring fullName = baseDirPf_ + relativeName;
- switch (deletionType)
+ switch (deletionPolicy_)
{
case DELETE_PERMANENTLY:
zen::removeFile(fullName);
+ //[!] resolve nameclash!
break;
case MOVE_TO_RECYCLE_BIN:
{
- const Zstring targetFile = sessionDelDirPf + relativeName; //ends with path separator
+ const Zstring targetFile = recyclerTmpDirPf + relativeName; //ends with path separator
try
{
@@ -660,14 +675,16 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
{
const Zstring targetDir = beforeLast(targetFile, FILE_NAME_SEPARATOR);
if (!dirExists(targetDir)) //no reason to update gui or overwrite status text!
- createDirectory(targetDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
+ {
+ makeDirectory(targetDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
+ renameFile(fullName, targetFile); //throw FileError -> this should work now!
+ }
else
throw;
- renameFile(fullName, targetFile); //throw FileError -> this should work now!
}
catch (FileError&) //if anything went wrong, move to recycle bin the standard way (single file processing: slow)
{
- moveToRecycleBin(fullName); //throw FileError
+ recycleOrDelete(fullName); //throw FileError
}
}
}
@@ -676,7 +693,7 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
case MOVE_TO_CUSTOM_DIRECTORY:
{
CallbackMoveFileImpl callBack(*procCallback_, *this, nullptr); //we do *not* report statistics in this method
- const Zstring targetFile = sessionDelDirPf + relativeName; //ends with path separator
+ const Zstring targetFile = versioningDirPf + relativeName; //ends with path separator
try //... to get away cheaply!
{
@@ -689,7 +706,7 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const
const Zstring targetDir = beforeLast(targetFile, FILE_NAME_SEPARATOR);
if (!dirExists(targetDir))
{
- createDirectory(targetDir); //throw FileError
+ makeDirectory(targetDir); //throw FileError
moveFile(fullName, targetFile, &callBack); //throw FileError -> this should work now!
}
else
@@ -708,9 +725,9 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
int objectsReported = 0; //use *only* if "objectsExpected" is bound!
//in error situation: undo communication of processed amount of data
- zen::ScopeGuard guardStatistics = zen::makeGuard([&] { procCallback_->updateProcessedData(-objectsReported, 0); });
+ ScopeGuard guardStatistics = makeGuard([&] { procCallback_->updateProcessedData(-objectsReported, 0); });
- switch (deletionType)
+ switch (deletionPolicy_)
{
case DELETE_PERMANENTLY:
{
@@ -721,7 +738,7 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
case MOVE_TO_RECYCLE_BIN:
{
- const Zstring targetDir = sessionDelDirPf + relativeName;
+ const Zstring targetDir = recyclerTmpDirPf + relativeName;
try
{
@@ -736,14 +753,16 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
{
const Zstring targetSuperDir = beforeLast(targetDir, FILE_NAME_SEPARATOR);
if (!dirExists(targetSuperDir)) //no reason to update gui or overwrite status text!
- createDirectory(targetSuperDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
+ {
+ makeDirectory(targetSuperDir); //throw FileError -> may legitimately fail on Linux if permissions are missing
+ renameFile(fullName, targetDir); //throw FileError -> this should work now!
+ }
else
throw;
- renameFile(fullName, targetDir); //throw FileError -> this should work now!
}
catch (FileError&) //if anything went wrong, move to recycle bin the standard way (single file processing: slow)
{
- moveToRecycleBin(fullName); //throw FileError
+ recycleOrDelete(fullName); //throw FileError
}
}
}
@@ -758,7 +777,7 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
case MOVE_TO_CUSTOM_DIRECTORY:
{
CallbackMoveFileImpl callBack(*procCallback_, *this, objectsExpected ? &objectsReported : nullptr);
- const Zstring targetDir = sessionDelDirPf + relativeName;
+ const Zstring targetDir = versioningDirPf + relativeName;
try //... to get away cheaply!
{
@@ -771,7 +790,7 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
const Zstring targetSuperDir = beforeLast(targetDir, FILE_NAME_SEPARATOR);
if (!dirExists(targetSuperDir))
{
- createDirectory(targetSuperDir); //throw FileError
+ makeDirectory(targetSuperDir); //throw FileError
moveDirectory(fullName, targetDir, &callBack); //throw FileError -> this should work now!
}
else
@@ -796,14 +815,14 @@ void DeletionHandling::removeFolderInt(const Zstring& relativeName, const int* o
//evaluate whether a deletion will actually free space within a volume
bool DeletionHandling::deletionFreesSpace() const
{
- switch (deletionType)
+ switch (deletionPolicy_)
{
case DELETE_PERMANENTLY:
return true;
case MOVE_TO_RECYCLE_BIN:
return false; //in general... (unless Recycle Bin is full)
case MOVE_TO_CUSTOM_DIRECTORY:
- switch (zen::onSameVolume(baseDirPf_, sessionDelDirPf))
+ switch (zen::onSameVolume(baseDirPf_, versioningDirPf))
{
case IS_SAME_YES:
return false;
@@ -1076,13 +1095,13 @@ void SynchronizeFolderPair::prepare2StepMove(FileMapping& sourceObj,
{
const Zstring& source = sourceObj.getFullName<side>();
const Zstring& tmpTarget = findUnusedTempName(sourceObj.getBaseDirPf<side>() + sourceObj.getShortName<side>());
- //this could still lead to a name-clash in obscure cases, if some file ex. on the other side with
+ //this could still lead to a name-clash in obscure cases, if some file exists on the other side with
//the very same (.ffs_tmp) name and is copied before the second step of the move is executed
//good news: even in this pathologic case, this may only prevent the copy of the other file, but not the move
reportInfo(replaceCpy(txtMovingFile, L"%y", fmtFileName(tmpTarget)), source);
- renameFile(source, tmpTarget); //throw FileError;
+ renameFile(source, tmpTarget); //throw FileError
//update file hierarchy
const FileDescriptor descrSource(sourceObj.getLastWriteTime<side>(),
@@ -1502,7 +1521,7 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
reportInfo(replaceCpy(txtMovingFile, L"%y", fmtFileName(target)), source);
- renameFile(source, target); //throw FileError;
+ renameFile(source, target); //throw FileError
const FileDescriptor descrTarget(sourceObj->getLastWriteTime<sideTrg>(),
sourceObj->getFileSize <sideTrg>(),
@@ -1549,7 +1568,7 @@ void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperati
if (fileObj.getShortName<sideTrg>() != fileObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
renameFile(fileObj.getFullName<sideTrg>(),
- beforeLast(fileObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName<sideSrc>()); //throw FileError;
+ beforeLast(fileObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName<sideSrc>()); //throw FileError
if (!sameFileTime(fileObj.getLastWriteTime<sideTrg>(), fileObj.getLastWriteTime<sideSrc>(), 2)) //respect 2 second FAT/FAT32 precision
setFileTime(fileObj.getFullName<sideTrg>(), fileObj.getLastWriteTime<sideSrc>(), SYMLINK_FOLLOW); //throw FileError
@@ -1673,7 +1692,7 @@ void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOper
if (linkObj.getShortName<sideTrg>() != linkObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
renameFile(linkObj.getFullName<sideTrg>(),
- beforeLast(linkObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName<sideSrc>()); //throw FileError;
+ beforeLast(linkObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName<sideSrc>()); //throw FileError
if (!sameFileTime(linkObj.getLastWriteTime<sideTrg>(), linkObj.getLastWriteTime<sideSrc>(), 2)) //respect 2 second FAT/FAT32 precision
setFileTime(linkObj.getFullName<sideTrg>(), linkObj.getLastWriteTime<sideSrc>(), SYMLINK_DIRECT); //throw FileError
@@ -1729,12 +1748,17 @@ void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperati
const Zstring& target = dirObj.getBaseDirPf<sideTrg>() + dirObj.getRelativeName<sideSrc>();
reportInfo(txtCreatingFolder, target);
- createDirectory(target, dirObj.getFullName<sideSrc>(), copyFilePermissions_); //no symlink copying!
+ try
+ {
+ makeNewDirectory(target, dirObj.getFullName<sideSrc>(), copyFilePermissions_); //no symlink copying!
+ }
+ catch (const ErrorTargetExisting&) { if (!dirExists(target)) throw; } //clash with file (dir-symlink is okay)
+
dirObj.copyTo<sideTrg>(); //update DirMapping
procCallback_.updateProcessedData(1, 0);
}
- else //source deleted meanwhile...nothing was done (logical point of view!)
+ else //source deleted meanwhile...nothing was done (logical point of view!) -> uh....what about a temporary network drop???
{
// throw FileError
const SyncStatistics subStats(dirObj);
@@ -1753,7 +1777,7 @@ void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperati
if (dirObj.getShortName<sideTrg>() != dirObj.getShortName<sideSrc>()) //adapt difference in case (windows only)
renameFile(dirObj.getFullName<sideTrg>(),
- beforeLast(dirObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName<sideSrc>()); //throw FileError;
+ beforeLast(dirObj.getFullName<sideTrg>(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName<sideSrc>()); //throw FileError
//copyFileTimes -> useless at this time: modification time changes with each child-object creation/deletion
dirObj.copyTo<sideTrg>(); //-> both sides *should* be completely equal now...
@@ -1843,7 +1867,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//initialize deletion handling: already required when checking for warnings
- std::vector<std::pair<DeletionHandling, DeletionHandling>> delHandler;
+ FixedList<std::pair<DeletionHandling, DeletionHandling>> delHandler;
for (auto j = begin(folderCmp); j != end(folderCmp); ++j)
{
const size_t folderIndex = j - folderCmp.begin();
@@ -1852,20 +1876,20 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
const Zstring subDirShort = folderCmp.size() <= 1 ? custDelDirShortname : custDelDirShortname + Zstr(" (") + numberTo<Zstring>(folderIndex + 1) + Zstr(")");
//e.g. "SyncJob 2012-05-15 131513 (1)" -> enforce different custom deletion dir when using multiple folder pairs!!!
- delHandler.push_back(std::make_pair(DeletionHandling(folderPairCfg.handleDeletion,
- folderPairCfg.custDelFolder,
- subDirShort,
- j->getBaseDirPf<LEFT_SIDE>(),
- procCallback),
-
- DeletionHandling(folderPairCfg.handleDeletion,
- folderPairCfg.custDelFolder,
- subDirShort,
- j->getBaseDirPf<RIGHT_SIDE>(),
- procCallback)));
+ delHandler.emplace_back(DeletionHandling(folderPairCfg.handleDeletion,
+ folderPairCfg.custDelFolder,
+ subDirShort,
+ j->getBaseDirPf<LEFT_SIDE>(),
+ procCallback),
+
+ DeletionHandling(folderPairCfg.handleDeletion,
+ folderPairCfg.custDelFolder,
+ subDirShort,
+ j->getBaseDirPf<RIGHT_SIDE>(),
+ procCallback));
}
- //-------------------some basic checks:------------------------------------------
+ //-------------------execute basic all at once before starting sync--------------------------------------
auto dependentDir = [](const Zstring& lhs, const Zstring& rhs) //note: this is NOT an equivalence relation!
{
@@ -1902,148 +1926,158 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
typedef std::vector<std::pair<Zstring, std::pair<Int64, Int64>>> DirSpaceRequAvailList; //dirname / space required / space available
DirSpaceRequAvailList diskSpaceMissing;
- std::set<Zstring> recyclMissing;
+#ifdef FFS_WIN
+ std::set<Zstring, LessFilename> recyclMissing;
+#endif
//start checking folder pairs
- for (auto j = begin(folderCmp); j != end(folderCmp); ++j)
{
- const size_t folderIndex = j - begin(folderCmp);
+ auto iterDelHandler = delHandler.cbegin();
+ for (auto j = begin(folderCmp); j != end(folderCmp); ++j, ++iterDelHandler)
+ {
+ const size_t folderIndex = j - begin(folderCmp);
- //exclude some pathological case (leftdir, rightdir are empty)
- if (EqualFilename()(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()))
- continue;
+ //exclude some pathological case (leftdir, rightdir are empty)
+ if (EqualFilename()(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()))
+ continue;
- const FolderPairSyncCfg& folderPairCfg = syncConfig[folderIndex];
- const std::pair<DeletionHandling, DeletionHandling>& delHandlerFp = delHandler[folderIndex];
+ const FolderPairSyncCfg& folderPairCfg = syncConfig[folderIndex];
- const SyncStatistics folderPairStat(*j);
+ const SyncStatistics folderPairStat(*j);
- //aggregate basic information
- const bool writeLeft = folderPairStat.getCreate<LEFT_SIDE>() +
- folderPairStat.getUpdate<LEFT_SIDE>() +
- folderPairStat.getDelete<LEFT_SIDE>() > 0;
+ //aggregate basic information
+ const bool writeLeft = folderPairStat.getCreate<LEFT_SIDE>() +
+ folderPairStat.getUpdate<LEFT_SIDE>() +
+ folderPairStat.getDelete<LEFT_SIDE>() > 0;
- const bool writeRight = folderPairStat.getCreate<RIGHT_SIDE>() +
- folderPairStat.getUpdate<RIGHT_SIDE>() +
- folderPairStat.getDelete<RIGHT_SIDE>() > 0;
+ const bool writeRight = folderPairStat.getCreate<RIGHT_SIDE>() +
+ folderPairStat.getUpdate<RIGHT_SIDE>() +
+ folderPairStat.getDelete<RIGHT_SIDE>() > 0;
- //skip folder pair if there is nothing to do (except for automatic mode, where data base needs to be written even in this case)
- if (!writeLeft && !writeRight &&
- !folderPairCfg.inAutomaticMode)
- {
- skipFolderPair[folderIndex] = true; //skip creating (not yet existing) base directories in particular if there's no need
- continue;
- }
+ //skip folder pair if there is nothing to do (except for automatic mode, where data base needs to be written even in this case)
+ if (!writeLeft && !writeRight &&
+ !folderPairCfg.inAutomaticMode)
+ {
+ skipFolderPair[folderIndex] = true; //skip creating (not yet existing) base directories in particular if there's no need
+ continue;
+ }
- //check empty input fields: basically this only makes sense if empty field is not target (and not automatic mode: because of db file creation)
- if ((j->getBaseDirPf<LEFT_SIDE >().empty() && (writeLeft || folderPairCfg.inAutomaticMode)) ||
- (j->getBaseDirPf<RIGHT_SIDE>().empty() && (writeRight || folderPairCfg.inAutomaticMode)))
- {
- procCallback.reportFatalError(_("Target folder name must not be empty."));
- skipFolderPair[folderIndex] = true;
- continue;
- }
-
- //aggregate information of folders used by multiple pairs in read/write access
- if (!dependentDir(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>())) //true in general
- {
- if (writeLeft && writeRight)
+ //check empty input fields: basically this only makes sense if empty field is not target (and not automatic mode: because of db file creation)
+ if ((j->getBaseDirPf<LEFT_SIDE >().empty() && (writeLeft || folderPairCfg.inAutomaticMode)) ||
+ (j->getBaseDirPf<RIGHT_SIDE>().empty() && (writeRight || folderPairCfg.inAutomaticMode)))
{
- incWriteCount(j->getBaseDirPf<LEFT_SIDE >());
- incWriteCount(j->getBaseDirPf<RIGHT_SIDE>());
+ procCallback.reportFatalError(_("Target folder input field must not be empty."));
+ skipFolderPair[folderIndex] = true;
+ continue;
}
- else if (writeLeft)
+
+ //aggregate information of folders used by multiple pairs in read/write access
+ if (!dependentDir(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>())) //true in general
{
- incWriteCount(j->getBaseDirPf<LEFT_SIDE>());
- incReadCount (j->getBaseDirPf<RIGHT_SIDE>());
+ if (writeLeft && writeRight)
+ {
+ incWriteCount(j->getBaseDirPf<LEFT_SIDE >());
+ incWriteCount(j->getBaseDirPf<RIGHT_SIDE>());
+ }
+ else if (writeLeft)
+ {
+ incWriteCount(j->getBaseDirPf<LEFT_SIDE>());
+ incReadCount (j->getBaseDirPf<RIGHT_SIDE>());
+ }
+ else if (writeRight)
+ {
+ incReadCount (j->getBaseDirPf<LEFT_SIDE>());
+ incWriteCount(j->getBaseDirPf<RIGHT_SIDE>());
+ }
}
- else if (writeRight)
+ else //if folder pair contains two dependent folders, a warning was already issued after comparison; in this context treat as one write access at most
{
- incReadCount (j->getBaseDirPf<LEFT_SIDE>());
- incWriteCount(j->getBaseDirPf<RIGHT_SIDE>());
+ if (writeLeft || writeRight)
+ incWriteCount(j->getBaseDirPf<LEFT_SIDE>());
}
- }
- else //if folder pair contains two dependent folders, a warning was already issued after comparison; in this context treat as one write access at most
- {
- if (writeLeft || writeRight)
- incWriteCount(j->getBaseDirPf<LEFT_SIDE>());
- }
- if (folderPairStat.getUpdate() + folderPairStat.getDelete() > 0)
- {
- if (folderPairCfg.handleDeletion == zen::MOVE_TO_CUSTOM_DIRECTORY)
+ if (folderPairStat.getUpdate() + folderPairStat.getDelete() > 0)
{
- //check if user-defined directory for deletion was specified
- if (folderPairCfg.custDelFolder.empty())
+ if (folderPairCfg.handleDeletion == zen::MOVE_TO_CUSTOM_DIRECTORY)
{
- procCallback.reportFatalError(_("Folder name for file versioning must not be empty."));
- skipFolderPair[folderIndex] = true;
- continue;
+ //check if user-defined directory for deletion was specified
+ if (folderPairCfg.custDelFolder.empty())
+ {
+ procCallback.reportFatalError(_("Folder input field for versioning must not be empty."));
+ skipFolderPair[folderIndex] = true;
+ continue;
+ }
}
}
- }
- //avoid data loss when source directory doesn't (temporarily?) exist anymore AND user chose to ignore errors (else we wouldn't arrive here)
- if (folderPairStat.getCreate() +
- folderPairStat.getUpdate() +
- folderPairStat.getConflict() == 0 &&
- folderPairStat.getDelete() > 0) //deletions only... (respect filtered items!)
- {
- Zstring missingSrcDir;
- if (!j->getBaseDirPf<LEFT_SIDE>().empty() && !j->wasExisting<LEFT_SIDE>()) //important: we need to evaluate existence status from time of comparison!
- missingSrcDir = j->getBaseDirPf<LEFT_SIDE>();
- if (!j->getBaseDirPf<RIGHT_SIDE>().empty() && !j->wasExisting<RIGHT_SIDE>())
- missingSrcDir = j->getBaseDirPf<RIGHT_SIDE>();
-
- if (!missingSrcDir.empty())
+ //the following scenario is covered by base directory creation below in case source directory exists (accessible or not), but latter doesn't cover not-yet-created source!!!
+ auto checkSourceMissing = [&](const Zstring& baseDirPf, bool wasExisting) -> bool //avoid race-condition: we need to evaluate existence status from time of comparison!
{
- procCallback.reportFatalError(replaceCpy(_("Source directory %x not found."), L"%x", fmtFileName(missingSrcDir)));
- skipFolderPair[folderIndex] = true;
+ const Zstring dirname = beforeLast(baseDirPf, FILE_NAME_SEPARATOR);
+ if (!dirname.empty())
+ {
+ //PERMANENT network drop: avoid data loss when source directory is not found AND user chose to ignore errors (else we wouldn't arrive here)
+ if (folderPairStat.getCreate() +
+ folderPairStat.getUpdate() == 0 &&
+ folderPairStat.getDelete() > 0) //deletions only... (respect filtered items!)
+ //folderPairStat.getConflict() == 0 && -> there COULD be conflicts for <automatic> if directory existence check fails, but loading sync.ffs_db succeeds
+ //https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3531351&group_id=234430 -> fixed, but still better not consider conflicts
+ {
+ if (!wasExisting) //avoid race-condition: we need to evaluate existence status from time of comparison!
+ {
+ procCallback.reportFatalError(replaceCpy(_("Source folder %x not found."), L"%x", fmtFileName(baseDirPf)));
+ skipFolderPair[folderIndex] = true;
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+ if (!checkSourceMissing(j->getBaseDirPf<LEFT_SIDE >(), j->wasExisting<LEFT_SIDE >()) ||
+ !checkSourceMissing(j->getBaseDirPf<RIGHT_SIDE>(), j->wasExisting<RIGHT_SIDE>()))
continue;
- }
- }
- //check if more than 50% of total number of files/dirs are to be created/overwritten/deleted
- if (significantDifferenceDetected(folderPairStat))
- significantDiff.push_back(std::make_pair(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()));
+ //check if more than 50% of total number of files/dirs are to be created/overwritten/deleted
+ if (significantDifferenceDetected(folderPairStat))
+ significantDiff.push_back(std::make_pair(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()));
- //check for sufficient free diskspace
- auto checkSpace = [&](const Zstring& baseDirPf, const Int64& spaceRequired)
- {
- try
+ //check for sufficient free diskspace
+ auto checkSpace = [&](const Zstring& baseDirPf, const Int64& spaceRequired)
{
- Int64 freeSpace = to<Int64>(getFreeDiskSpace(baseDirPf)); //throw FileError
+ try
+ {
+ Int64 freeSpace = to<Int64>(getFreeDiskSpace(baseDirPf)); //throw FileError
- if (0 < freeSpace && //zero disk space is either an error or not: in both cases this warning message is obsolete (WebDav seems to report 0)
- freeSpace < spaceRequired)
- diskSpaceMissing.push_back(std::make_pair(baseDirPf, std::make_pair(spaceRequired, freeSpace)));
- }
- catch (FileError&) {}
- };
- const std::pair<Int64, Int64> spaceNeeded = DiskSpaceNeeded::calculate(*j, delHandlerFp.first.deletionFreesSpace(),
- delHandlerFp.second.deletionFreesSpace());
- checkSpace(j->getBaseDirPf<LEFT_SIDE >(), spaceNeeded.first);
- checkSpace(j->getBaseDirPf<RIGHT_SIDE>(), spaceNeeded.second);
+ if (0 < freeSpace && //zero disk space is either an error or not: in both cases this warning message is obsolete (WebDav seems to report 0)
+ freeSpace < spaceRequired)
+ diskSpaceMissing.push_back(std::make_pair(baseDirPf, std::make_pair(spaceRequired, freeSpace)));
+ }
+ catch (FileError&) {}
+ };
+ const std::pair<Int64, Int64> spaceNeeded = DiskSpaceNeeded::calculate(*j,
+ iterDelHandler->first .deletionFreesSpace(),
+ iterDelHandler->second.deletionFreesSpace());
+ checkSpace(j->getBaseDirPf<LEFT_SIDE >(), spaceNeeded.first);
+ checkSpace(j->getBaseDirPf<RIGHT_SIDE>(), spaceNeeded.second);
#ifdef FFS_WIN
- //windows: check if recycle bin really exists; if not, Windows will silently delete, which is wrong
- if (folderPairCfg.handleDeletion == MOVE_TO_RECYCLE_BIN)
- {
- if (folderPairStat.getUpdate<LEFT_SIDE>() +
- folderPairStat.getDelete<LEFT_SIDE>() > 0 &&
-
- recycleBinStatus(j->getBaseDirPf<LEFT_SIDE>()) != STATUS_REC_EXISTS)
- recyclMissing.insert(j->getBaseDirPf<LEFT_SIDE>());
-
- if (folderPairStat.getUpdate<RIGHT_SIDE>() +
- folderPairStat.getDelete<RIGHT_SIDE>() > 0 &&
-
- recycleBinStatus(j->getBaseDirPf<RIGHT_SIDE>()) != STATUS_REC_EXISTS)
- recyclMissing.insert(j->getBaseDirPf<RIGHT_SIDE>());
- }
+ //windows: check if recycle bin really exists; if not, Windows will silently delete, which is wrong
+ if (folderPairCfg.handleDeletion == MOVE_TO_RECYCLE_BIN)
+ {
+ if (folderPairStat.getUpdate<LEFT_SIDE>() +
+ folderPairStat.getDelete<LEFT_SIDE>() > 0 &&
+ iterDelHandler->first.recyclerFallbackOnDelete())
+ recyclMissing.insert(j->getBaseDirPf<LEFT_SIDE>());
+
+ if (folderPairStat.getUpdate<RIGHT_SIDE>() +
+ folderPairStat.getDelete<RIGHT_SIDE>() > 0 &&
+ iterDelHandler->second.recyclerFallbackOnDelete())
+ recyclMissing.insert(j->getBaseDirPf<RIGHT_SIDE>());
+ }
#endif
+ }
}
//check if unresolved conflicts exist
@@ -2053,12 +2087,12 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
std::wstring warningMessage = _("Unresolved conflicts existing!") +
L" (" + toGuiString(statisticsTotal.getConflict()) + L")\n\n";
- const auto& firstConflicts = statisticsTotal.getFirstConflicts(); //get first few sync conflicts
- for (auto iter = firstConflicts.begin(); iter != firstConflicts.end(); ++iter)
+ const auto& conflictMsgs = statisticsTotal.getConflictMessages(); //get first few sync conflicts
+ for (auto iter = conflictMsgs.begin(); iter != conflictMsgs.end(); ++iter)
warningMessage += fmtFileName(iter->first) + L": " + iter->second + L"\n\n";
- if (statisticsTotal.getConflict() > static_cast<int>(firstConflicts.size()))
- warningMessage += L"[...]\n\n";
+ // if (statisticsTotal.getConflict() > static_cast<int>(conflictMsgs.size()))
+ // warningMessage += L"[...]\n\n";
warningMessage += _("You can ignore conflicts and continue synchronization.");
@@ -2090,8 +2124,8 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
for (auto i = diskSpaceMissing.begin(); i != diskSpaceMissing.end(); ++i)
warningMessage += std::wstring(L"\n\n") +
fmtFileName(i->first) + L"\n" +
- _("Free disk space required:") + L" " + filesizeToShortString(i->second.first) + L"\n" +
- _("Free disk space available:") + L" " + filesizeToShortString(i->second.second);
+ _("Required:") + L" " + filesizeToShortString(i->second.first) + L"\n" +
+ _("Available:") + L" " + filesizeToShortString(i->second.second);
procCallback.reportWarning(warningMessage, m_warnings.warningNotEnoughDiskSpace);
}
@@ -2139,8 +2173,13 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
try
{
//loop through all directory pairs
- for (auto j = begin(folderCmp); j != end(folderCmp); ++j)
+ auto iterDelHandler = delHandler.begin();
+ for (auto j = begin(folderCmp); j != end(folderCmp); ++j, ++iterDelHandler)
{
+ //exclude some pathological case (leftdir, rightdir are empty)
+ if (EqualFilename()(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()))
+ continue;
+
//------------------------------------------------------------------------------------------
//always report folder pairs for log file, even if there is no work to do
std::wstring left = _("Left") + L": ";
@@ -2154,38 +2193,66 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
//------------------------------------------------------------------------------------------
const size_t folderIndex = j - begin(folderCmp);
-
const FolderPairSyncCfg& folderPairCfg = syncConfig[folderIndex];
- std::pair<DeletionHandling, DeletionHandling>& delHandlerFp = delHandler[folderIndex];
if (skipFolderPair[folderIndex]) //folder pairs may be skipped after fatal errors were found
continue;
- //exclude some pathological case (leftdir, rightdir are empty)
- if (EqualFilename()(j->getBaseDirPf<LEFT_SIDE>(), j->getBaseDirPf<RIGHT_SIDE>()))
- continue;
-
- //create base directories first (if not yet existing) -> no symlink or attribute copying! -> single error message instead of one per file (e.g. unplugged network drive)
- const Zstring dirnameLeft = beforeLast(j->getBaseDirPf<LEFT_SIDE>(), FILE_NAME_SEPARATOR);
- if (!dirnameLeft.empty() && !dirExistsUpdating(dirnameLeft, false, procCallback))
+ //create base directories first (if not yet existing) -> no symlink or attribute copying!
+ auto createDir = [&](const Zstring& baseDirPf, bool wasExisting) -> bool
{
- if (!tryReportingError([&] { createDirectory(dirnameLeft); }, procCallback)) //may throw in error-callback!
- continue; //skip this folder pair
- }
- const Zstring dirnameRight = beforeLast(j->getBaseDirPf<RIGHT_SIDE>(), FILE_NAME_SEPARATOR);
- if (!dirnameRight.empty() && !dirExistsUpdating(dirnameRight, false, procCallback))
- {
- if (!tryReportingError([&] { createDirectory(dirnameRight); }, procCallback)) //may throw in error-callback!
- continue; //skip this folder pair
- }
+ const Zstring dirname = beforeLast(baseDirPf, FILE_NAME_SEPARATOR);
+ if (!dirname.empty())
+ {
+ if (wasExisting) //atomicity: do NOT check directory existence again!
+ {
+ //just convenience: exit sync right here instead of showing tons of error messages during file copy
+ return tryReportingError([&]
+ {
+ if (!dirExistsUpdating(dirname, false, procCallback))
+ throw FileError(replaceCpy(_("Cannot find folder %x."), L"%x", fmtFileName(dirname))); //this should really be a "fatal error"
+ }, procCallback); //may throw in error-callback!
+ }
+ else //create target directory: user presumably ignored error "dir existing" in order to have it created automatically
+ {
+ bool temporaryNetworkDrop = false;
+ bool rv = tryReportingError([&]
+ {
+ try
+ {
+ makeNewDirectory(dirname, Zstring(), false); //FileError, ErrorTargetExisting
+ //a nice race-free check and set operation!
+ }
+ catch (const ErrorTargetExisting&)
+ {
+ //TEMPORARY network drop: base directory not found during comparison, but reappears during synchronization
+ //=> sync-directions are based on false assumptions! Abort.
+ procCallback.reportFatalError(replaceCpy(_("Target folder %x already existing."), L"%x", fmtFileName(baseDirPf)));
+ temporaryNetworkDrop = true;
+
+ //Is it possible we're catching a "false-positive" here, could FFS have created the directory indirectly after comparison?
+ // 1. deletion handling: recycler -> no, temp directory created only at first deletion
+ // 2. deletion handling: versioning -> "
+ // 3. log file creates containing folder -> no, log only created in batch mode, and only *before* comparison
+ }
+ }, procCallback); //may throw in error-callback!
+ return rv && !temporaryNetworkDrop;
+ }
+ }
+ return true;
+ };
+ if (!createDir(j->getBaseDirPf<LEFT_SIDE >(), j->wasExisting<LEFT_SIDE >()) ||
+ !createDir(j->getBaseDirPf<RIGHT_SIDE>(), j->wasExisting<RIGHT_SIDE>()))
+ continue; //skip this folder pair
+
//------------------------------------------------------------------------------------------
//execute synchronization recursively
//update synchronization database (automatic sync only)
- zen::ScopeGuard guardUpdateDb = zen::makeGuard([&]
+ ScopeGuard guardUpdateDb = makeGuard([&]
{
if (folderPairCfg.inAutomaticMode)
- try { zen::saveToDisk(*j); }
+ try { zen::saveLastSynchronousState(*j); }
catch (...) {} //throw FileError
});
@@ -2204,13 +2271,12 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
#ifdef FFS_WIN
shadowCopyHandler.get(),
#endif
- delHandlerFp.first, delHandlerFp.second);
-
+ iterDelHandler->first, iterDelHandler->second);
syncFP.startSync(*j);
//(try to gracefully) cleanup temporary folders (Recycle bin optimization) -> will be done in ~DeletionHandling anyway...
- tryReportingError([&] { delHandlerFp.first .tryCleanup(); }, procCallback); //show error dialog if necessary
- tryReportingError([&] { delHandlerFp.second.tryCleanup(); }, procCallback); //
+ tryReportingError([&] { iterDelHandler->first .tryCleanup(); }, procCallback); //show error dialog if necessary
+ tryReportingError([&] { iterDelHandler->second.tryCleanup(); }, procCallback); //
//(try to gracefully) write database file (will be done in ~EnforceUpdateDatabase anyway...)
if (folderPairCfg.inAutomaticMode)
@@ -2218,7 +2284,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector<FolderPairSyncCf
procCallback.reportStatus(_("Generating database..."));
procCallback.forceUiRefresh();
- tryReportingError([&] { zen::saveToDisk(*j); }, procCallback); //throw FileError
+ tryReportingError([&] { zen::saveLastSynchronousState(*j); }, procCallback); //throw FileError
guardUpdateDb.dismiss();
}
}
@@ -2277,7 +2343,7 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
//start of (possibly) long-running copy process: ensure status updates are performed regularly
//in error situation: undo communication of processed amount of data
- zen::ScopeGuard guardStatistics = zen::makeGuard([&]
+ ScopeGuard guardStatistics = makeGuard([&]
{
procCallback_.updateProcessedData(0, -bytesReported);
bytesReported = 0;
@@ -2285,7 +2351,7 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
WhileCopying<DelTargetCommand> callback(bytesReported, procCallback_, cmd);
- zen::copyFile(source, //type File implicitly means symlinks need to be dereferenced!
+ copyFile(source, //type File implicitly means symlinks need to be dereferenced!
target,
copyFilePermissions_,
transactionalFileCopy_,
@@ -2342,8 +2408,8 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const
//#################### Verification #############################
if (verifyCopiedFiles_)
{
- zen::ScopeGuard guardTarget = zen::makeGuard([&] { removeFile(target); }); //delete target if verification fails
- zen::ScopeGuard guardStatistics = zen::makeGuard([&]
+ ScopeGuard guardTarget = makeGuard([&] { removeFile(target); }); //delete target if verification fails
+ ScopeGuard guardStatistics = makeGuard([&]
{
procCallback_.updateProcessedData(0, -bytesReported);
bytesReported = 0;
diff --git a/synchronization.h b/synchronization.h
index 525a74d1..dfead072 100644
--- a/synchronization.h
+++ b/synchronization.h
@@ -32,15 +32,16 @@ public:
int getDelete() const;
template <SelectedSide side> int getDelete() const;
- int getConflict() const { return conflict; }
+ int getConflict() const { return static_cast<int>(conflictMsgs.size()); }
typedef std::vector<std::pair<Zstring, std::wstring> > ConflictTexts; // Pair(filename/conflict text)
- const ConflictTexts& getFirstConflicts() const { return firstConflicts; }
+ const ConflictTexts& getConflictMessages() const { return conflictMsgs; }
zen::Int64 getDataToProcess() const { return dataToProcess; }
size_t getRowCount() const { return rowsTotal; }
private:
+ //static const size_t MAX_CONFLICTS = 3;
void init();
void recurse(const HierarchyObject& hierObj);
@@ -52,8 +53,8 @@ private:
int createLeft, createRight;
int updateLeft, updateRight;
int deleteLeft, deleteRight;
- int conflict;
- ConflictTexts firstConflicts; //save the first few conflict texts to display as a warning message
+ // int conflict;
+ ConflictTexts conflictMsgs; //conflict texts to display as a warning message
zen::Int64 dataToProcess;
size_t rowsTotal;
};
diff --git a/ui/batch_config.cpp b/ui/batch_config.cpp
index 10cee822..75033bf8 100644
--- a/ui/batch_config.cpp
+++ b/ui/batch_config.cpp
@@ -14,7 +14,6 @@
#include <zen/file_handling.h>
#include "msg_popup.h"
#include "gui_generated.h"
-//#include <wx/dnd.h>
#include <wx/msgdlg.h>
#include <wx+/button.h>
#include <wx+/choice_enum.h>
@@ -504,7 +503,7 @@ void BatchDialog::OnSaveBatchJob(wxCommandEvent& event)
wxEmptyString,
wxEmptyString,
defaultFileName,
- _("FreeFileSync batch file") + L" (*.ffs_batch)|*.ffs_batch" + L"|" +_("All files") + L" (*.*)|*",
+ _("FreeFileSync batch") + L" (*.ffs_batch)|*.ffs_batch" + L"|" +_("All files") + L" (*.*)|*",
wxFD_SAVE | wxFD_OVERWRITE_PROMPT); //creating this on freestore leads to memleak!
if (filePicker.ShowModal() == wxID_OK)
{
@@ -523,7 +522,7 @@ void BatchDialog::OnLoadBatchJob(wxCommandEvent& event)
wxEmptyString,
beforeLast(proposedBatchFileName, utfCvrtTo<wxString>(FILE_NAME_SEPARATOR)), //set default dir: empty string if "currentConfigFileName" is empty or has no path separator
wxEmptyString,
- _("FreeFileSync batch file") + L" (*.ffs_batch;*.ffs_gui)|*.ffs_batch;*.ffs_gui" + L"|" +_("All files") + L" (*.*)|*",
+ _("FreeFileSync batch") + L" (*.ffs_batch;*.ffs_gui)|*.ffs_batch;*.ffs_gui" + L"|" +_("All files") + L" (*.*)|*",
wxFD_OPEN | wxFD_MULTIPLE); //creating this on freestore leads to memleak!
if (filePicker.ShowModal() == wxID_OK)
{
diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp
index 89d28084..c0958025 100644
--- a/ui/batch_status_handler.cpp
+++ b/ui/batch_status_handler.cpp
@@ -5,10 +5,8 @@
// **************************************************************************
#include "batch_status_handler.h"
-#include <wx/ffile.h>
#include <zen/file_handling.h>
#include <zen/file_traverser.h>
-#include <wx+/string_conv.h>
#include <wx+/app_main.h>
#include <wx+/format_unit.h>
#include <wx+/shell_execute.h>
@@ -17,6 +15,7 @@
#include "../lib/ffs_paths.h"
#include "../lib/resolve_path.h"
#include "../lib/status_handler_impl.h"
+#include "../lib/generate_logfile.h"
using namespace zen;
@@ -44,130 +43,62 @@ private:
const Zstring prefix_;
std::vector<Zstring>& logfiles_;
};
-}
-class LogFile //throw FileError
+void limitLogfileCount(const Zstring& logdir, const std::wstring& jobname, size_t maxCount) //throw()
{
-public:
- LogFile(const Zstring& logfileDirectory,
- const std::wstring& jobName,
- const std::wstring& timestamp) :
- jobName_(jobName), //throw FileError
- logfileName(findUnusedLogname(logfileDirectory, jobName, timestamp))
- {
- logFile.Open(toWx(logfileName), L"w");
- if (!logFile.IsOpened())
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(logfileName)));
+ std::vector<Zstring> logFiles;
+ FindLogfiles traverseCallback(toZ(jobname), logFiles);
- //write header
- const wxString& headerLine = wxString(L"FreeFileSync - ") + _("Batch execution") + L" - " + formatTime<wxString>(FORMAT_DATE);
- logFile.Write(headerLine + L'\n');
- logFile.Write(wxString().Pad(headerLine.Len(), L'=') + L'\n');
+ traverseFolder(logdir, //throw();
+ traverseCallback);
- //logItemStart = formatTime<wxString>(L"[%X] ") + _("Start");
+ if (logFiles.size() <= maxCount)
+ return;
- totalTime.Start(); //measure total time
- }
+ //delete oldest logfiles
+ std::nth_element(logFiles.begin(), logFiles.end() - maxCount, logFiles.end()); //take advantage of logfile naming convention to find oldest files
- void writeLog(const ErrorLog& log, const std::wstring& finalStatus,
- int itemsSynced, Int64 dataSynced,
- int itemsTotal, Int64 dataTotal)
- {
- //assemble results box
- std::vector<wxString> results;
- results.push_back(finalStatus);
- results.push_back(L"");
- if (itemsTotal != 0 || dataTotal != 0) //=: sync phase was reached and there were actual items to sync
- {
- results.push_back(L" " + _("Items processed:") + L" " + toGuiString(itemsSynced) + L" (" + filesizeToShortString(dataSynced) + L")");
+ std::for_each(logFiles.begin(), logFiles.end() - maxCount,
+ [](const Zstring& filename) { try { removeFile(filename); } catch (FileError&) {} });
+}
- if (itemsSynced != itemsTotal ||
- dataSynced != dataTotal)
- results.push_back(L" " + _("Items remaining:") + L" " + toGuiString(itemsTotal - itemsSynced) + L" (" + filesizeToShortString(dataTotal - dataSynced) + L")");
- }
- results.push_back(L" " + _("Total time:") + L" " + wxTimeSpan::Milliseconds(totalTime.Time()).Format());
- //write results box
- size_t sepLineLen = 0;
- std::for_each(results.begin(), results.end(), [&](const wxString& str) { sepLineLen = std::max(sepLineLen, str.size()); });
+std::unique_ptr<FileOutput> prepareNewLogfile(const Zstring& logfileDirectory, //throw FileError
+ const std::wstring& jobName,
+ const std::wstring& timestamp) //return value always bound!
+{
+ //create logfile directory if required
+ Zstring logfileDir = logfileDirectory.empty() ?
+ getConfigDir() + Zstr("Logs") :
+ getFormattedDirectoryName(logfileDirectory);
- logFile.Write(wxString().Pad(sepLineLen, L'_') + L"\n\n");
- std::for_each(results.begin(), results.end(), [&](const wxString& str) { logFile.Write(str + L'\n'); });
- logFile.Write(wxString().Pad(sepLineLen, L'_') + L"\n\n");
+ makeDirectory(logfileDir); //throw FileError
- //logFile.Write(logItemStart + L"\n\n");
+ //assemble logfile name
+ const Zstring body = appendSeparator(logfileDir) + toZ(jobName) + Zstr(" ") + utfCvrtTo<Zstring>(timestamp);
- //write log items
- const auto& entries = log.getEntries();
- for (auto iter = entries.begin(); iter != entries.end(); ++iter)
+ //ensure uniqueness
+ for (int i = 0;; ++i)
+ try
{
- const std::string& msg = utfCvrtTo<std::string>(formatMessage(*iter));
- logFile.Write(msg.c_str(), msg.size()); //better do UTF8 conversion ourselves rather than to rely on wxWidgets
- logFile.Write(L'\n');
- }
+ const Zstring& filename = i == 0 ?
+ body + Zstr(".log") :
+ body + Zstr('_') + numberTo<Zstring>(i) + Zstr(".log");
- ////write footer
- //logFile.Write(L'\n');
- //logFile.Write(formatTime<wxString>(L"[%X] ") + _("Stop") + L" (" + _("Total time:") + L" " + wxTimeSpan::Milliseconds(totalTime.Time()).Format() + L")\n");
- }
-
- void limitLogfileCount(size_t maxCount) const //throw()
- {
- std::vector<Zstring> logFiles;
- FindLogfiles traverseCallback(toZ(jobName_), logFiles);
-
- traverseFolder(beforeLast(logfileName, FILE_NAME_SEPARATOR), //throw();
- traverseCallback);
-
- if (logFiles.size() <= maxCount)
- return;
-
- //delete oldest logfiles
- std::nth_element(logFiles.begin(), logFiles.end() - maxCount, logFiles.end()); //take advantage of logfile naming convention to find oldest files
-
- std::for_each(logFiles.begin(), logFiles.end() - maxCount,
- [](const Zstring& filename) { try { removeFile(filename); } catch (FileError&) {} });
- }
-
- //Zstring getLogfileName() const { return logfileName; }
-
-private:
- static Zstring findUnusedLogname(const Zstring& logfileDirectory,
- const std::wstring& jobName,
- const std::wstring& timestamp)
- {
- //create logfile directory
- Zstring logfileDir = logfileDirectory.empty() ?
- getConfigDir() + Zstr("Logs") :
- getFormattedDirectoryName(logfileDirectory);
-
- if (!dirExists(logfileDir))
- createDirectory(logfileDir); //throw FileError; create recursively if necessary
-
- //assemble logfile name
- const Zstring logfileName = appendSeparator(logfileDir) + toZ(jobName) + Zstr(" ") + utfCvrtTo<Zstring>(timestamp);
-
- //ensure uniqueness
- Zstring output = logfileName + Zstr(".log");
-
- for (int i = 1; somethingExists(output); ++i)
- output = logfileName + Zstr('_') + numberTo<Zstring>(i) + Zstr(".log");
- return output;
- }
-
- const wxString jobName_;
- const Zstring logfileName;
- wxFFile logFile;
- wxStopWatch totalTime;
-};
+ return make_unique<FileOutput>(filename, FileOutput::ACC_CREATE_NEW); //throw FileError, ErrorTargetExisting
+ //*no* file system race-condition!
+ }
+ catch (const ErrorTargetExisting&) {}
+}
+}
//##############################################################################################################################
BatchStatusHandler::BatchStatusHandler(bool showProgress,
const std::wstring& jobName,
const std::wstring& timestamp,
- const wxString& logfileDirectory,
+ const wxString& logfileDirectory, //may be empty
size_t logFileCountMax,
const xmlAccess::OnError handleError,
const SwitchToGui& switchBatchToGui, //functionality to change from batch mode to GUI mode
@@ -179,19 +110,23 @@ BatchStatusHandler::BatchStatusHandler(bool showProgress,
switchToGuiRequested(false),
handleError_(handleError),
returnCode_(returnCode),
- syncStatusFrame(*this, *this, nullptr, showProgress, jobName, execWhenFinished, execFinishedHistory)
+ syncStatusFrame(*this, *this, nullptr, showProgress, jobName, execWhenFinished, execFinishedHistory),
+ jobName_(jobName)
{
if (logFileCountMax > 0) //init log file: starts internal timer!
if (!tryReportingError([&]
{
- logFile.reset(new LogFile(toZ(logfileDirectory), jobName, timestamp)); //throw FileError
- logFile->limitLogfileCount(logFileCountMax); //throw()
+ logFile = prepareNewLogfile(toZ(logfileDirectory), jobName, timestamp); //throw FileError; return value always bound!
+
+ limitLogfileCount(beforeLast(logFile->getFilename(), FILE_NAME_SEPARATOR), jobName_, logFileCountMax); //throw()
}, *this))
{
returnCode_ = FFS_RC_ABORTED;
throw BatchAbortProcess();
}
+ totalTime.Start(); //measure total time
+
//::wxSetEnv(L"logfile", logFile->getLogfileName());
}
@@ -224,14 +159,26 @@ BatchStatusHandler::~BatchStatusHandler()
errorLog.logMsg(finalStatus, TYPE_INFO);
}
+ const Utf8String logStream = generateLogStream(errorLog, jobName_, finalStatus,
+ getObjectsCurrent(PHASE_SYNCHRONIZING), getDataCurrent(PHASE_SYNCHRONIZING),
+ getObjectsTotal (PHASE_SYNCHRONIZING), getDataTotal (PHASE_SYNCHRONIZING), totalTime.Time() / 1000);
//print the results list: logfile
if (logFile.get())
{
- logFile->writeLog(errorLog, finalStatus,
- getObjectsCurrent(PHASE_SYNCHRONIZING), getDataCurrent(PHASE_SYNCHRONIZING),
- getObjectsTotal (PHASE_SYNCHRONIZING), getDataTotal (PHASE_SYNCHRONIZING));
+ try
+ {
+ if (!logStream.empty())
+ logFile->write(&*logStream.begin(), logStream.size()); //throw FileError
+ }
+ catch (FileError&) {}
+
logFile.reset(); //close file now: user may do something with it in "on completion"
}
+ try
+ {
+ saveToLastSyncsLog(logStream); //throw FileError
+ }
+ catch (FileError&) {}
//decide whether to stay on status screen or exit immediately...
if (switchToGuiRequested) //-> avoid recursive yield() calls, thous switch not before ending batch mode
@@ -326,11 +273,11 @@ void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
bool dontWarnAgain = false;
switch (showWarningDlg(syncStatusFrame.getAsWindow(),
- ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_SWITCH | ReturnWarningDlg::BUTTON_ABORT,
+ ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_SWITCH | ReturnWarningDlg::BUTTON_CANCEL,
warningMessage + L"\n\n" + _("Press \"Switch\" to resolve issues in FreeFileSync main dialog."),
dontWarnAgain))
{
- case ReturnWarningDlg::BUTTON_ABORT:
+ case ReturnWarningDlg::BUTTON_CANCEL:
abortThisProcess();
break;
@@ -368,7 +315,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er
bool ignoreNextErrors = false;
switch (showErrorDlg(syncStatusFrame.getAsWindow(),
- ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL,
errorMessage, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
@@ -380,7 +327,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& er
case ReturnErrorDlg::BUTTON_RETRY:
return ProcessCallback::RETRY;
- case ReturnErrorDlg::BUTTON_ABORT:
+ case ReturnErrorDlg::BUTTON_CANCEL:
errorLog.logMsg(errorMessage, TYPE_ERROR);
abortThisProcess();
}
@@ -414,21 +361,18 @@ void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage)
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(syncStatusFrame.getAsWindow(),
- ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_ABORT,
- errorMessage, &ignoreNextErrors))
+ switch (showFatalErrorDlg(syncStatusFrame.getAsWindow(),
+ ReturnFatalErrorDlg::BUTTON_IGNORE | ReturnFatalErrorDlg::BUTTON_CANCEL,
+ errorMessage, &ignoreNextErrors))
{
- case ReturnErrorDlg::BUTTON_IGNORE:
+ case ReturnFatalErrorDlg::BUTTON_IGNORE:
if (ignoreNextErrors) //falsify only
handleError_ = xmlAccess::ON_ERROR_IGNORE;
break;
- case ReturnErrorDlg::BUTTON_ABORT:
+ case ReturnFatalErrorDlg::BUTTON_CANCEL:
abortThisProcess();
break;
-
- case ReturnErrorDlg::BUTTON_RETRY:
- assert(false);
}
}
break;
diff --git a/ui/batch_status_handler.h b/ui/batch_status_handler.h
index 56e9e781..c6def13c 100644
--- a/ui/batch_status_handler.h
+++ b/ui/batch_status_handler.h
@@ -8,13 +8,13 @@
#define BATCHSTATUSHANDLER_H_INCLUDED
#include <zen/error_log.h>
+#include <zen/file_io.h>
#include "../lib/status_handler.h"
#include "../lib/process_xml.h"
#include "progress_indicator.h"
#include "switch_to_gui.h"
#include "lib/return_codes.h"
-class LogFile;
//Exception class used to abort the "compare" and "sync" process
class BatchAbortProcess {};
@@ -55,7 +55,10 @@ private:
zen::FfsReturnCode& returnCode_;
SyncStatus syncStatusFrame; //the window managed by SyncStatus has longer lifetime than this handler!
- std::unique_ptr<LogFile> logFile; //optional!
+ std::unique_ptr<zen::FileOutput> logFile; //optional!
+
+ const std::wstring jobName_;
+ wxStopWatch totalTime;
};
diff --git a/ui/check_version.cpp b/ui/check_version.cpp
index 5856f95a..56896836 100644
--- a/ui/check_version.cpp
+++ b/ui/check_version.cpp
@@ -15,56 +15,46 @@
#include <zen/string_tools.h>
#include "msg_popup.h"
#include "../lib/ffs_paths.h"
-#include <zen/scope_guard.h>
-#include <wx/tokenzr.h>
#include <zen/i18n.h>
+using namespace zen;
-bool getOnlineVersion(wxString& version)
+
+wxString getOnlineVersion() //empty string on error;
{
wxWindowDisabler dummy;
wxHTTP webAccess;
- webAccess.SetHeader(wxT("Content-type"), wxT("text/html; charset=utf-8"));
- webAccess.SetTimeout(5); //5 seconds of timeout instead of 10 minutes...
+ webAccess.SetHeader(L"Content-type", L"text/html; charset=utf-8");
+ webAccess.SetTimeout(5); //5 seconds of timeout instead of 10 minutes(WTF are they thinking???)...
- if (webAccess.Connect(wxT("freefilesync.cvs.sourceforge.net"))) //only the server, no pages here yet...
+ if (webAccess.Connect(L"freefilesync.cvs.sourceforge.net")) //only the server, no pages here yet...
{
//wxApp::IsMainLoopRunning(); // should return true
- std::unique_ptr<wxInputStream> httpStream(webAccess.GetInputStream(wxT("/viewvc/freefilesync/version/version.txt")));
+ std::unique_ptr<wxInputStream> httpStream(webAccess.GetInputStream(L"/viewvc/freefilesync/version/version.txt"));
//must be deleted BEFORE webAccess is closed
if (httpStream && webAccess.GetError() == wxPROTO_NOERR)
{
- wxString newestVersion;
- wxStringOutputStream out_stream(&newestVersion);
+ wxString onlineVersion;
+ wxStringOutputStream out_stream(&onlineVersion);
httpStream->Read(out_stream);
- if (!newestVersion.empty())
- {
- version = newestVersion;
- return true;
- }
+ return onlineVersion;
}
}
-
- return false;
+ return wxString();
}
const wchar_t VERSION_SEP = L'.';
-
std::vector<size_t> parseVersion(const wxString& version)
{
- std::vector<size_t> output;
+ std::vector<wxString> digits = split(version, VERSION_SEP);
- wxStringTokenizer tkz(version, VERSION_SEP, wxTOKEN_RET_EMPTY);
- while (tkz.HasMoreTokens())
- {
- const wxString& token = tkz.GetNextToken();
- output.push_back(zen::stringTo<size_t>(token));
- }
+ std::vector<size_t> output;
+ std::transform(digits.begin(), digits.end(), std::back_inserter(output), [&](const wxString& d) { return stringTo<size_t>(d); });
return output;
}
@@ -74,18 +64,18 @@ bool isNewerVersion(const wxString& onlineVersion)
std::vector<size_t> current = parseVersion(zen::currentVersion);
std::vector<size_t> online = parseVersion(onlineVersion);
- if (online.empty() || online[0] == 0) //onlineVersion may be "This website has been moved..." In this case better check for an update
+ if (online.empty() || online[0] == 0) //online version may be "This website has been moved..." In this case better check for an update
return true;
return std::lexicographical_compare(current.begin(), current.end(),
- online.begin(), online.end());
+ online .begin(), online .end());
}
void zen::checkForUpdateNow(wxWindow* parent)
{
- wxString onlineVersion;
- if (!getOnlineVersion(onlineVersion))
+ const wxString onlineVersion = getOnlineVersion();
+ if (onlineVersion.empty())
{
wxMessageBox(_("Unable to connect to sourceforge.net!"), _("Error"), wxOK | wxICON_ERROR, parent);
return;
@@ -94,7 +84,7 @@ void zen::checkForUpdateNow(wxWindow* parent)
if (isNewerVersion(onlineVersion))
{
if (showQuestionDlg(parent, ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_CANCEL,
- _("A newer version of FreeFileSync is available:") + L" " + onlineVersion + L"\n\n" + _("Download now?")) == ReturnQuestionDlg::BUTTON_YES)
+ _("A new version of FreeFileSync is available:") + L" " + onlineVersion + L"\n\n" + _("Download now?")) == ReturnQuestionDlg::BUTTON_YES)
wxLaunchDefaultBrowser(L"http://sourceforge.net/projects/freefilesync/files/freefilesync/v" + onlineVersion + L"/");
}
else
@@ -105,7 +95,7 @@ void zen::checkForUpdateNow(wxWindow* parent)
void zen::checkForUpdatePeriodically(wxWindow* parent, long& lastUpdateCheck)
{
#ifdef FFS_LINUX
- if (!zen::isPortableVersion()) //don't check for updates in installer version -> else: handled by .deb
+ if (!zen::isPortableVersion()) //don't check for updates in locally installed version -> handled by system updater
return;
#endif
@@ -132,8 +122,8 @@ void zen::checkForUpdatePeriodically(wxWindow* parent, long& lastUpdateCheck)
}
else if (wxGetLocalTime() >= lastUpdateCheck + 7 * 24 * 3600) //check weekly
{
- wxString onlineVersion;
- if (!getOnlineVersion(onlineVersion))
+ const wxString onlineVersion = getOnlineVersion();
+ if (onlineVersion.empty())
return; //do not handle error
lastUpdateCheck = wxGetLocalTime();
@@ -141,7 +131,7 @@ void zen::checkForUpdatePeriodically(wxWindow* parent, long& lastUpdateCheck)
if (isNewerVersion(onlineVersion))
{
if (showQuestionDlg(parent, ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_CANCEL,
- _("A newer version of FreeFileSync is available:") + L" " + onlineVersion + L"\n\n" + _("Download now?")) == ReturnQuestionDlg::BUTTON_YES)
+ _("A new version of FreeFileSync is available:") + L" " + onlineVersion + L"\n\n" + _("Download now?")) == ReturnQuestionDlg::BUTTON_YES)
wxLaunchDefaultBrowser(L"http://sourceforge.net/projects/freefilesync/files/freefilesync/v" + onlineVersion + L"/");
}
}
diff --git a/ui/custom_grid.cpp b/ui/custom_grid.cpp
index d6180dd0..f340a819 100644
--- a/ui/custom_grid.cpp
+++ b/ui/custom_grid.cpp
@@ -347,6 +347,9 @@ private:
case COL_TYPE_SIZE: //file size
if (!fsObj_.isEmpty<side>())
value = zen::toGuiString(fileObj.getFileSize<side>());
+
+ //if (!fsObj_.isEmpty<side>()) -> test file id
+ // value = toGuiString(fileObj.getFileId<side>().second);
break;
case COL_TYPE_DATE: //date
if (!fsObj_.isEmpty<side>())
@@ -647,14 +650,14 @@ private:
virtual void visit(const FileMapping& fileObj)
{
tipMsg_ += L"\n" +
- _("Size") + L": " + zen::filesizeToShortString(to<Int64>(fileObj.getFileSize<side>())) + L"\n" +
- _("Date") + L": " + zen::utcToLocalTimeString(fileObj.getLastWriteTime<side>());
+ _("Size:") + L" " + zen::filesizeToShortString(to<Int64>(fileObj.getFileSize<side>())) + L"\n" +
+ _("Date:") + L" " + zen::utcToLocalTimeString(fileObj.getLastWriteTime<side>());
}
virtual void visit(const SymLinkMapping& linkObj)
{
tipMsg_ += L"\n" +
- _("Date") + L": " + zen::utcToLocalTimeString(linkObj.getLastWriteTime<side>());
+ _("Date:") + L" " + zen::utcToLocalTimeString(linkObj.getLastWriteTime<side>());
}
virtual void visit(const DirMapping& dirObj) {}
@@ -769,7 +772,8 @@ public:
void onSelectBegin(const wxPoint& clientPos, size_t row, ColumnType colType)
{
- if (static_cast<ColumnTypeMiddle>(colType) == COL_TYPE_MIDDLE_VALUE)
+ if (static_cast<ColumnTypeMiddle>(colType) == COL_TYPE_MIDDLE_VALUE &&
+ row < refGrid().getRowCount())
{
refGrid().clearSelection(gridview::COMP_MIDDLE);
dragSelection.reset(new std::pair<size_t, BlockPosition>(row, mousePosToBlock(clientPos, row)));
diff --git a/ui/dir_name.cpp b/ui/dir_name.cpp
index fcab49ca..3d8db37d 100644
--- a/ui/dir_name.cpp
+++ b/ui/dir_name.cpp
@@ -22,7 +22,7 @@ namespace
{
void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, wxWindow& tooltipWnd, wxStaticText* staticText, size_t timeout)
{
- const wxString dirFormatted = toWx(getFormattedDirectoryName(toZ(dirname)));
+ const wxString dirFormatted = utfCvrtTo<wxString>(getFormattedDirectoryName(toZ(dirname)));
tooltipWnd.SetToolTip(nullptr); //workaround wxComboBox bug http://trac.wxwidgets.org/ticket/10512 / http://trac.wxwidgets.org/ticket/12659
tooltipWnd.SetToolTip(dirFormatted); //only lord knows when the real bugfix reaches mere mortals via an official release
diff --git a/ui/folder_history_box.cpp b/ui/folder_history_box.cpp
index d30ada64..2b773c20 100644
--- a/ui/folder_history_box.cpp
+++ b/ui/folder_history_box.cpp
@@ -8,6 +8,7 @@
#include <list>
#include <wx/scrolwin.h>
#include "../lib/resolve_path.h"
+#include <wx+/string_conv.h>
using namespace zen;
diff --git a/ui/folder_history_box.h b/ui/folder_history_box.h
index 24ff1725..68197786 100644
--- a/ui/folder_history_box.h
+++ b/ui/folder_history_box.h
@@ -10,7 +10,6 @@
#include <wx/combobox.h>
#include <memory>
#include <zen/zstring.h>
-#include <wx+/string_conv.h>
#include <zen/stl_tools.h>
//combobox with history function + functionality to delete items (DEL)
diff --git a/ui/folder_pair.h b/ui/folder_pair.h
index 3dadc07c..c9f42259 100644
--- a/ui/folder_pair.h
+++ b/ui/folder_pair.h
@@ -15,7 +15,6 @@
#include <wx/event.h>
#include <wx+/context_menu.h>
#include <wx/menu.h>
-#include <wx+/string_conv.h>
#include "../lib/norm_filter.h"
#include <wx+/button.h>
#include <wx+/image_tools.h>
diff --git a/ui/grid_view.h b/ui/grid_view.h
index c830224b..5fc80338 100644
--- a/ui/grid_view.h
+++ b/ui/grid_view.h
@@ -181,16 +181,12 @@ private:
-
-
-
-//############################################################################
-//inline implementation
+//##################### implementation #########################################
inline
const FileSystemObject* GridView::getObject(size_t row) const
{
- return row < rowsOnView() ?
+ return row < viewRef.size() ?
FileSystemObject::retrieve(viewRef[row]) : nullptr;
}
diff --git a/ui/gui_generated.cpp b/ui/gui_generated.cpp
index c59028c2..c0f83cec 100644
--- a/ui/gui_generated.cpp
+++ b/ui/gui_generated.cpp
@@ -44,9 +44,12 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
m_menuItemLoad = new wxMenuItem( m_menuFile, wxID_OPEN, wxString( _("&Open...") ) + wxT('\t') + wxT("Ctrl+O"), wxEmptyString, wxITEM_NORMAL );
m_menuFile->Append( m_menuItemLoad );
- m_menuItemSave = new wxMenuItem( m_menuFile, wxID_SAVE, wxString( _("&Save...") ) + wxT('\t') + wxT("Ctrl+S"), wxEmptyString, wxITEM_NORMAL );
+ m_menuItemSave = new wxMenuItem( m_menuFile, wxID_SAVE, wxString( _("&Save") ) + wxT('\t') + wxT("Ctrl+S"), wxEmptyString, wxITEM_NORMAL );
m_menuFile->Append( m_menuItemSave );
+ m_menuItemSaveAs = new wxMenuItem( m_menuFile, wxID_SAVEAS, wxString( _("Save &As...") ) , wxEmptyString, wxITEM_NORMAL );
+ m_menuFile->Append( m_menuItemSaveAs );
+
m_menuFile->AppendSeparator();
wxMenuItem* m_menuItem4;
@@ -559,19 +562,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer1712;
bSizer1712 = new wxBoxSizer( wxVERTICAL );
-
- bSizer1712->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapCreateLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
m_bitmapCreateLeft->SetToolTip( _("Number of files and folders that will be created") );
bSizer1712->Add( m_bitmapCreateLeft, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- bSizer1712->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer1712->Add( 5, 2, 0, 0, 5 );
- bSizer1712->Add( 2, 2, 0, 0, 5 );
+ bSizer1712->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextCreateLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCreateLeft->Wrap( -1 );
@@ -588,19 +588,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer172;
bSizer172 = new wxBoxSizer( wxVERTICAL );
-
- bSizer172->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapUpdateLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
m_bitmapUpdateLeft->SetToolTip( _("Number of files that will be overwritten") );
bSizer172->Add( m_bitmapUpdateLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
- bSizer172->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer172->Add( 5, 2, 0, 0, 5 );
- bSizer172->Add( 2, 2, 0, 0, 5 );
+ bSizer172->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextUpdateLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextUpdateLeft->Wrap( -1 );
@@ -617,19 +614,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer173;
bSizer173 = new wxBoxSizer( wxVERTICAL );
-
- bSizer173->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapDeleteLeft = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
m_bitmapDeleteLeft->SetToolTip( _("Number of files and folders that will be deleted") );
bSizer173->Add( m_bitmapDeleteLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
- bSizer173->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer173->Add( 5, 2, 0, 0, 5 );
- bSizer173->Add( 2, 2, 0, 0, 5 );
+ bSizer173->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextDeleteLeft = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextDeleteLeft->Wrap( -1 );
@@ -645,23 +639,20 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizerData = new wxBoxSizer( wxVERTICAL );
-
- bSizerData->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapData = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- m_bitmapData->SetToolTip( _("Total amount of data that will be transferred") );
+ m_bitmapData->SetToolTip( _("Total bytes to copy") );
bSizerData->Add( m_bitmapData, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- bSizerData->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizerData->Add( 5, 2, 0, 0, 5 );
- bSizerData->Add( 2, 2, 0, 0, 5 );
+ bSizerData->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextData = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextData->Wrap( -1 );
- m_staticTextData->SetToolTip( _("Total amount of data that will be transferred") );
+ m_staticTextData->SetToolTip( _("Total bytes to copy") );
bSizerData->Add( m_staticTextData, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -674,19 +665,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer176;
bSizer176 = new wxBoxSizer( wxVERTICAL );
-
- bSizer176->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapDeleteRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
m_bitmapDeleteRight->SetToolTip( _("Number of files and folders that will be deleted") );
bSizer176->Add( m_bitmapDeleteRight, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
- bSizer176->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer176->Add( 5, 2, 0, 0, 5 );
- bSizer176->Add( 2, 2, 0, 0, 5 );
+ bSizer176->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextDeleteRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextDeleteRight->Wrap( -1 );
@@ -703,19 +691,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer177;
bSizer177 = new wxBoxSizer( wxVERTICAL );
-
- bSizer177->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapUpdateRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
m_bitmapUpdateRight->SetToolTip( _("Number of files that will be overwritten") );
bSizer177->Add( m_bitmapUpdateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- bSizer177->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer177->Add( 5, 2, 0, 0, 5 );
- bSizer177->Add( 2, 2, 0, 0, 5 );
+ bSizer177->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextUpdateRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextUpdateRight->Wrap( -1 );
@@ -732,19 +717,16 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer178;
bSizer178 = new wxBoxSizer( wxVERTICAL );
-
- bSizer178->Add( 0, 0, 1, wxEXPAND, 5 );
-
m_bitmapCreateRight = new wxStaticBitmap( m_panelStatistics, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
m_bitmapCreateRight->SetToolTip( _("Number of files and folders that will be created") );
bSizer178->Add( m_bitmapCreateRight, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
- bSizer178->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer178->Add( 5, 2, 0, 0, 5 );
- bSizer178->Add( 2, 2, 0, 0, 5 );
+ bSizer178->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextCreateRight = new wxStaticText( m_panelStatistics, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextCreateRight->Wrap( -1 );
@@ -832,9 +814,10 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) );
this->Connect( m_menuItem10->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) );
this->Connect( m_menuItem11->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ) );
- this->Connect( m_menuItemNew->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnNewConfig ) );
- this->Connect( m_menuItemLoad->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ) );
- this->Connect( m_menuItemSave->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ) );
+ this->Connect( m_menuItemNew->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigNew ) );
+ this->Connect( m_menuItemLoad->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ) );
+ this->Connect( m_menuItemSave->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSave ) );
+ this->Connect( m_menuItemSaveAs->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSaveAs ) );
this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) );
this->Connect( m_menuItemGlobSett->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuGlobalSettings ) );
this->Connect( m_menuItem7->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuBatchJob ) );
@@ -851,8 +834,8 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
m_dirPickerLeft->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this );
m_bpButtonSwapSides->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapSides ), NULL, this );
m_dirPickerRight->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this );
- m_bpButtonLoad->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ), NULL, this );
- m_bpButtonSave->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ), NULL, this );
+ m_bpButtonLoad->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), NULL, this );
+ m_bpButtonSave->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigSaveAs ), NULL, this );
m_listBoxHistory->Connect( wxEVT_CHAR, wxKeyEventHandler( MainDialogGenerated::OnCfgHistoryKeyEvent ), NULL, this );
m_listBoxHistory->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadFromHistory ), NULL, this );
m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this );
@@ -879,9 +862,10 @@ MainDialogGenerated::~MainDialogGenerated()
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ) );
- this->Disconnect( wxID_NEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnNewConfig ) );
- this->Disconnect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ) );
- this->Disconnect( wxID_SAVE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ) );
+ this->Disconnect( wxID_NEW, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigNew ) );
+ this->Disconnect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ) );
+ this->Disconnect( wxID_SAVE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSave ) );
+ this->Disconnect( wxID_SAVEAS, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnConfigSaveAs ) );
this->Disconnect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) );
this->Disconnect( wxID_PREFERENCES, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuGlobalSettings ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuBatchJob ) );
@@ -898,8 +882,8 @@ MainDialogGenerated::~MainDialogGenerated()
m_dirPickerLeft->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this );
m_bpButtonSwapSides->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapSides ), NULL, this );
m_dirPickerRight->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this );
- m_bpButtonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnLoadConfig ), NULL, this );
- m_bpButtonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSaveConfig ), NULL, this );
+ m_bpButtonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigLoad ), NULL, this );
+ m_bpButtonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigSaveAs ), NULL, this );
m_listBoxHistory->Disconnect( wxEVT_CHAR, wxKeyEventHandler( MainDialogGenerated::OnCfgHistoryKeyEvent ), NULL, this );
m_listBoxHistory->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnLoadFromHistory ), NULL, this );
m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this );
@@ -1109,7 +1093,7 @@ CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id,
sSizerTimeRemaining = new wxBoxSizer( wxHORIZONTAL );
- m_staticTextTimeRemFixed = new wxStaticText( this, wxID_ANY, _("Remaining time:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextTimeRemFixed = new wxStaticText( this, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextTimeRemFixed->Wrap( -1 );
m_staticTextTimeRemFixed->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
@@ -1130,7 +1114,7 @@ CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id,
sSizerTimeElapsed = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* m_staticText37;
- m_staticText37 = new wxStaticText( this, wxID_ANY, _("Elapsed time:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText37 = new wxStaticText( this, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText37->Wrap( -1 );
m_staticText37->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
@@ -1539,16 +1523,16 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer68;
bSizer68 = new wxBoxSizer( wxHORIZONTAL );
- m_buttonSave = new wxButton( this, wxID_SAVE, _("&Save..."), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonSave->SetDefault();
- m_buttonSave->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
-
- bSizer68->Add( m_buttonSave, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
-
m_buttonLoad = new wxButton( this, wxID_OPEN, _("&Open..."), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_buttonLoad->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
- bSizer68->Add( m_buttonLoad, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ bSizer68->Add( m_buttonLoad, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
+
+ m_buttonSave = new wxButton( this, wxID_SAVE, _("Save &As..."), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonSave->SetDefault();
+ m_buttonSave->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) );
+
+ bSizer68->Add( m_buttonSave, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_button6 = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
m_button6->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
@@ -1575,8 +1559,8 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
m_bpButtonRemovePair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRemoveTopFolderPair ), NULL, this );
m_choiceHandleError->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnChangeErrorHandling ), NULL, this );
m_spinCtrlLogCountMax->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BatchDlgGenerated::OnChangeMaxLogCountTxt ), NULL, this );
- m_buttonSave->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this );
m_buttonLoad->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLoadBatchJob ), NULL, this );
+ m_buttonSave->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this );
m_button6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this );
}
@@ -1592,8 +1576,8 @@ BatchDlgGenerated::~BatchDlgGenerated()
m_bpButtonRemovePair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRemoveTopFolderPair ), NULL, this );
m_choiceHandleError->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( BatchDlgGenerated::OnChangeErrorHandling ), NULL, this );
m_spinCtrlLogCountMax->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( BatchDlgGenerated::OnChangeMaxLogCountTxt ), NULL, this );
- m_buttonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this );
m_buttonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLoadBatchJob ), NULL, this );
+ m_buttonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this );
m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this );
}
@@ -2257,7 +2241,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
m_staticTextStatus->Wrap( -1 );
m_staticTextStatus->SetFont( wxFont( 14, 70, 90, 92, false, wxEmptyString ) );
- bSizer42->Add( m_staticTextStatus, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxTOP, 5 );
+ bSizer42->Add( m_staticTextStatus, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 5 );
m_animationControl1 = new wxAnimationCtrl( m_panelHeader, wxID_ANY, wxNullAnimation, wxDefaultPosition, wxDefaultSize, wxAC_DEFAULT_STYLE );
m_animationControl1->SetMinSize( wxSize( 45,45 ) );
@@ -2359,7 +2343,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
fgSizer10->Add( m_staticTextSpeed, 0, wxALIGN_BOTTOM, 5 );
- m_staticTextLabelRemTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Remaining time:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextLabelRemTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextLabelRemTime->Wrap( -1 );
m_staticTextLabelRemTime->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
@@ -2371,7 +2355,7 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id,
fgSizer10->Add( m_staticTextRemTime, 0, wxALIGN_BOTTOM, 5 );
- m_staticTextLabelElapsedTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Elapsed time:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextLabelElapsedTime = new wxStaticText( m_panelProgress, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextLabelElapsedTime->Wrap( -1 );
m_staticTextLabelElapsedTime->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
@@ -2561,20 +2545,20 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer53;
bSizer53 = new wxBoxSizer( wxVERTICAL );
- m_panel5 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxSIMPLE_BORDER|wxTAB_TRAVERSAL );
- m_panel5->SetBackgroundColour( wxColour( 255, 255, 255 ) );
+ m_panelLogo = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxSIMPLE_BORDER|wxTAB_TRAVERSAL );
+ m_panelLogo->SetBackgroundColour( wxColour( 255, 255, 255 ) );
wxBoxSizer* bSizer36;
bSizer36 = new wxBoxSizer( wxHORIZONTAL );
- m_bitmap11 = new wxStaticBitmap( m_panel5, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_bitmap11 = new wxStaticBitmap( m_panelLogo, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer36->Add( m_bitmap11, 0, wxALIGN_CENTER_VERTICAL, 5 );
- m_panel5->SetSizer( bSizer36 );
- m_panel5->Layout();
- bSizer36->Fit( m_panel5 );
- bSizer53->Add( m_panel5, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxBOTTOM, 5 );
+ m_panelLogo->SetSizer( bSizer36 );
+ m_panelLogo->Layout();
+ bSizer36->Fit( m_panelLogo );
+ bSizer53->Add( m_panelLogo, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxBOTTOM, 5 );
m_build = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_build->Wrap( -1 );
@@ -2680,57 +2664,54 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizerCodeInfo->Fit( m_panel33 );
bSizer53->Add( m_panel33, 0, wxBOTTOM|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
- wxStaticBoxSizer* sbSizer29;
- sbSizer29 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Feedback and suggestions are welcome") ), wxHORIZONTAL );
-
- wxBoxSizer* bSizer170;
- bSizer170 = new wxBoxSizer( wxHORIZONTAL );
-
-
- bSizer170->Add( 0, 0, 1, wxEXPAND, 5 );
-
- m_hyperlink1 = new wxHyperlinkCtrl( this, wxID_ANY, _("Homepage"), wxT("http://sourceforge.net/projects/freefilesync/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink1->SetFont( wxFont( 10, 70, 90, 92, true, wxEmptyString ) );
- m_hyperlink1->SetToolTip( _("http://sourceforge.net/projects/freefilesync/") );
-
- bSizer170->Add( m_hyperlink1, 0, wxALIGN_CENTER_VERTICAL, 5 );
-
- m_bitmap9 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
- m_bitmap9->SetToolTip( _("FreeFileSync at Sourceforge") );
-
- bSizer170->Add( m_bitmap9, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+ m_panel40 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_panel40->SetBackgroundColour( wxColour( 153, 170, 187 ) );
+ wxBoxSizer* bSizer183;
+ bSizer183 = new wxBoxSizer( wxVERTICAL );
- bSizer170->Add( 0, 0, 1, wxEXPAND, 5 );
+ m_panel39 = new wxPanel( m_panel40, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+ m_panel39->SetBackgroundColour( wxColour( 221, 221, 255 ) );
+ wxBoxSizer* bSizer184;
+ bSizer184 = new wxBoxSizer( wxHORIZONTAL );
- sbSizer29->Add( bSizer170, 1, wxALIGN_CENTER_VERTICAL, 5 );
+ m_staticText83 = new wxStaticText( m_panel39, wxID_ANY, _("If you like FreeFileSync"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText83->Wrap( -1 );
+ m_staticText83->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 93, 92, false, wxEmptyString ) );
+ m_staticText83->SetForegroundColour( wxColour( 0, 0, 0 ) );
- wxBoxSizer* bSizer1711;
- bSizer1711 = new wxBoxSizer( wxHORIZONTAL );
+ bSizer184->Add( m_staticText83, 0, wxALL, 5 );
- bSizer1711->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer184->Add( 0, 0, 1, wxEXPAND, 5 );
- m_hyperlink2 = new wxHyperlinkCtrl( this, wxID_ANY, _("Email"), wxT("mailto:zhnmju123@gmx.de"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink2->SetFont( wxFont( 10, 70, 90, 92, true, wxEmptyString ) );
- m_hyperlink2->SetToolTip( _("zhnmju123@gmx.de") );
+ m_hyperlink3 = new wxHyperlinkCtrl( m_panel39, wxID_ANY, _("Donate with PayPal"), wxT("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=zhnmju123@gmx.de&lc=US&currency_code=EUR"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink3->SetFont( wxFont( 10, 70, 90, 92, true, wxEmptyString ) );
+ m_hyperlink3->SetBackgroundColour( wxColour( 221, 221, 255 ) );
+ m_hyperlink3->SetToolTip( _("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=zhnmju123@gmx.de&lc=US&currency_code=EUR") );
- bSizer1711->Add( m_hyperlink2, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer184->Add( m_hyperlink3, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
- m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
- m_bitmap10->SetToolTip( _("Email") );
+ m_bitmapPaypal = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ m_bitmapPaypal->SetToolTip( _("Donate with PayPal") );
- bSizer1711->Add( m_bitmap10, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+ bSizer184->Add( m_bitmapPaypal, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
- bSizer1711->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer184->Add( 0, 0, 1, wxEXPAND, 5 );
- sbSizer29->Add( bSizer1711, 1, wxALIGN_CENTER_VERTICAL, 5 );
+ m_panel39->SetSizer( bSizer184 );
+ m_panel39->Layout();
+ bSizer184->Fit( m_panel39 );
+ bSizer183->Add( m_panel39, 0, wxEXPAND|wxALL, 5 );
- bSizer53->Add( sbSizer29, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 );
+ m_panel40->SetSizer( bSizer183 );
+ m_panel40->Layout();
+ bSizer183->Fit( m_panel40 );
+ bSizer53->Add( m_panel40, 0, wxEXPAND|wxBOTTOM|wxALIGN_CENTER_HORIZONTAL, 5 );
m_scrolledWindowTranslators = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxSize( -1,-1 ), wxDOUBLE_BORDER|wxHSCROLL|wxVSCROLL );
m_scrolledWindowTranslators->SetScrollRate( 5, 5 );
@@ -2761,54 +2742,57 @@ AboutDlgGenerated::AboutDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizerTranslators->Fit( m_scrolledWindowTranslators );
bSizer53->Add( m_scrolledWindowTranslators, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxEXPAND, 5 );
- m_panel40 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
- m_panel40->SetBackgroundColour( wxColour( 153, 170, 187 ) );
+ wxStaticBoxSizer* sbSizer29;
+ sbSizer29 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Feedback and suggestions are welcome") ), wxHORIZONTAL );
- wxBoxSizer* bSizer183;
- bSizer183 = new wxBoxSizer( wxVERTICAL );
+ wxBoxSizer* bSizer170;
+ bSizer170 = new wxBoxSizer( wxHORIZONTAL );
- m_panel39 = new wxPanel( m_panel40, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
- m_panel39->SetBackgroundColour( wxColour( 221, 221, 255 ) );
- wxBoxSizer* bSizer184;
- bSizer184 = new wxBoxSizer( wxHORIZONTAL );
+ bSizer170->Add( 0, 0, 1, wxEXPAND, 5 );
- m_staticText83 = new wxStaticText( m_panel39, wxID_ANY, _("If you like FreeFileSync"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticText83->Wrap( -1 );
- m_staticText83->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 93, 92, false, wxEmptyString ) );
- m_staticText83->SetForegroundColour( wxColour( 0, 0, 0 ) );
+ m_hyperlink1 = new wxHyperlinkCtrl( this, wxID_ANY, _("Homepage"), wxT("http://sourceforge.net/projects/freefilesync/"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink1->SetFont( wxFont( 10, 70, 90, 92, true, wxEmptyString ) );
+ m_hyperlink1->SetToolTip( _("http://sourceforge.net/projects/freefilesync/") );
- bSizer184->Add( m_staticText83, 0, wxALL, 5 );
+ bSizer170->Add( m_hyperlink1, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ m_bitmap9 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_bitmap9->SetToolTip( _("FreeFileSync at Sourceforge") );
- bSizer184->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer170->Add( m_bitmap9, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
- m_hyperlink3 = new wxHyperlinkCtrl( m_panel39, wxID_ANY, _("Donate with PayPal"), wxT("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=zhnmju123@gmx.de&lc=US&currency_code=EUR"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- m_hyperlink3->SetFont( wxFont( 10, 70, 90, 92, true, wxEmptyString ) );
- m_hyperlink3->SetBackgroundColour( wxColour( 221, 221, 255 ) );
- m_hyperlink3->SetToolTip( _("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=zhnmju123@gmx.de&lc=US&currency_code=EUR") );
- bSizer184->Add( m_hyperlink3, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ bSizer170->Add( 0, 0, 1, wxEXPAND, 5 );
- m_bitmapPaypal = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- m_bitmapPaypal->SetToolTip( _("Donate with PayPal") );
- bSizer184->Add( m_bitmapPaypal, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ sbSizer29->Add( bSizer170, 1, wxALIGN_CENTER_VERTICAL, 5 );
+ wxBoxSizer* bSizer1711;
+ bSizer1711 = new wxBoxSizer( wxHORIZONTAL );
- bSizer184->Add( 0, 0, 1, wxEXPAND, 5 );
+ bSizer1711->Add( 0, 0, 1, wxEXPAND, 5 );
- m_panel39->SetSizer( bSizer184 );
- m_panel39->Layout();
- bSizer184->Fit( m_panel39 );
- bSizer183->Add( m_panel39, 0, wxEXPAND|wxALL, 5 );
+ m_hyperlink2 = new wxHyperlinkCtrl( this, wxID_ANY, _("Email"), wxT("mailto:zhnmju123@gmx.de"), wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ m_hyperlink2->SetFont( wxFont( 10, 70, 90, 92, true, wxEmptyString ) );
+ m_hyperlink2->SetToolTip( _("zhnmju123@gmx.de") );
+ bSizer1711->Add( m_hyperlink2, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ m_bitmap10->SetToolTip( _("Email") );
+
+ bSizer1711->Add( m_bitmap10, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+
+
+ bSizer1711->Add( 0, 0, 1, wxEXPAND, 5 );
- m_panel40->SetSizer( bSizer183 );
- m_panel40->Layout();
- bSizer183->Fit( m_panel40 );
- bSizer53->Add( m_panel40, 0, wxEXPAND|wxBOTTOM, 5 );
+
+ sbSizer29->Add( bSizer1711, 1, wxALIGN_CENTER_VERTICAL, 5 );
+
+
+ bSizer53->Add( sbSizer29, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM, 5 );
wxStaticBoxSizer* sbSizer14;
sbSizer14 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Published under the GNU General Public License") ), wxHORIZONTAL );
@@ -2857,7 +2841,7 @@ AboutDlgGenerated::~AboutDlgGenerated()
}
-ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
+MessageDlgGenerated::MessageDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxSize( 300,160 ), wxDefaultSize );
this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
@@ -2871,11 +2855,11 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer26;
bSizer26 = new wxBoxSizer( wxHORIZONTAL );
- m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
- bSizer26->Add( m_bitmap10, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+ m_bitmapMsgType = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
+ bSizer26->Add( m_bitmapMsgType, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
- m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,130 ), wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER );
- bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
+ m_textCtrlMessage = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,130 ), wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER );
+ bSizer26->Add( m_textCtrlMessage, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
@@ -2889,29 +2873,27 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
wxBoxSizer* bSizer177;
bSizer177 = new wxBoxSizer( wxVERTICAL );
- m_checkBoxIgnoreErrors = new wxCheckBox( m_panel33, wxID_ANY, _("Ignore further errors"), wxDefaultPosition, wxDefaultSize, 0 );
- m_checkBoxIgnoreErrors->SetToolTip( _("Hide further error messages during the current process") );
-
- bSizer177->Add( m_checkBoxIgnoreErrors, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 5 );
+ m_checkBoxCustom = new wxCheckBox( m_panel33, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ bSizer177->Add( m_checkBoxCustom, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 5 );
wxBoxSizer* bSizer25;
bSizer25 = new wxBoxSizer( wxHORIZONTAL );
- m_buttonIgnore = new wxButton( m_panel33, wxID_OK, _("&Ignore"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonIgnore->SetDefault();
- m_buttonIgnore->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+ m_buttonCustom1 = new wxButton( m_panel33, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonCustom1->SetDefault();
+ m_buttonCustom1->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
- bSizer25->Add( m_buttonIgnore, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer25->Add( m_buttonCustom1, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
- m_buttonRetry = new wxButton( m_panel33, wxID_RETRY, _("&Retry"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonRetry->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+ m_buttonCustom2 = new wxButton( m_panel33, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonCustom2->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
- bSizer25->Add( m_buttonRetry, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer25->Add( m_buttonCustom2, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
- m_buttonAbort = new wxButton( m_panel33, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonAbort->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
+ m_buttonCancel = new wxButton( m_panel33, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
+ m_buttonCancel->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
- bSizer25->Add( m_buttonAbort, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
+ bSizer25->Add( m_buttonCancel, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
bSizer177->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
@@ -2930,193 +2912,19 @@ ErrorDlgGenerated::ErrorDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
this->Centre( wxBOTH );
// Connect Events
- this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ErrorDlgGenerated::OnClose ) );
- m_buttonIgnore->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnIgnore ), NULL, this );
- m_buttonRetry->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnRetry ), NULL, this );
- m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnAbort ), NULL, this );
-}
-
-ErrorDlgGenerated::~ErrorDlgGenerated()
-{
- // Disconnect Events
- this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( ErrorDlgGenerated::OnClose ) );
- m_buttonIgnore->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnIgnore ), NULL, this );
- m_buttonRetry->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnRetry ), NULL, this );
- m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ErrorDlgGenerated::OnAbort ), NULL, this );
-
-}
-
-WarningDlgGenerated::WarningDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
-{
- this->SetSizeHints( wxSize( 300,160 ), wxDefaultSize );
- this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- wxBoxSizer* bSizer24;
- bSizer24 = new wxBoxSizer( wxVERTICAL );
-
-
- bSizer24->Add( 0, 10, 0, wxEXPAND, 5 );
-
- wxBoxSizer* bSizer26;
- bSizer26 = new wxBoxSizer( wxHORIZONTAL );
-
- m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
- bSizer26->Add( m_bitmap10, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
-
- m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,130 ), wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER );
- bSizer26->Add( m_textCtrl8, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
-
-
- bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
-
- m_staticline7 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
- bSizer24->Add( m_staticline7, 0, wxEXPAND|wxTOP, 5 );
-
- m_panel34 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
- m_panel34->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
-
- wxBoxSizer* bSizer178;
- bSizer178 = new wxBoxSizer( wxVERTICAL );
-
- m_checkBoxDontShowAgain = new wxCheckBox( m_panel34, wxID_ANY, _("Do not show this dialog again"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer178->Add( m_checkBoxDontShowAgain, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 5 );
-
- wxBoxSizer* bSizer25;
- bSizer25 = new wxBoxSizer( wxHORIZONTAL );
-
- m_buttonIgnore = new wxButton( m_panel34, wxID_IGNORE, _("&Ignore"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonIgnore->SetDefault();
- m_buttonIgnore->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer25->Add( m_buttonIgnore, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
-
- m_buttonSwitch = new wxButton( m_panel34, wxID_MORE, _("&Switch"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonSwitch->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer25->Add( m_buttonSwitch, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
-
- m_buttonAbort = new wxButton( m_panel34, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonAbort->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer25->Add( m_buttonAbort, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
-
-
- bSizer178->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
-
-
- m_panel34->SetSizer( bSizer178 );
- m_panel34->Layout();
- bSizer178->Fit( m_panel34 );
- bSizer24->Add( m_panel34, 0, wxEXPAND, 5 );
-
-
- this->SetSizer( bSizer24 );
- this->Layout();
- bSizer24->Fit( this );
-
- this->Centre( wxBOTH );
-
- // Connect Events
- this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( WarningDlgGenerated::OnClose ) );
- m_buttonIgnore->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnIgnore ), NULL, this );
- m_buttonSwitch->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnSwitch ), NULL, this );
- m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this );
-}
-
-WarningDlgGenerated::~WarningDlgGenerated()
-{
- // Disconnect Events
- this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( WarningDlgGenerated::OnClose ) );
- m_buttonIgnore->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnIgnore ), NULL, this );
- m_buttonSwitch->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnSwitch ), NULL, this );
- m_buttonAbort->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( WarningDlgGenerated::OnAbort ), NULL, this );
-
-}
-
-QuestionDlgGenerated::QuestionDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
-{
- this->SetSizeHints( wxSize( 300,160 ), wxDefaultSize );
- this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
-
- wxBoxSizer* bSizer24;
- bSizer24 = new wxBoxSizer( wxVERTICAL );
-
-
- bSizer24->Add( 0, 10, 0, wxEXPAND, 5 );
-
- wxBoxSizer* bSizer26;
- bSizer26 = new wxBoxSizer( wxHORIZONTAL );
-
- m_bitmap10 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), 0 );
- bSizer26->Add( m_bitmap10, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
-
- m_textCtrl8 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 400,130 ), wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER );
- bSizer26->Add( m_textCtrl8, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
-
-
- bSizer24->Add( bSizer26, 1, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
-
- m_staticline8 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
- bSizer24->Add( m_staticline8, 0, wxEXPAND|wxTOP, 5 );
-
- m_panel35 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
- m_panel35->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
-
- wxBoxSizer* bSizer179;
- bSizer179 = new wxBoxSizer( wxVERTICAL );
-
- m_checkBox = new wxCheckBox( m_panel35, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer179->Add( m_checkBox, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP, 5 );
-
- wxBoxSizer* bSizer25;
- bSizer25 = new wxBoxSizer( wxHORIZONTAL );
-
- m_buttonYes = new wxButton( m_panel35, wxID_YES, _("&Yes"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonYes->SetDefault();
- m_buttonYes->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer25->Add( m_buttonYes, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
-
- m_buttonNo = new wxButton( m_panel35, wxID_NO, _("&No"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonNo->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer25->Add( m_buttonNo, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
-
- m_buttonCancel = new wxButton( m_panel35, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 );
- m_buttonCancel->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) );
-
- bSizer25->Add( m_buttonCancel, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
-
-
- bSizer179->Add( bSizer25, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
-
-
- m_panel35->SetSizer( bSizer179 );
- m_panel35->Layout();
- bSizer179->Fit( m_panel35 );
- bSizer24->Add( m_panel35, 0, wxEXPAND, 5 );
-
-
- this->SetSizer( bSizer24 );
- this->Layout();
- bSizer24->Fit( this );
-
- this->Centre( wxBOTH );
-
- // Connect Events
- this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( QuestionDlgGenerated::OnClose ) );
- m_buttonYes->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnYes ), NULL, this );
- m_buttonNo->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnNo ), NULL, this );
- m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnCancel ), NULL, this );
+ this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MessageDlgGenerated::OnClose ) );
+ m_buttonCustom1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MessageDlgGenerated::OnButton1 ), NULL, this );
+ m_buttonCustom2->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MessageDlgGenerated::OnButton2 ), NULL, this );
+ m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MessageDlgGenerated::OnCancel ), NULL, this );
}
-QuestionDlgGenerated::~QuestionDlgGenerated()
+MessageDlgGenerated::~MessageDlgGenerated()
{
// Disconnect Events
- this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( QuestionDlgGenerated::OnClose ) );
- m_buttonYes->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnYes ), NULL, this );
- m_buttonNo->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnNo ), NULL, this );
- m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( QuestionDlgGenerated::OnCancel ), NULL, this );
+ this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MessageDlgGenerated::OnClose ) );
+ m_buttonCustom1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MessageDlgGenerated::OnButton1 ), NULL, this );
+ m_buttonCustom2->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MessageDlgGenerated::OnButton2 ), NULL, this );
+ m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MessageDlgGenerated::OnCancel ), NULL, this );
}
@@ -3738,7 +3546,7 @@ SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID i
fgSizer11->Add( m_bitmapDeleteLeft, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
m_bitmapData = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- m_bitmapData->SetToolTip( _("Total amount of data that will be transferred") );
+ m_bitmapData->SetToolTip( _("Total bytes to copy") );
fgSizer11->Add( m_bitmapData, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 );
@@ -3777,7 +3585,7 @@ SyncPreviewDlgGenerated::SyncPreviewDlgGenerated( wxWindow* parent, wxWindowID i
m_staticTextData = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextData->Wrap( -1 );
- m_staticTextData->SetToolTip( _("Total amount of data that will be transferred") );
+ m_staticTextData->SetToolTip( _("Total bytes to copy") );
fgSizer11->Add( m_staticTextData, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 );
diff --git a/ui/gui_generated.h b/ui/gui_generated.h
index cb608374..fa388377 100644
--- a/ui/gui_generated.h
+++ b/ui/gui_generated.h
@@ -77,6 +77,7 @@ protected:
wxMenuItem* m_menuItemNew;
wxMenuItem* m_menuItemLoad;
wxMenuItem* m_menuItemSave;
+ wxMenuItem* m_menuItemSaveAs;
wxMenu* m_menuAdvanced;
wxMenu* m_menuLanguages;
wxMenuItem* m_menuItemGlobSett;
@@ -169,9 +170,10 @@ protected:
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
virtual void OnCompare( wxCommandEvent& event ) { event.Skip(); }
virtual void OnStartSync( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnNewConfig( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnLoadConfig( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSaveConfig( wxCommandEvent& 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 OnConfigSaveAs( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuQuit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuGlobalSettings( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuBatchJob( wxCommandEvent& event ) { event.Skip(); }
@@ -321,8 +323,8 @@ protected:
wxPanel* m_panelLogfile;
wxStaticText* m_staticText94;
zen::DirPickerCtrl* m_dirPickerLogfileDir;
- wxButton* m_buttonSave;
wxButton* m_buttonLoad;
+ wxButton* m_buttonSave;
wxButton* m_button6;
// Virtual event handlers, overide them in your derived class
@@ -335,8 +337,8 @@ protected:
virtual void OnRemoveTopFolderPair( wxCommandEvent& event ) { event.Skip(); }
virtual void OnChangeErrorHandling( wxCommandEvent& event ) { event.Skip(); }
virtual void OnChangeMaxLogCountTxt( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSaveBatchJob( wxCommandEvent& event ) { event.Skip(); }
virtual void OnLoadBatchJob( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnSaveBatchJob( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
@@ -607,7 +609,7 @@ class AboutDlgGenerated : public wxDialog
private:
protected:
- wxPanel* m_panel5;
+ wxPanel* m_panelLogo;
wxStaticBitmap* m_bitmap11;
wxStaticText* m_build;
wxPanel* m_panel33;
@@ -625,19 +627,19 @@ protected:
wxHyperlinkCtrl* m_hyperlink18;
wxHyperlinkCtrl* m_hyperlink14;
wxHyperlinkCtrl* m_hyperlink21;
- wxHyperlinkCtrl* m_hyperlink1;
- wxStaticBitmap* m_bitmap9;
- wxHyperlinkCtrl* m_hyperlink2;
- wxStaticBitmap* m_bitmap10;
- wxScrolledWindow* m_scrolledWindowTranslators;
- wxBoxSizer* bSizerTranslators;
- wxStaticText* m_staticText54;
- wxFlexGridSizer* fgSizerTranslators;
wxPanel* m_panel40;
wxPanel* m_panel39;
wxStaticText* m_staticText83;
wxHyperlinkCtrl* m_hyperlink3;
wxStaticBitmap* m_bitmapPaypal;
+ wxScrolledWindow* m_scrolledWindowTranslators;
+ wxBoxSizer* bSizerTranslators;
+ wxStaticText* m_staticText54;
+ wxFlexGridSizer* fgSizerTranslators;
+ wxHyperlinkCtrl* m_hyperlink1;
+ wxStaticBitmap* m_bitmap9;
+ wxHyperlinkCtrl* m_hyperlink2;
+ wxStaticBitmap* m_bitmap10;
wxStaticBitmap* m_bitmap13;
wxHyperlinkCtrl* m_hyperlink5;
wxButton* m_buttonOkay;
@@ -655,95 +657,33 @@ public:
};
///////////////////////////////////////////////////////////////////////////////
-/// Class ErrorDlgGenerated
+/// Class MessageDlgGenerated
///////////////////////////////////////////////////////////////////////////////
-class ErrorDlgGenerated : public wxDialog
+class MessageDlgGenerated : public wxDialog
{
private:
protected:
- wxStaticBitmap* m_bitmap10;
- wxTextCtrl* m_textCtrl8;
+ wxStaticBitmap* m_bitmapMsgType;
+ wxTextCtrl* m_textCtrlMessage;
wxStaticLine* m_staticline6;
wxPanel* m_panel33;
- wxCheckBox* m_checkBoxIgnoreErrors;
- wxButton* m_buttonIgnore;
- wxButton* m_buttonRetry;
- wxButton* m_buttonAbort;
-
- // Virtual event handlers, overide them in your derived class
- virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
- virtual void OnIgnore( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnRetry( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnAbort( wxCommandEvent& event ) { event.Skip(); }
-
-
-public:
-
- ErrorDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Error"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER );
- ~ErrorDlgGenerated();
-
-};
-
-///////////////////////////////////////////////////////////////////////////////
-/// Class WarningDlgGenerated
-///////////////////////////////////////////////////////////////////////////////
-class WarningDlgGenerated : public wxDialog
-{
-private:
-
-protected:
- wxTextCtrl* m_textCtrl8;
- wxStaticLine* m_staticline7;
- wxPanel* m_panel34;
- wxCheckBox* m_checkBoxDontShowAgain;
- wxButton* m_buttonIgnore;
- wxButton* m_buttonSwitch;
- wxButton* m_buttonAbort;
-
- // Virtual event handlers, overide them in your derived class
- virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
- virtual void OnIgnore( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnSwitch( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnAbort( wxCommandEvent& event ) { event.Skip(); }
-
-
-public:
- wxStaticBitmap* m_bitmap10;
-
- WarningDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Warning"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER );
- ~WarningDlgGenerated();
-
-};
-
-///////////////////////////////////////////////////////////////////////////////
-/// Class QuestionDlgGenerated
-///////////////////////////////////////////////////////////////////////////////
-class QuestionDlgGenerated : public wxDialog
-{
-private:
-
-protected:
- wxStaticBitmap* m_bitmap10;
- wxTextCtrl* m_textCtrl8;
- wxStaticLine* m_staticline8;
- wxPanel* m_panel35;
- wxCheckBox* m_checkBox;
- wxButton* m_buttonYes;
- wxButton* m_buttonNo;
+ wxCheckBox* m_checkBoxCustom;
+ wxButton* m_buttonCustom1;
+ wxButton* m_buttonCustom2;
wxButton* m_buttonCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
- virtual void OnYes( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnNo( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnButton1( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnButton2( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
public:
- QuestionDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Question"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER );
- ~QuestionDlgGenerated();
+ MessageDlgGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("dummy"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER );
+ ~MessageDlgGenerated();
};
diff --git a/ui/gui_status_handler.cpp b/ui/gui_status_handler.cpp
index 65e40410..57785403 100644
--- a/ui/gui_status_handler.cpp
+++ b/ui/gui_status_handler.cpp
@@ -10,6 +10,7 @@
#include "msg_popup.h"
#include "main_dlg.h"
#include "exec_finished_box.h"
+#include "../lib/generate_logfile.h"
using namespace zen;
using namespace xmlAccess;
@@ -54,7 +55,7 @@ CompareStatusHandler::~CompareStatusHandler()
mainDlg.m_buttonAbort->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CompareStatusHandler::OnAbortCompare), nullptr, this);
if (abortIsRequested())
- mainDlg.pushStatusInformation(_("Operation aborted!"));
+ mainDlg.flashStatusInformation(_("Operation aborted!"));
}
@@ -103,7 +104,7 @@ ProcessCallback::Response CompareStatusHandler::reportError(const std::wstring&
bool ignoreNextErrors = false;
switch (showErrorDlg(&mainDlg,
- ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL,
message, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
@@ -113,7 +114,7 @@ ProcessCallback::Response CompareStatusHandler::reportError(const std::wstring&
case ReturnErrorDlg::BUTTON_RETRY:
return ProcessCallback::RETRY;
- case ReturnErrorDlg::BUTTON_ABORT:
+ case ReturnErrorDlg::BUTTON_CANCEL:
abortThisProcess();
}
@@ -126,7 +127,7 @@ void CompareStatusHandler::reportFatalError(const std::wstring& errorMessage)
{
forceUiRefresh();
- showErrorDlg(&mainDlg, ReturnErrorDlg::BUTTON_ABORT, errorMessage, nullptr);
+ showFatalErrorDlg(&mainDlg, ReturnFatalErrorDlg::BUTTON_CANCEL, errorMessage, nullptr);
}
@@ -140,7 +141,7 @@ void CompareStatusHandler::reportWarning(const std::wstring& warningMessage, boo
//show pop-up and ask user how to handle warning
bool dontWarnAgain = false;
switch (showWarningDlg(&mainDlg,
- ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_ABORT,
+ ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_CANCEL,
warningMessage, dontWarnAgain))
{
case ReturnWarningDlg::BUTTON_IGNORE:
@@ -149,7 +150,7 @@ void CompareStatusHandler::reportWarning(const std::wstring& warningMessage, boo
case ReturnWarningDlg::BUTTON_SWITCH:
assert(false);
- case ReturnWarningDlg::BUTTON_ABORT:
+ case ReturnWarningDlg::BUTTON_CANCEL:
abortThisProcess();
break;
}
@@ -178,13 +179,15 @@ void CompareStatusHandler::abortThisProcess()
SyncStatusHandler::SyncStatusHandler(MainDialog* parentDlg,
OnGuiError handleError,
- const wxString& jobName,
+ const std::wstring& jobName,
const std::wstring& execWhenFinished,
std::vector<std::wstring>& execFinishedHistory) :
parentDlg_(parentDlg),
syncStatusFrame(*this, *this, parentDlg, true, jobName, execWhenFinished, execFinishedHistory),
- handleError_(handleError)
+ handleError_(handleError),
+ jobName_(jobName)
{
+ totalTime.Start(); //measure total time
}
@@ -193,19 +196,37 @@ SyncStatusHandler::~SyncStatusHandler()
const int totalErrors = errorLog.getItemCount(TYPE_ERROR | TYPE_FATAL_ERROR); //evaluate before finalizing log
//finalize error log
+ //finalize error log
+ std::wstring finalStatus;
if (abortIsRequested())
- errorLog.logMsg(_("Synchronization aborted!"), TYPE_ERROR);
+ {
+ finalStatus = _("Synchronization aborted!");
+ errorLog.logMsg(finalStatus, TYPE_ERROR);
+ }
else if (totalErrors > 0)
- errorLog.logMsg(_("Synchronization completed with errors!"), TYPE_WARNING);
+ {
+ finalStatus = _("Synchronization completed with errors!");
+ errorLog.logMsg(finalStatus, TYPE_WARNING);
+ }
else
{
if (getObjectsTotal(PHASE_SYNCHRONIZING) == 0 && //we're past "initNewPhase(PHASE_SYNCHRONIZING)" at this point!
getDataTotal (PHASE_SYNCHRONIZING) == 0)
- errorLog.logMsg(_("Nothing to synchronize!"), TYPE_INFO); //even if "ignored conflicts" occurred!
+ finalStatus = _("Nothing to synchronize!"); //even if "ignored conflicts" occurred!
else
- errorLog.logMsg(_("Synchronization completed successfully!"), TYPE_INFO);
+ finalStatus = _("Synchronization completed successfully!");
+ errorLog.logMsg(finalStatus, TYPE_INFO);
}
+ const Utf8String logStream = generateLogStream(errorLog, jobName_, finalStatus,
+ getObjectsCurrent(PHASE_SYNCHRONIZING), getDataCurrent(PHASE_SYNCHRONIZING),
+ getObjectsTotal (PHASE_SYNCHRONIZING), getDataTotal (PHASE_SYNCHRONIZING), totalTime.Time() / 1000);
+ try
+ {
+ saveToLastSyncsLog(logStream); //throw FileError
+ }
+ catch (FileError&) {}
+
bool showFinalResults = true;
//execute "on completion" command (even in case of ignored errors)
@@ -272,7 +293,7 @@ ProcessCallback::Response SyncStatusHandler::reportError(const std::wstring& err
bool ignoreNextErrors = false;
switch (showErrorDlg(parentDlg_,
- ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL,
errorMessage,
&ignoreNextErrors))
{
@@ -285,7 +306,7 @@ ProcessCallback::Response SyncStatusHandler::reportError(const std::wstring& err
case ReturnErrorDlg::BUTTON_RETRY:
return ProcessCallback::RETRY;
- case ReturnErrorDlg::BUTTON_ABORT:
+ case ReturnErrorDlg::BUTTON_CANCEL:
errorLog.logMsg(errorMessage, TYPE_ERROR);
abortThisProcess();
break;
@@ -308,21 +329,18 @@ void SyncStatusHandler::reportFatalError(const std::wstring& errorMessage)
forceUiRefresh();
bool ignoreNextErrors = false;
- switch (showErrorDlg(parentDlg_,
- ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_ABORT,
- errorMessage, &ignoreNextErrors))
+ switch (showFatalErrorDlg(parentDlg_,
+ ReturnFatalErrorDlg::BUTTON_IGNORE | ReturnFatalErrorDlg::BUTTON_CANCEL,
+ errorMessage, &ignoreNextErrors))
{
- case ReturnErrorDlg::BUTTON_IGNORE:
+ case ReturnFatalErrorDlg::BUTTON_IGNORE:
if (ignoreNextErrors) //falsify only
handleError_ = ON_GUIERROR_IGNORE;
break;
- case ReturnErrorDlg::BUTTON_ABORT:
+ case ReturnFatalErrorDlg::BUTTON_CANCEL:
abortThisProcess();
break;
-
- case ReturnErrorDlg::BUTTON_RETRY:
- assert(false);
}
}
break;
@@ -349,7 +367,7 @@ void SyncStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
bool dontWarnAgain = false;
switch (showWarningDlg(parentDlg_,
- ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_ABORT,
+ ReturnWarningDlg::BUTTON_IGNORE | ReturnWarningDlg::BUTTON_CANCEL,
warningMessage, dontWarnAgain))
{
case ReturnWarningDlg::BUTTON_IGNORE: //no unhandled error situation!
@@ -358,7 +376,7 @@ void SyncStatusHandler::reportWarning(const std::wstring& warningMessage, bool&
case ReturnWarningDlg::BUTTON_SWITCH:
assert(false);
- case ReturnWarningDlg::BUTTON_ABORT:
+ case ReturnWarningDlg::BUTTON_CANCEL:
abortThisProcess();
break;
}
diff --git a/ui/gui_status_handler.h b/ui/gui_status_handler.h
index ebc59473..0bda9923 100644
--- a/ui/gui_status_handler.h
+++ b/ui/gui_status_handler.h
@@ -9,6 +9,7 @@
#include <wx/event.h>
#include <zen/error_log.h>
+#include <wx/stopwatch.h>
#include "progress_indicator.h"
#include "../lib/status_handler.h"
#include "../lib/process_xml.h"
@@ -49,7 +50,7 @@ class SyncStatusHandler : public zen::StatusHandler
public:
SyncStatusHandler(MainDialog* parentDlg,
xmlAccess::OnGuiError handleError,
- const wxString& jobName,
+ const std::wstring& jobName,
const std::wstring& execWhenFinished,
std::vector<std::wstring>& execFinishedHistory);
~SyncStatusHandler();
@@ -70,6 +71,8 @@ private:
SyncStatus syncStatusFrame; //the window managed by SyncStatus has longer lifetime than this handler!
xmlAccess::OnGuiError handleError_;
zen::ErrorLog errorLog;
+ const std::wstring jobName_;
+ wxStopWatch totalTime;
};
diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp
index 1ea2f29f..03a94e33 100644
--- a/ui/main_dlg.cpp
+++ b/ui/main_dlg.cpp
@@ -9,7 +9,6 @@
#include <stdexcept>
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
-#include <wx/ffile.h>
#include <wx/imaglist.h>
#include <wx/wupdlock.h>
#include <wx/msgdlg.h>
@@ -29,7 +28,6 @@
#include "check_version.h"
#include "gui_status_handler.h"
#include "sync_cfg.h"
-#include <wx+/string_conv.h>
#include "small_dlgs.h"
#include <wx+/mouse_move_dlg.h>
#include "progress_indicator.h"
@@ -45,6 +43,7 @@
#include <wx+/toggle_button.h>
#include "folder_pair.h"
#include <wx+/rtl.h>
+#include <wx+/serialize.h>
#include "search.h"
#include "../lib/help_provider.h"
#include "batch_config.h"
@@ -514,7 +513,7 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig& guiCfg,
wxAuiPaneInfo().Name(wxT("Panel6")).Layer(4).Bottom().Row(1).Position(2).Caption(_("Select view")).MinSize(m_bpButtonSyncDirNone->GetSize().GetWidth(), m_panelViewFilter->GetSize().GetHeight()));
auiMgr.AddPane(m_panelStatistics,
- wxAuiPaneInfo().Name(wxT("Panel7")).Layer(4).Bottom().Row(1).Position(3).Caption(_("Statistics")).MinSize(bSizerData->GetSize().GetWidth() / 2, m_panelStatistics->GetSize().GetHeight()));
+ wxAuiPaneInfo().Name(wxT("Panel7")).Layer(4).Bottom().Row(1).Position(3).Caption(_("Statistics")).MinSize(m_bitmapData->GetSize().GetWidth() + m_staticTextData->GetSize().GetWidth(), m_panelStatistics->GetSize().GetHeight()));
auiMgr.Update();
@@ -601,11 +600,22 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig& guiCfg,
//menu icons: workaround for wxWidgets: small hack to update menu items: actually this is a wxWidgets bug (affects Windows- and Linux-build)
MenuItemUpdater updateMenuFile(*m_menuFile);
- updateMenuFile.markForUpdate(m_menuItem10, GlobalResources::getImage(wxT("compareSmall")));
- updateMenuFile.markForUpdate(m_menuItem11, GlobalResources::getImage(wxT("syncSmall")));
- //updateMenuFile.markForUpdate(m_menuItemNew, GlobalResources::getImage(wxT("newSmall")));
- updateMenuFile.markForUpdate(m_menuItemSave, GlobalResources::getImage(wxT("saveSmall")));
- updateMenuFile.markForUpdate(m_menuItemLoad, GlobalResources::getImage(wxT("loadSmall")));
+
+ const int dummySize = 5;
+ wxImage dummyImg(dummySize, dummySize);
+ if (!dummyImg.HasAlpha())
+ dummyImg.InitAlpha();
+ std::fill(dummyImg.GetAlpha(), dummyImg.GetAlpha() + dummySize * dummySize, wxIMAGE_ALPHA_TRANSPARENT);
+
+ updateMenuFile.markForUpdate(m_menuItem10, GlobalResources::getImage(L"compareSmall"));
+ updateMenuFile.markForUpdate(m_menuItem11, GlobalResources::getImage(L"syncSmall"));
+
+ updateMenuFile.markForUpdate(m_menuItemNew, dummyImg); //it's ridiculous, but wxWidgets screws up aligning short-cut label texts if we don't set an image!
+ //updateMenuFile.markForUpdate(m_menuItemSave, dummyImg); //
+ updateMenuFile.markForUpdate(m_menuItemSave, GlobalResources::getImage(L"saveSmall"));
+
+ //updateMenuFile.markForUpdate(m_menuItemSaveAs, GlobalResources::getImage(L"saveSmall"));
+ updateMenuFile.markForUpdate(m_menuItemLoad, GlobalResources::getImage(L"loadSmall"));
MenuItemUpdater updateMenuAdv(*m_menuAdvanced);
updateMenuAdv.markForUpdate(m_menuItemGlobSett, GlobalResources::getImage(L"settingsSmall"));
@@ -613,7 +623,7 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig& guiCfg,
MenuItemUpdater updateMenuHelp(*m_menuHelp);
updateMenuHelp.markForUpdate(m_menuItemManual, GlobalResources::getImage(L"helpSmall"));
- updateMenuHelp.markForUpdate(m_menuItemAbout, GlobalResources::getImage(L"aboutSmall"));
+ updateMenuHelp.markForUpdate(m_menuItemAbout, GlobalResources::getImage(L"aboutSmall"));
#ifdef FFS_LINUX
m_menuItemCheckVer->Enable(zen::isPortableVersion()); //disable update check for Linux installer-based version -> handled by .deb
@@ -856,29 +866,6 @@ void MainDialog::setManualFilter(const std::vector<FileSystemObject*>& selection
}
-void MainDialog::OnIdleEvent(wxEvent& event)
-{
- //small routine to restore status information after some time
- if (!stackObjects.empty()) //check if there is some work to do
- {
- wxMilliClock_t currentTime = wxGetLocalTimeMillis();
- if (currentTime - lastStatusChange > 2500) //restore stackObject after two seconds
- {
- lastStatusChange = currentTime;
-
- m_staticTextStatusMiddle->SetLabel(stackObjects.top());
- stackObjects.pop();
-
- if (stackObjects.empty())
- m_staticTextStatusMiddle->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //reset color
-
- m_panelStatusBar->Layout();
- }
- }
-
- event.Skip();
-}
-
namespace
{
//fast replacement for wxString modelling exponential growth
@@ -995,7 +982,6 @@ public:
deletionCount(0)
{
mainDlg->disableAllElements(true); //disable everything except abort button
- mainDlg->clearStatusBar();
//register abort button
mainDlg->m_buttonAbort->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ManualDeletionHandler::OnAbortDeletion), nullptr, this );
@@ -1021,7 +1007,7 @@ public:
bool ignoreNextErrors = false;
switch (showErrorDlg(mainDlg,
- ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_ABORT,
+ ReturnErrorDlg::BUTTON_IGNORE | ReturnErrorDlg::BUTTON_RETRY | ReturnErrorDlg::BUTTON_CANCEL,
errorMessage, &ignoreNextErrors))
{
case ReturnErrorDlg::BUTTON_IGNORE:
@@ -1029,7 +1015,7 @@ public:
return DeleteFilesHandler::IGNORE_ERROR;
case ReturnErrorDlg::BUTTON_RETRY:
return DeleteFilesHandler::RETRY;
- case ReturnErrorDlg::BUTTON_ABORT:
+ case ReturnErrorDlg::BUTTON_CANCEL:
throw AbortDeleteProcess();
}
@@ -1043,14 +1029,8 @@ public:
if (updateUiIsAllowed()) //test if specific time span between ui updates is over
{
- wxString statusMessage = replaceCpy(_P("Object deleted successfully!", "%x objects deleted successfully!", deletionCount),
- L"%x", zen::toGuiString(deletionCount), false);
-
- if (mainDlg->m_staticTextStatusMiddle->GetLabel() != statusMessage)
- {
- mainDlg->m_staticTextStatusMiddle->SetLabel(statusMessage);
- mainDlg->m_panelStatusBar->Layout();
- }
+ mainDlg->setStatusInformation(replaceCpy(_P("Object deleted successfully!", "%x objects deleted successfully!", deletionCount),
+ L"%x", zen::toGuiString(deletionCount), false));
updateUiNow();
}
@@ -1227,29 +1207,58 @@ void MainDialog::openExternalApplication(const wxString& commandline, const zen:
}
-void MainDialog::pushStatusInformation(const wxString& text)
+void MainDialog::setStatusInformation(const wxString& msg)
{
- lastStatusChange = wxGetLocalTimeMillis();
- stackObjects.push(m_staticTextStatusMiddle->GetLabel());
- m_staticTextStatusMiddle->SetLabel(text);
- m_staticTextStatusMiddle->SetForegroundColour(wxColour(31, 57, 226)); //highlight color: blue
- m_panelStatusBar->Layout();
+ if (statusMsgStack.empty())
+ {
+ if (m_staticTextStatusMiddle->GetLabel() != msg)
+ {
+ m_staticTextStatusMiddle->SetLabel(msg);
+ m_panelStatusBar->Layout();
+ }
+ }
+ else
+ statusMsgStack[0] = msg; //statusMsgStack, index 0 is main status, while 1, 2, ... are temporary status texts in reverse order of screen appearance
+}
+
+
+void MainDialog::flashStatusInformation(const wxString& text)
+{
+ if (statusMsgStack.empty())
+ {
+ statusMsgStack.push_back(m_staticTextStatusMiddle->GetLabel());
+
+ lastStatusChange = wxGetLocalTimeMillis();
+ m_staticTextStatusMiddle->SetLabel(text);
+ m_staticTextStatusMiddle->SetForegroundColour(wxColour(31, 57, 226)); //highlight color: blue
+ m_panelStatusBar->Layout();
+ }
+ else
+ statusMsgStack.insert(statusMsgStack.begin() + 1, text);
}
-void MainDialog::clearStatusBar()
+void MainDialog::OnIdleEvent(wxEvent& event)
{
- while (!stackObjects.empty())
- stackObjects.pop();
+ //small routine to restore status information after some time
+ if (!statusMsgStack.empty()) //check if there is some work to do
+ {
+ wxMilliClock_t currentTime = wxGetLocalTimeMillis();
+ if (currentTime - lastStatusChange > 2500) //restore stackObject after two seconds
+ {
+ lastStatusChange = currentTime;
- m_staticTextStatusMiddle->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //reset color
- bSizerStatusLeftDirectories->Show(false);
- bSizerStatusLeftFiles ->Show(false);
+ m_staticTextStatusMiddle->SetLabel(statusMsgStack.back());
+ statusMsgStack.pop_back();
- m_staticTextStatusMiddle->SetLabel(wxEmptyString);
+ if (statusMsgStack.empty())
+ m_staticTextStatusMiddle->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //reset color
+
+ m_panelStatusBar->Layout();
+ }
+ }
- bSizerStatusRightDirectories->Show(false);
- bSizerStatusRightFiles ->Show(false);
+ event.Skip();
}
@@ -1267,7 +1276,7 @@ void MainDialog::disableAllElements(bool enableAbort)
m_bpButtonSyncConfig ->Disable();
m_buttonStartSync ->Disable();
m_gridMain ->Disable();
- m_panelCenter ->Disable();
+ m_gridMain ->Disable();
m_panelStatistics ->Disable();
m_gridNavi ->Disable();
m_panelDirectoryPairs->Disable();
@@ -1303,7 +1312,7 @@ void MainDialog::enableAllElements()
m_bpButtonSyncConfig ->Enable();
m_buttonStartSync ->Enable();
m_gridMain ->Enable();
- m_panelCenter ->Enable();
+ m_gridMain ->Enable();
m_panelStatistics ->Enable();
m_gridNavi ->Enable();
m_panelDirectoryPairs->Enable();
@@ -1326,21 +1335,11 @@ namespace
{
void updateSizerOrientation(wxBoxSizer& sizer, wxWindow& window)
{
- if (window.GetSize().GetWidth() > window.GetSize().GetHeight()) //check window NOT sizer width!
+ const int newOrientation = window.GetSize().GetWidth() > window.GetSize().GetHeight() ? wxHORIZONTAL : wxVERTICAL; //check window NOT sizer width!
+ if (sizer.GetOrientation() != newOrientation)
{
- if (sizer.GetOrientation() != wxHORIZONTAL)
- {
- sizer.SetOrientation(wxHORIZONTAL);
- window.Layout();
- }
- }
- else
- {
- if (sizer.GetOrientation() != wxVERTICAL)
- {
- sizer.SetOrientation(wxVERTICAL);
- window.Layout();
- }
+ sizer.SetOrientation(newOrientation);
+ window.Layout();
}
}
}
@@ -1360,7 +1359,27 @@ void MainDialog::OnResizeViewPanel(wxEvent& event)
void MainDialog::OnResizeStatisticsPanel(wxEvent& event)
{
- updateSizerOrientation(*bSizerStatistics, *m_panelStatistics);
+ //updateSizerOrientation(*bSizerStatistics, *m_panelStatistics);
+
+ //we need something more fancy:
+ const int parentOrient = m_panelStatistics->GetSize().GetWidth() > m_panelStatistics->GetSize().GetHeight() ? wxHORIZONTAL : wxVERTICAL; //check window NOT sizer width!
+ if (bSizerStatistics->GetOrientation() != parentOrient)
+ {
+ bSizerStatistics->SetOrientation(parentOrient);
+
+ //apply opposite orientation for child sizers
+ const int childOrient = parentOrient == wxHORIZONTAL ? wxVERTICAL : wxHORIZONTAL;
+ wxSizerItemList& sl = bSizerStatistics->GetChildren();
+ for (auto iter = sl.begin(); iter != sl.end(); ++iter) //yet another wxWidgets bug keeps us from using std::for_each
+ {
+ wxSizerItem& szItem = **iter;
+ if (auto sizerChild = dynamic_cast<wxBoxSizer*>(szItem.GetSizer()))
+ if (sizerChild->GetOrientation() != childOrient)
+ sizerChild->SetOrientation(childOrient);
+ }
+ m_panelStatistics->Layout();
+ }
+
event.Skip();
}
@@ -2202,7 +2221,29 @@ void MainDialog::addFileToCfgHistory(const std::vector<wxString>& filenames)
}
-void MainDialog::OnSaveConfig(wxCommandEvent& event)
+void MainDialog::OnConfigSave(wxCommandEvent& event)
+{
+ //if we work on a single named configuration document: save directly if changed
+ //else: always show file dialog
+ if (activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName())
+ {
+ const wxString filename = activeConfigFiles[0];
+
+ //don't overwrite .ffs_batch!
+ using namespace xmlAccess;
+ if (getXmlType(utfCvrtTo<Zstring>(filename)) == XML_TYPE_GUI) //throw()
+ {
+ if (lastConfigurationSaved != getConfig())
+ trySaveConfig(&filename);
+ return;
+ }
+ }
+
+ trySaveConfig(nullptr);
+}
+
+
+void MainDialog::OnConfigSaveAs(wxCommandEvent& event)
{
trySaveConfig(nullptr);
}
@@ -2239,7 +2280,7 @@ bool MainDialog::trySaveConfig(const wxString* fileName) //return true if saved
xmlAccess::writeConfig(guiCfg, toZ(targetFilename)); //write config to XML
setLastUsedConfig(targetFilename, guiCfg);
- pushStatusInformation(_("Configuration saved!"));
+ flashStatusInformation(_("Configuration saved!"));
return true;
}
catch (const xmlAccess::FfsXmlError& e)
@@ -2250,7 +2291,51 @@ bool MainDialog::trySaveConfig(const wxString* fileName) //return true if saved
}
-void MainDialog::OnLoadConfig(wxCommandEvent& event)
+bool MainDialog::saveOldConfig() //return false on user abort
+{
+ if (lastConfigurationSaved != getConfig())
+ {
+ //notify user about changed settings
+ if (globalSettings->optDialogs.popupOnConfigChange)
+ if (activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName())
+ //only if check is active and non-default config file loaded
+ {
+ const wxString filename = activeConfigFiles[0];
+
+ bool neverSave = !globalSettings->optDialogs.popupOnConfigChange;
+ CheckBox cb(_("Never save changes"), neverSave);
+
+ switch (showQuestionDlg(this,
+ ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO | ReturnQuestionDlg::BUTTON_CANCEL,
+ replaceCpy(_("Do you want to save changes to %x?"), L"%x", fmtFileName(afterLast(utfCvrtTo<Zstring>(filename), FILE_NAME_SEPARATOR))),
+ filename, //caption
+ _("Save"), _("Don't Save"),
+ &cb))
+ {
+ case ReturnQuestionDlg::BUTTON_YES:
+
+ using namespace xmlAccess;
+ return trySaveConfig(getXmlType(utfCvrtTo<Zstring>(filename)) == XML_TYPE_GUI ? //don't overwrite .ffs_batch!
+ &filename :
+ nullptr);
+
+ case ReturnQuestionDlg::BUTTON_NO:
+ globalSettings->optDialogs.popupOnConfigChange = !neverSave;
+ break;
+
+ case ReturnQuestionDlg::BUTTON_CANCEL:
+ return false;
+ }
+ }
+
+ //discard current config selection, this ensures next app start will load <last session> instead of the original non-modified config selection
+ setLastUsedConfig(std::vector<wxString>(), getConfig());
+ }
+ return true;
+}
+
+
+void MainDialog::OnConfigLoad(wxCommandEvent& event)
{
wxFileDialog filePicker(this,
wxEmptyString,
@@ -2270,7 +2355,7 @@ void MainDialog::OnLoadConfig(wxCommandEvent& event)
}
-void MainDialog::OnNewConfig(wxCommandEvent& event)
+void MainDialog::OnConfigNew(wxCommandEvent& event)
{
if (!saveOldConfig()) //notify user about changed settings
return;
@@ -2305,45 +2390,6 @@ void MainDialog::OnLoadFromHistory(wxCommandEvent& event)
}
-bool MainDialog::saveOldConfig() //return false on user abort
-{
- if (lastConfigurationSaved != getConfig())
- {
- //notify user about changed settings
- if (!globalSettings->optDialogs.popupOnConfigChange)
- //discard current config selection, this ensures next app start will load <last session> instead of the original non-modified config selection
- setLastUsedConfig(std::vector<wxString>(), getConfig());
- else if (activeConfigFiles.size() == 1 && activeConfigFiles[0] != lastRunConfigName() /*|| activeConfigFiles.size() > 1*/)
- //only if check is active and non-default config file loaded
- {
- const wxString filename = activeConfigFiles[0];
-
- bool neverSave = !globalSettings->optDialogs.popupOnConfigChange;
- CheckBox cb(_("Never save changes"), neverSave);
-
- switch (showQuestionDlg(this,
- ReturnQuestionDlg::BUTTON_YES | ReturnQuestionDlg::BUTTON_NO | ReturnQuestionDlg::BUTTON_CANCEL,
- _("Save changes to current configuration?"), &cb))
- {
- case ReturnQuestionDlg::BUTTON_YES:
- return trySaveConfig(endsWith(filename, L".ffs_gui") ? &filename : nullptr); //don't overwrite .ffs_batch!
-
- case ReturnQuestionDlg::BUTTON_NO:
- globalSettings->optDialogs.popupOnConfigChange = !neverSave;
- //by choosing "no" user actively discards current config selection
- //this ensures next app start will load <last session> instead of the original non-modified config selection
- setLastUsedConfig(std::vector<wxString>(), getConfig());
- break;
-
- case ReturnQuestionDlg::BUTTON_CANCEL:
- return false;
- }
- }
- }
- return true;
-}
-
-
void MainDialog::loadConfiguration(const wxString& filename)
{
std::vector<wxString> filenames;
@@ -2369,7 +2415,7 @@ void MainDialog::loadConfiguration(const std::vector<wxString>& filenames)
xmlAccess::convertConfig(toZ(filenames), newGuiCfg); //throw FfsXmlError
setLastUsedConfig(filenames, newGuiCfg);
- pushStatusInformation(_("Configuration loaded!"));
+ //flashStatusInformation(_("Configuration loaded!")); -> irrelvant!?
}
catch (const xmlAccess::FfsXmlError& error)
{
@@ -2434,7 +2480,7 @@ void MainDialog::OnClose(wxCloseEvent& event)
const bool cancelled = !saveOldConfig(); //notify user about changed settings
if (cancelled)
{
- //attention: this Veto() would NOT cancel system shutdown since saveOldConfig() shows modal dialog
+ //attention: this Veto() will NOT cancel system shutdown since saveOldConfig() blocks on modal dialog
event.Veto();
return;
@@ -2892,7 +2938,6 @@ void MainDialog::updateFilterButtons()
void MainDialog::OnCompare(wxCommandEvent& event)
{
//PERF_START;
- clearStatusBar();
wxBusyCursor dummy; //show hourglass cursor
@@ -2961,7 +3006,7 @@ void MainDialog::OnCompare(wxCommandEvent& event)
//prepare status information
if (allElementsEqual(folderCmp))
- pushStatusInformation(_("All directories in sync!"));
+ flashStatusInformation(_("All directories in sync!"));
}
@@ -3097,8 +3142,6 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
if (folderCmp.empty()) //check if user aborted or error occured, ect...
return;
- //pushStatusInformation(_("Please run a Compare first before synchronizing!"));
- //return;
}
//show sync preview screen
@@ -3117,7 +3160,6 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
wxBusyCursor dummy; //show hourglass cursor
- clearStatusBar();
try
{
//PERF_START;
@@ -3421,8 +3463,6 @@ void MainDialog::updateGridViewData()
//status bar
wxWindowUpdateLocker dummy(m_panelStatusBar); //avoid display distortion
- clearStatusBar();
-
//#################################################
//update status information
bSizerStatusLeftDirectories->Show(foldersOnLeftView > 0);
@@ -3440,7 +3480,7 @@ void MainDialog::updateGridViewData()
replace(statusMiddleNew, L"%x", toGuiString(gridDataView->rowsOnView()), false);
replace(statusMiddleNew, L"%y", toGuiString(gridDataView->rowsTotal ()), false);
}
- setText(*m_staticTextStatusMiddle, statusMiddleNew);
+ setStatusInformation(statusMiddleNew);
}
bSizerStatusRightDirectories->Show(foldersOnRightView > 0);
@@ -3734,46 +3774,46 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
if (filePicker.ShowModal() != wxID_OK)
return;
- const wxString newFileName = filePicker.GetPath();
+ const Zstring filename = utfCvrtTo<Zstring>(filePicker.GetPath());
- typedef Zbase<char> UtfString; //perf: wxString doesn't model exponential growth and so is out, std::string doesn't give performance guarantee!
- UtfString exportString;
+ Utf8String buffer; //perf: wxString doesn't model exponential growth and so is out, std::string doesn't give performance guarantee!
+ buffer += BYTE_ORDER_MARK_UTF8;
//write legend
- exportString += utfCvrtTo<UtfString>(_("Legend")) + '\n';
+ buffer += utfCvrtTo<Utf8String>(_("Legend")) + '\n';
if (showSyncAction_)
{
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_EQUAL)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_EQUAL)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_CREATE_NEW_LEFT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_CREATE_NEW_LEFT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_CREATE_NEW_RIGHT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_CREATE_NEW_RIGHT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_OVERWRITE_LEFT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_OVERWRITE_LEFT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_OVERWRITE_RIGHT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_OVERWRITE_RIGHT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_DELETE_LEFT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_DELETE_LEFT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_DELETE_RIGHT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_DELETE_RIGHT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_DO_NOTHING)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_DO_NOTHING)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getSyncOpDescription(SO_UNRESOLVED_CONFLICT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(SO_UNRESOLVED_CONFLICT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_EQUAL)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_EQUAL)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_CREATE_NEW_LEFT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_CREATE_NEW_LEFT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_CREATE_NEW_RIGHT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_CREATE_NEW_RIGHT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_OVERWRITE_LEFT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_OVERWRITE_LEFT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_OVERWRITE_RIGHT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_OVERWRITE_RIGHT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_DELETE_LEFT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_DELETE_LEFT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_DELETE_RIGHT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_DELETE_RIGHT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_DO_NOTHING)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_DO_NOTHING)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getSyncOpDescription(SO_UNRESOLVED_CONFLICT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(SO_UNRESOLVED_CONFLICT)) + '\n';
}
else
{
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_EQUAL)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_EQUAL)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_DIFFERENT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_DIFFERENT)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_LEFT_SIDE_ONLY)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_LEFT_SIDE_ONLY)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_RIGHT_SIDE_ONLY)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_RIGHT_SIDE_ONLY)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_LEFT_NEWER)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_LEFT_NEWER)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_RIGHT_NEWER)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_RIGHT_NEWER)) + '\n';
- exportString += "\"" + utfCvrtTo<UtfString>(getCategoryDescription(FILE_CONFLICT)) + "\";" + utfCvrtTo<UtfString>(getSymbol(FILE_CONFLICT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_EQUAL)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_EQUAL)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_DIFFERENT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_DIFFERENT)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_LEFT_SIDE_ONLY)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_LEFT_SIDE_ONLY)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_RIGHT_SIDE_ONLY)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_RIGHT_SIDE_ONLY)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_LEFT_NEWER)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_LEFT_NEWER)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_RIGHT_NEWER)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_RIGHT_NEWER)) + '\n';
+ buffer += "\"" + utfCvrtTo<Utf8String>(getCategoryDescription(FILE_CONFLICT)) + "\";" + utfCvrtTo<Utf8String>(getSymbol(FILE_CONFLICT)) + '\n';
}
- exportString += '\n';
+ buffer += '\n';
//base folders
- exportString += utfCvrtTo<UtfString>(_("Folder pairs")) + '\n' ;
+ buffer += utfCvrtTo<Utf8String>(_("Folder pairs")) + '\n' ;
std::for_each(begin(folderCmp), end(folderCmp),
[&](BaseDirMapping& baseMap)
{
- exportString += utfCvrtTo<UtfString>(baseMap.getBaseDirPf<LEFT_SIDE >()) + ';';
- exportString += utfCvrtTo<UtfString>(baseMap.getBaseDirPf<RIGHT_SIDE>()) + '\n';
+ buffer += utfCvrtTo<Utf8String>(baseMap.getBaseDirPf<LEFT_SIDE >()) + ';';
+ buffer += utfCvrtTo<Utf8String>(baseMap.getBaseDirPf<RIGHT_SIDE>()) + '\n';
});
- exportString += '\n';
+ buffer += '\n';
//write header
auto provLeft = m_gridMain->getDataProvider(gridview::COMP_LEFT);
@@ -3791,9 +3831,9 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
auto addCellValue = [&](const wxString& val)
{
if (val.find(L';') != wxString::npos)
- exportString += '\"' + utfCvrtTo<UtfString>(val) + '\"';
+ buffer += '\"' + utfCvrtTo<Utf8String>(val) + '\"';
else
- exportString += utfCvrtTo<UtfString>(val);
+ buffer += utfCvrtTo<Utf8String>(val);
};
if (provLeft && provMiddle && provRight)
@@ -3802,13 +3842,13 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
[&](const Grid::ColumnAttribute& ca)
{
addCellValue(provLeft->getColumnLabel(ca.type_));
- exportString += ';';
+ buffer += ';';
});
std::for_each(colAttrMiddle.begin(), colAttrMiddle.end(),
[&](const Grid::ColumnAttribute& ca)
{
addCellValue(provMiddle->getColumnLabel(ca.type_));
- exportString += ';';
+ buffer += ';';
});
if (!colAttrRight.empty())
{
@@ -3816,11 +3856,11 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
[&](const Grid::ColumnAttribute& ca)
{
addCellValue(provRight->getColumnLabel(ca.type_));
- exportString += ';';
+ buffer += ';';
});
addCellValue(provRight->getColumnLabel(colAttrRight.back().type_));
}
- exportString += '\n';
+ buffer += '\n';
//main grid
const size_t rowCount = m_gridMain->getRowCount();
@@ -3830,13 +3870,13 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
[&](const Grid::ColumnAttribute& ca)
{
addCellValue(provLeft->getValue(row, ca.type_));
- exportString += ';';
+ buffer += ';';
});
std::for_each(colAttrMiddle.begin(), colAttrMiddle.end(),
[&](const Grid::ColumnAttribute& ca)
{
addCellValue(provMiddle->getValue(row, ca.type_));
- exportString += ';';
+ buffer += ';';
});
if (!colAttrRight.empty())
{
@@ -3844,23 +3884,26 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
[&](const Grid::ColumnAttribute& ca)
{
addCellValue(provRight->getValue(row, ca.type_));
- exportString += ';';
+ buffer += ';';
});
addCellValue(provRight->getValue(row, colAttrRight.back().type_));
}
- exportString += '\n';
+ buffer += '\n';
}
- //write export file
- wxFFile output(newFileName.c_str(), L"w"); //don't write in binary mode
- if (output.IsOpened())
+ //write file
+ try
+ {
+ replace(buffer, '\n', LINE_BREAK);
+
+ saveBinStream(filename, buffer); //throw FileError
+
+ flashStatusInformation(_("File list exported!"));
+ }
+ catch (const FileError& e)
{
- output.Write(BYTE_ORDER_MARK_UTF8, sizeof(BYTE_ORDER_MARK_UTF8) - 1);
- output.Write(exportString.c_str(), exportString.size());
- pushStatusInformation(_("File list exported!"));
+ wxMessageBox(e.toString(), _("Error"), wxOK | wxICON_ERROR, this);
}
- else
- wxMessageBox(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(toZ(newFileName))), _("Error"), wxOK | wxICON_ERROR, this);
}
}
diff --git a/ui/main_dlg.h b/ui/main_dlg.h
index b9f3fe0d..0e9a7830 100644
--- a/ui/main_dlg.h
+++ b/ui/main_dlg.h
@@ -112,8 +112,8 @@ private:
void OnIdleEvent(wxEvent& event);
//delayed status information restore
- void pushStatusInformation(const wxString& text);
- void clearStatusBar();
+ void setStatusInformation(const wxString& msg); //set main status
+ void flashStatusInformation(const wxString& msg); //temporarily show different status
//events
void onGridButtonEvent (wxKeyEvent& event);
@@ -159,9 +159,10 @@ private:
void OnSyncDirRight( wxCommandEvent& event);
void OnSyncDirNone( wxCommandEvent& event);
- void OnNewConfig( wxCommandEvent& event);
- void OnSaveConfig( wxCommandEvent& event);
- void OnLoadConfig( wxCommandEvent& event);
+ void OnConfigNew( wxCommandEvent& event);
+ void OnConfigSave( wxCommandEvent& event);
+ void OnConfigSaveAs( wxCommandEvent& event);
+ void OnConfigLoad( wxCommandEvent& event);
void OnLoadFromHistory( wxCommandEvent& event);
void OnCfgHistoryKeyEvent( wxKeyEvent& event);
@@ -242,7 +243,7 @@ private:
//***********************************************
//status information
wxLongLong lastStatusChange;
- std::stack<wxString> stackObjects;
+ std::vector<wxString> statusMsgStack;
//compare status panel (hidden on start, shown when comparing)
std::unique_ptr<CompareStatus> compareStatus; //always bound
diff --git a/ui/msg_popup.cpp b/ui/msg_popup.cpp
index 142d2e9e..09bf24c9 100644
--- a/ui/msg_popup.cpp
+++ b/ui/msg_popup.cpp
@@ -9,179 +9,191 @@
#include <wx+/mouse_move_dlg.h>
#include "gui_generated.h"
-
using namespace zen;
-class ErrorDlg : public ErrorDlgGenerated
+class ErrorDlg : public MessageDlgGenerated
{
public:
ErrorDlg(wxWindow* parent,
int activeButtons,
const wxString& messageText,
+ const wxString& caption, //optional
bool* ignoreNextErrors);
private:
- void OnClose(wxCloseEvent& event);
- void OnIgnore(wxCommandEvent& event);
- void OnRetry(wxCommandEvent& event);
- void OnAbort(wxCommandEvent& event);
+ void OnClose (wxCloseEvent& event) { EndModal(ReturnErrorDlg::BUTTON_CANCEL); }
+ void OnCancel(wxCommandEvent& event) { EndModal(ReturnErrorDlg::BUTTON_CANCEL); }
+ void OnButton1(wxCommandEvent& event);
+ void OnButton2(wxCommandEvent& event);
bool* ignoreErrors;
+ wxButton& buttonIgnore; //
+ wxButton& buttonRetry; // map generic controls
+ wxCheckBox& checkBoxIgnoreErrors; //
};
-ErrorDlg::ErrorDlg(wxWindow* parent, const int activeButtons, const wxString& messageText, bool* ignoreNextErrors) :
- ErrorDlgGenerated(parent),
- ignoreErrors(ignoreNextErrors)
+ErrorDlg::ErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, const wxString& caption, bool* ignoreNextErrors) :
+ MessageDlgGenerated(parent),
+ ignoreErrors(ignoreNextErrors),
+ buttonIgnore(*m_buttonCustom1),
+ buttonRetry (*m_buttonCustom2),
+ checkBoxIgnoreErrors(*m_checkBoxCustom)
{
#ifdef FFS_WIN
new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
#endif
- m_bitmap10->SetBitmap(GlobalResources::getImage(L"error"));
- m_textCtrl8->SetValue(messageText);
+ SetTitle(!caption.empty() ? caption : _("Error"));
+ m_bitmapMsgType->SetBitmap(GlobalResources::getImage(L"error"));
+ m_textCtrlMessage->SetValue(messageText);
+ checkBoxIgnoreErrors.SetLabel(_("Ignore further errors"));
+ buttonIgnore.SetLabel(_("&Ignore"));
+ buttonRetry .SetLabel(_("&Retry"));
+ buttonIgnore.SetId(wxID_IGNORE);
+ buttonRetry .SetId(wxID_RETRY);
if (ignoreNextErrors)
- m_checkBoxIgnoreErrors->SetValue(*ignoreNextErrors);
+ checkBoxIgnoreErrors.SetValue(*ignoreNextErrors);
else
- m_checkBoxIgnoreErrors->Hide();
+ checkBoxIgnoreErrors.Hide();
if (~activeButtons & ReturnErrorDlg::BUTTON_IGNORE)
{
- m_buttonIgnore->Hide();
- m_checkBoxIgnoreErrors->Hide();
+ buttonIgnore.Hide();
+ checkBoxIgnoreErrors.Hide();
}
if (~activeButtons & ReturnErrorDlg::BUTTON_RETRY)
- m_buttonRetry->Hide();
+ buttonRetry.Hide();
- if (~activeButtons & ReturnErrorDlg::BUTTON_ABORT)
- m_buttonAbort->Hide();
+ if (~activeButtons & ReturnErrorDlg::BUTTON_CANCEL)
+ m_buttonCancel->Hide();
//set button focus precedence
if (activeButtons & ReturnErrorDlg::BUTTON_RETRY)
- m_buttonRetry->SetFocus();
+ buttonRetry.SetFocus();
else if (activeButtons & ReturnErrorDlg::BUTTON_IGNORE)
- m_buttonIgnore->SetFocus();
- else if (activeButtons & ReturnErrorDlg::BUTTON_ABORT)
- m_buttonAbort->SetFocus();
+ buttonIgnore.SetFocus();
+ else if (activeButtons & ReturnErrorDlg::BUTTON_CANCEL)
+ m_buttonCancel->SetFocus();
Fit(); //child-element widths have changed: image was set
}
-void ErrorDlg::OnClose(wxCloseEvent& event)
-{
- EndModal(ReturnErrorDlg::BUTTON_ABORT);
-}
-
-
-void ErrorDlg::OnIgnore(wxCommandEvent& event)
+void ErrorDlg::OnButton1(wxCommandEvent& event) //ignore
{
- if (ignoreErrors) *ignoreErrors = m_checkBoxIgnoreErrors->GetValue();
+ if (ignoreErrors)
+ *ignoreErrors = checkBoxIgnoreErrors.GetValue();
EndModal(ReturnErrorDlg::BUTTON_IGNORE);
}
-void ErrorDlg::OnRetry(wxCommandEvent& event)
+void ErrorDlg::OnButton2(wxCommandEvent& event) //retry
{
- if (ignoreErrors) *ignoreErrors = m_checkBoxIgnoreErrors->GetValue();
+ if (ignoreErrors)
+ *ignoreErrors = checkBoxIgnoreErrors.GetValue();
EndModal(ReturnErrorDlg::BUTTON_RETRY);
}
-void ErrorDlg::OnAbort(wxCommandEvent& event)
+ReturnErrorDlg::ButtonPressed zen::showErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors)
{
- if (ignoreErrors) *ignoreErrors = m_checkBoxIgnoreErrors->GetValue();
- EndModal(ReturnErrorDlg::BUTTON_ABORT);
+ ErrorDlg errorDlg(parent, activeButtons, messageText, wxString(), ignoreNextErrors);
+ errorDlg.Raise();
+ return static_cast<ReturnErrorDlg::ButtonPressed>(errorDlg.ShowModal());
}
+//########################################################################################
-ReturnErrorDlg::ButtonPressed zen::showErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors)
+ReturnFatalErrorDlg::ButtonPressed zen::showFatalErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors)
{
- ErrorDlg errorDlg(parent, activeButtons, messageText, ignoreNextErrors);
+ ErrorDlg errorDlg(parent, activeButtons, messageText, _("Fatal Error"), ignoreNextErrors);
errorDlg.Raise();
- return static_cast<ReturnErrorDlg::ButtonPressed>(errorDlg.ShowModal());
+ return static_cast<ReturnFatalErrorDlg::ButtonPressed>(errorDlg.ShowModal());
}
-//########################################################################################
+//########################################################################################
-class WarningDlg : public WarningDlgGenerated
+class WarningDlg : public MessageDlgGenerated
{
public:
WarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowAgain);
private:
- void OnClose(wxCloseEvent& event);
- void OnIgnore(wxCommandEvent& event);
- void OnSwitch(wxCommandEvent& event);
- void OnAbort(wxCommandEvent& event);
+ void OnClose (wxCloseEvent& event) { EndModal(ReturnWarningDlg::BUTTON_CANCEL); }
+ void OnCancel(wxCommandEvent& event) { EndModal(ReturnWarningDlg::BUTTON_CANCEL); }
+ void OnButton1(wxCommandEvent& event);
+ void OnButton2(wxCommandEvent& event);
+
bool& dontShowAgain;
+ wxButton& buttonIgnore; //
+ wxButton& buttonSwitch; // map generic controls
+ wxCheckBox& checkBoxDontShowAgain; //
};
WarningDlg::WarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowDlgAgain) :
- WarningDlgGenerated(parent),
- dontShowAgain(dontShowDlgAgain)
+ MessageDlgGenerated(parent),
+ dontShowAgain(dontShowDlgAgain),
+ buttonIgnore(*m_buttonCustom1),
+ buttonSwitch(*m_buttonCustom2),
+ checkBoxDontShowAgain(*m_checkBoxCustom)
+
{
#ifdef FFS_WIN
new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
#endif
- m_bitmap10->SetBitmap(GlobalResources::getImage(L"warning"));
- m_textCtrl8->SetValue(messageText);
- m_checkBoxDontShowAgain->SetValue(dontShowAgain);
+ SetTitle(_("Warning"));
+ m_bitmapMsgType->SetBitmap(GlobalResources::getImage(L"warning"));
+ m_textCtrlMessage->SetValue(messageText);
+ checkBoxDontShowAgain.SetLabel(_("Do not show this dialog again"));
+ buttonIgnore.SetLabel(_("&Ignore"));
+ buttonSwitch.SetLabel(_("&Switch"));
+ buttonIgnore.SetId(wxID_IGNORE);
+ buttonSwitch.SetId(wxID_MORE);
+
+ checkBoxDontShowAgain.SetValue(dontShowAgain);
if (~activeButtons & ReturnWarningDlg::BUTTON_IGNORE)
{
- m_buttonIgnore->Hide();
- m_checkBoxDontShowAgain->Hide();
+ buttonIgnore.Hide();
+ checkBoxDontShowAgain.Hide();
}
if (~activeButtons & ReturnWarningDlg::BUTTON_SWITCH)
- m_buttonSwitch->Hide();
+ buttonSwitch.Hide();
- if (~activeButtons & ReturnWarningDlg::BUTTON_ABORT)
- m_buttonAbort->Hide();
+ if (~activeButtons & ReturnWarningDlg::BUTTON_CANCEL)
+ m_buttonCancel->Hide();
//set button focus precedence
if (activeButtons & ReturnWarningDlg::BUTTON_IGNORE)
- m_buttonIgnore->SetFocus();
- else if (activeButtons & ReturnWarningDlg::BUTTON_ABORT)
- m_buttonAbort->SetFocus();
+ buttonIgnore.SetFocus();
+ else if (activeButtons & ReturnWarningDlg::BUTTON_CANCEL)
+ m_buttonCancel->SetFocus();
Fit(); //child-element widths have changed: image was set
}
-void WarningDlg::OnClose(wxCloseEvent& event)
-{
- EndModal(ReturnWarningDlg::BUTTON_ABORT);
-}
-
-
-void WarningDlg::OnIgnore(wxCommandEvent& event)
+void WarningDlg::OnButton1(wxCommandEvent& event) //ignore
{
- dontShowAgain = m_checkBoxDontShowAgain->GetValue();
+ dontShowAgain = checkBoxDontShowAgain.GetValue();
EndModal(ReturnWarningDlg::BUTTON_IGNORE);
}
-void WarningDlg::OnSwitch(wxCommandEvent& event)
+void WarningDlg::OnButton2(wxCommandEvent& event) //switch
{
- dontShowAgain = m_checkBoxDontShowAgain->GetValue();
+ dontShowAgain = checkBoxDontShowAgain.GetValue();
EndModal(ReturnWarningDlg::BUTTON_SWITCH);
}
-void WarningDlg::OnAbort(wxCommandEvent& event)
-{
- dontShowAgain = m_checkBoxDontShowAgain->GetValue();
- EndModal(ReturnWarningDlg::BUTTON_ABORT);
-}
-
-
ReturnWarningDlg::ButtonPressed zen::showWarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowAgain)
{
WarningDlg warningDlg(parent, activeButtons, messageText, dontShowAgain);
@@ -191,77 +203,98 @@ ReturnWarningDlg::ButtonPressed zen::showWarningDlg(wxWindow* parent, int active
//########################################################################################
-class QuestionDlg : public QuestionDlgGenerated
+class QuestionDlg : public MessageDlgGenerated
{
public:
- QuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox);
+ QuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, const wxString& caption, const wxString& labelYes, const wxString& labelNo, CheckBox* checkbox);
private:
void OnClose (wxCloseEvent& event) { EndModal(ReturnQuestionDlg::BUTTON_CANCEL); }
void OnCancel(wxCommandEvent& event) { EndModal(ReturnQuestionDlg::BUTTON_CANCEL); }
- void OnYes(wxCommandEvent& event);
- void OnNo (wxCommandEvent& event);
+ void OnButton1(wxCommandEvent& event);
+ void OnButton2(wxCommandEvent& event);
CheckBox* checkbox_; //optional
+ wxButton& buttonYes; // map generic controls
+ wxButton& buttonNo; //
};
-QuestionDlg::QuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox) :
- QuestionDlgGenerated(parent),
- checkbox_(checkbox)
+QuestionDlg::QuestionDlg(wxWindow* parent,
+ int activeButtons,
+ const wxString& messageText,
+ const wxString& caption, //optional
+ const wxString& labelYes,
+ const wxString& labelNo,
+ CheckBox* checkbox) :
+ MessageDlgGenerated(parent),
+ checkbox_(checkbox),
+ buttonYes(*m_buttonCustom1),
+ buttonNo (*m_buttonCustom2)
{
#ifdef FFS_WIN
new zen::MouseMoveWindow(*this); //allow moving main dialog by clicking (nearly) anywhere...; ownership passed to "this"
#endif
- m_bitmap10->SetBitmap(GlobalResources::getImage(L"question"));
- m_textCtrl8->SetValue(messageText);
+ SetTitle(!caption.empty()? caption : _("Question"));
+ m_bitmapMsgType->SetBitmap(GlobalResources::getImage(L"question"));
+ m_textCtrlMessage->SetValue(messageText);
+ buttonYes.SetLabel(!labelYes.empty() ? labelYes : _("&Yes"));
+ buttonNo .SetLabel(!labelNo .empty() ? labelNo : _("&No"));
+ buttonYes.SetId(wxID_YES);
+ buttonNo .SetId(wxID_NO);
if (checkbox_)
{
- m_checkBox->SetValue(checkbox_->value_);
- m_checkBox->SetLabel(checkbox_->label_);
+ m_checkBoxCustom->SetValue(checkbox_->value_);
+ m_checkBoxCustom->SetLabel(checkbox_->label_);
}
else
- m_checkBox->Hide();
+ m_checkBoxCustom->Hide();
if (~activeButtons & ReturnQuestionDlg::BUTTON_YES)
- m_buttonYes->Hide();
+ buttonYes.Hide();
if (~activeButtons & ReturnQuestionDlg::BUTTON_NO)
- m_buttonNo->Hide();
+ buttonNo.Hide();
if (~activeButtons & ReturnQuestionDlg::BUTTON_CANCEL)
m_buttonCancel->Hide();
//set button focus precedence
if (activeButtons & ReturnQuestionDlg::BUTTON_YES)
- m_buttonYes->SetFocus();
+ buttonYes.SetFocus();
else if (activeButtons & ReturnQuestionDlg::BUTTON_CANCEL)
m_buttonCancel->SetFocus();
else if (activeButtons & ReturnQuestionDlg::BUTTON_NO)
- m_buttonNo->SetFocus();
+ buttonNo.SetFocus();
Fit(); //child-element widths have changed: image was set
}
-void QuestionDlg::OnYes(wxCommandEvent& event)
+void QuestionDlg::OnButton1(wxCommandEvent& event) //yes
{
if (checkbox_)
- checkbox_->value_ = m_checkBox->GetValue();
+ checkbox_->value_ = m_checkBoxCustom->GetValue();
EndModal(ReturnQuestionDlg::BUTTON_YES);
}
-void QuestionDlg::OnNo(wxCommandEvent& event)
+void QuestionDlg::OnButton2(wxCommandEvent& event) //no
{
if (checkbox_)
- checkbox_->value_ = m_checkBox->GetValue();
+ checkbox_->value_ = m_checkBoxCustom->GetValue();
EndModal(ReturnQuestionDlg::BUTTON_NO);
}
-ReturnQuestionDlg::ButtonPressed zen::showQuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox)
+
+ReturnQuestionDlg::ButtonPressed zen::showQuestionDlg(wxWindow* parent,
+ int activeButtons,
+ const wxString& messageText,
+ const wxString& caption, //optional
+ const wxString& labelYes, const wxString& labelNo,
+ CheckBox* checkbox)
{
- QuestionDlg qtnDlg(parent, activeButtons, messageText, checkbox);
+ QuestionDlg qtnDlg(parent, activeButtons, messageText, caption, labelYes, labelNo, checkbox);
qtnDlg.Raise();
return static_cast<ReturnQuestionDlg::ButtonPressed>(qtnDlg.ShowModal());
}
diff --git a/ui/msg_popup.h b/ui/msg_popup.h
index 19a3c84f..48a4e8cb 100644
--- a/ui/msg_popup.h
+++ b/ui/msg_popup.h
@@ -21,19 +21,30 @@ struct ReturnErrorDlg
{
BUTTON_IGNORE = 1,
BUTTON_RETRY = 2,
- BUTTON_ABORT = 4
+ BUTTON_CANCEL = 4
};
};
ReturnErrorDlg::ButtonPressed showErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors); //ignoreNextErrors may be nullptr
+struct ReturnFatalErrorDlg
+{
+ enum ButtonPressed
+ {
+ BUTTON_IGNORE = ReturnErrorDlg::BUTTON_IGNORE,
+ BUTTON_CANCEL = ReturnErrorDlg::BUTTON_CANCEL
+ };
+};
+ReturnFatalErrorDlg::ButtonPressed showFatalErrorDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool* ignoreNextErrors); //ignoreNextErrors may be nullptr
+
+
struct ReturnWarningDlg
{
enum ButtonPressed
{
BUTTON_IGNORE = 1,
BUTTON_SWITCH = 2,
- BUTTON_ABORT = 4
+ BUTTON_CANCEL = 4
};
};
ReturnWarningDlg::ButtonPressed showWarningDlg(wxWindow* parent, int activeButtons, const wxString& messageText, bool& dontShowAgain);
@@ -57,7 +68,13 @@ struct CheckBox
bool& value_; //in/out
};
-ReturnQuestionDlg::ButtonPressed showQuestionDlg(wxWindow* parent, int activeButtons, const wxString& messageText, CheckBox* checkbox = nullptr);
+ReturnQuestionDlg::ButtonPressed showQuestionDlg(wxWindow* parent,
+ int activeButtons,
+ const wxString& messageText,
+ const wxString& caption = wxString(),
+ const wxString& labelYes = wxString(), //overwrite default "Yes, No" labels
+ const wxString& labelNo = wxString(), //
+ CheckBox* checkbox = nullptr);
}
#endif // MESSAGEPOPUP_H_INCLUDED
diff --git a/ui/small_dlgs.cpp b/ui/small_dlgs.cpp
index 0dd85593..bfe8de9c 100644
--- a/ui/small_dlgs.cpp
+++ b/ui/small_dlgs.cpp
@@ -9,7 +9,6 @@
#include "msg_popup.h"
#include "../lib/resources.h"
#include "../algorithm.h"
-#include <wx+/string_conv.h>
#include <wx+/format_unit.h>
#include <wx+/choice_enum.h>
#include "../synchronization.h"
@@ -25,6 +24,7 @@
#include <wx+/image_tools.h>
#include <zen/stl_tools.h>
#include "../lib/hard_filter.h"
+#include "../version/version.h"
using namespace zen;
@@ -44,7 +44,6 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
{
m_bitmap9 ->SetBitmap(GlobalResources::getImage(L"website"));
m_bitmap10->SetBitmap(GlobalResources::getImage(L"email"));
- m_bitmap11->SetBitmap(GlobalResources::getImage(L"logo"));
m_bitmap13->SetBitmap(GlobalResources::getImage(L"gpl"));
//m_bitmapTransl->SetBitmap(GlobalResources::getImage(wxT("translation")));
m_bitmapPaypal->SetBitmap(GlobalResources::getImage(L"paypal"));
@@ -71,6 +70,9 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
bSizerTranslators->Fit(m_scrolledWindowTranslators);
+#ifdef FFS_WIN
+ new zen::MouseMoveWindow(*this); //-> put *after* creating credits
+#endif
//build information
wxString build = __TDATE__;
@@ -92,12 +94,33 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
//m_animationControl1->SetAnimation(GlobalResources::instance().animationMoney);
//m_animationControl1->Play();
- m_buttonOkay->SetFocus();
Fit(); //child-element widths have changed: image was set
-#ifdef FFS_WIN
- new zen::MouseMoveWindow(*this); //-> put *after* creating credit control
-#endif
+ //generate logo
+ //-> put *after* first Fit()
+ Layout(); //make sure m_panelLogo has final width (required by wxGTK)
+
+ wxBitmap bmpLogo;
+ {
+ wxImage tmp = GlobalResources::getImage(L"logo").ConvertToImage();
+ tmp.Resize(wxSize(m_panelLogo->GetClientSize().GetWidth(), tmp.GetHeight()), wxPoint(0, 0), 255, 255, 255); //enlarge to fit full width
+ bmpLogo = wxBitmap(tmp);
+ }
+ {
+ wxMemoryDC dc;
+ dc.SelectObject(bmpLogo);
+
+ dc.SetTextForeground(*wxBLACK);
+ dc.SetFont(wxFont(18, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, L"Tahoma"));
+ dc.DrawLabel(wxString(L"FreeFileSync ") + zen::currentVersion, wxNullBitmap, wxRect(0, 0, bmpLogo.GetWidth(), bmpLogo.GetHeight()), wxALIGN_CENTER);
+
+ dc.SelectObject(wxNullBitmap);
+ }
+ m_bitmap11->SetBitmap(bmpLogo);
+
+ Fit(); //child-element widths have changed: image was set
+
+ m_buttonOkay->SetFocus();
}
@@ -170,7 +193,7 @@ FilterDlg::FilterDlg(wxWindow* parent,
add(USIZE_KB, _("KB")).
add(USIZE_MB, _("MB"));
- m_bitmap26->SetBitmap(GlobalResources::getImage(L"filterOn"));
+ m_bitmap26->SetBitmap(GlobalResources::getImage(L"filter"));
m_bpButtonHelp->SetBitmapLabel(GlobalResources::getImage(L"help"));
setFilter(filter);
diff --git a/ui/sync_cfg.cpp b/ui/sync_cfg.cpp
index b88d40f0..794569cc 100644
--- a/ui/sync_cfg.cpp
+++ b/ui/sync_cfg.cpp
@@ -10,7 +10,6 @@
#include "dir_name.h"
#include <wx/wupdlock.h>
#include <wx+/mouse_move_dlg.h>
-#include <wx+/string_conv.h>
#include <wx+/dir_picker.h>
#include <wx+/rtl.h>
#include "gui_generated.h"
@@ -223,7 +222,7 @@ SyncCfgDialog::SyncCfgDialog(wxWindow* parent,
//a proper set-method may be in order some time...
setEnumVal(enumDelhandDescr, *m_choiceHandleDeletion, syncCfg.handleDeletion);
- customDelFolder.setName(toWx(syncCfg.customDeletionDirectory));
+ customDelFolder.setName(utfCvrtTo<wxString>(syncCfg.customDeletionDirectory));
updateGui();
//error handling
@@ -353,7 +352,7 @@ void SyncCfgDialog::OnApply(wxCommandEvent& event)
//write configuration to main dialog
syncCfgOut.directionCfg = currentDirectionCfg;
syncCfgOut.handleDeletion = getEnumVal(enumDelhandDescr, *m_choiceHandleDeletion);
- syncCfgOut.customDeletionDirectory = toZ(customDelFolder.getName());
+ syncCfgOut.customDeletionDirectory = utfCvrtTo<Zstring>(customDelFolder.getName());
if (refHandleError)
*refHandleError = getEnumVal(enumErrhandDescr, *m_choiceHandleError);
diff --git a/version/version.h b/version/version.h
index 92e4e347..23741258 100644
--- a/version/version.h
+++ b/version/version.h
@@ -3,7 +3,7 @@
namespace zen
{
-const wchar_t currentVersion[] = L"5.4"; //internal linkage!
+const wchar_t currentVersion[] = L"5.5"; //internal linkage!
}
#endif
diff --git a/version/version.rc b/version/version.rc
index c12673f9..91d2e0f9 100644
--- a/version/version.rc
+++ b/version/version.rc
@@ -1,2 +1,2 @@
-#define VER_FREEFILESYNC 5,4,0,0
-#define VER_FREEFILESYNC_STR "5.4\0"
+#define VER_FREEFILESYNC 5,5,0,0
+#define VER_FREEFILESYNC_STR "5.5\0"
diff --git a/wx+/button.cpp b/wx+/button.cpp
index 1e9cb7f0..0b193cfb 100644
--- a/wx+/button.cpp
+++ b/wx+/button.cpp
@@ -8,6 +8,7 @@
#include <algorithm>
#include <limits>
#include <cmath>
+#include <zen/string_tools.h>
#include <wx/dcmemory.h>
#include <wx/image.h>
#include "image_tools.h"
@@ -79,7 +80,7 @@ void makeWhiteTransparent(wxImage& image) //assume black text on white backgroun
unsigned char* alphaLast = alphaFirst + image.GetWidth() * image.GetHeight();
//dist(black, white)
- double distBlackWhite = std::sqrt(3.0 * 255 * 255);
+ const double distBlackWhite = 255 * std::sqrt(3.0);
const unsigned char* bytePos = image.GetData();
@@ -101,12 +102,14 @@ void makeWhiteTransparent(wxImage& image) //assume black text on white backgroun
wxSize getSizeNeeded(const wxString& text, wxFont& font)
{
- wxCoord width, height;
- wxMemoryDC dc;
+ const wxString& textFormatted = replaceCpy(text, L"&", L"", false); //remove accelerator
+
+ wxCoord width = 0;
+ wxCoord height = 0;
- wxString textFormatted = text;
- textFormatted.Replace(wxT("&"), wxT(""), false); //remove accelerator
+ wxMemoryDC dc;
dc.GetMultiLineTextExtent(textFormatted, &width, &height, nullptr, &font);
+
return wxSize(width, height);
}
@@ -138,7 +141,7 @@ wxBitmap BitmapButton::createBitmapFromText(const wxString& text)
wxString textLabelFormatted = text;
if ((accelPos = text.find(wxT("&"))) != wxString::npos)
{
- textLabelFormatted.Replace(wxT("&"), wxT(""), false); //remove accelerator
+ replace(textLabelFormatted, L"&", L"", false); //remove accelerator
indexAccel = static_cast<int>(accelPos);
}
diff --git a/wx+/create_pch.cpp b/wx+/create_pch.cpp
new file mode 100644
index 00000000..a9b2ea37
--- /dev/null
+++ b/wx+/create_pch.cpp
@@ -0,0 +1,8 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+//dummy file for Visual Studio to compile precompiled header:
+//attaching pch to any other cpp file triggers a full rebuild each time code is changed! \ No newline at end of file
diff --git a/wx+/dir_picker.h b/wx+/dir_picker.h
index 5f18b6fb..51bd9757 100644
--- a/wx+/dir_picker.h
+++ b/wx+/dir_picker.h
@@ -22,10 +22,14 @@ public:
#ifdef FFS_WIN
//fix wxWidgets localization gap:
wxButton* button = dynamic_cast<wxButton*>(m_pickerIface);
- if (button) button->SetLabel(_("Browse"));
+ if (button)
+ {
+ button->SetLabel(_("Browse")); //button width needs to be adapted for very long translations
+ SetMinSize(button->GetBestSize()); //SetSize and wxButton::SetSize just do nothing!!??
+ }
#endif
}
};
}
-#endif // DIR_PICKER_I18N_H_INCLUDED
+#endif // DIR_PICKER_I18N_H_INCLUDED
diff --git a/wx+/serialize.h b/wx+/serialize.h
index f49bff04..030b55c7 100644
--- a/wx+/serialize.h
+++ b/wx+/serialize.h
@@ -8,14 +8,306 @@
#define SERIALIZE_H_INCLUDED
#include <cstdint>
-#include <wx/stream.h>
+#include <zen/string_base.h>
#include <zen/file_io.h>
+#ifdef FFS_WIN
+warn_static("get rid of wx, then move to zen")
+#endif
+
+#include <wx/stream.h>
+
namespace zen
{
+//high-performance unformatted serialization (avoiding wxMemoryOutputStream/wxMemoryInputStream inefficiencies)
+
+/*
+--------------------------
+|Binary Container Concept|
+--------------------------
+binary container for data storage: must support "basic" std::vector interface (e.g. std::vector<char>, std::string, Zbase<char>)
+*/
+
+//binary container reference implementations
+typedef Zbase<char> Utf8String; //ref-counted + COW text stream + guaranteed performance: exponential growth
+class BinaryStream; //ref-counted byte stream + guaranteed performance: exponential growth -> no COW, but 12% faster than Utf8String (due to no null-termination?)
+
+class BinaryStream //essentially a std::vector<char> with ref-counted semantics
+{
+public:
+ BinaryStream() : buffer(std::make_shared<std::vector<char>>()) {}
+
+ typedef std::vector<char>::value_type value_type;
+ typedef std::vector<char>::iterator iterator;
+ typedef std::vector<char>::const_iterator const_iterator;
+
+ iterator begin() { return buffer->begin(); }
+ iterator end () { return buffer->end (); }
+
+ const_iterator begin() const { return buffer->begin(); }
+ const_iterator end () const { return buffer->end (); }
+
+ void resize(size_t len) { buffer->resize(len); }
+ size_t size() const { return buffer->size(); }
+ bool empty() const { return buffer->empty(); }
+
+ inline friend bool operator==(const BinaryStream& lhs, const BinaryStream& rhs) { return *lhs.buffer == *rhs.buffer; }
+
+private:
+ std::shared_ptr<std::vector<char>> buffer; //always bound!
+ //perf: shared_ptr indirection irrelevant: less than 1% slower!
+};
+
+//----------------------------------------------------------------------
+//functions based on binary container abstraction
+template <class BinContainer> void saveBinStream(const Zstring& filename, const BinContainer& cont); //throw FileError
+template <class BinContainer> BinContainer loadBinStream(const Zstring& filename); //throw FileError, ErrorNotExisting
+
+
+/*
+-----------------------------
+|Binary Input Stream Concept|
+-----------------------------
+struct BinInputStream
+{
+ const void* requestRead(size_t len); //expect external read of len bytes
+};
+
+------------------------------
+|Binary Output Stream Concept|
+------------------------------
+struct BinOutputStream
+{
+ void* requestWrite(size_t len); //expect external write of len bytes
+};
+*/
+
+//binary input/output stream reference implementation
+class UnexpectedEndOfStreamError {};
+
+struct BinStreamIn //throw UnexpectedEndOfStreamError
+{
+ BinStreamIn(const BinaryStream& cont) : buffer(cont), pos(0) {} //this better be cheap!
+
+ const void* requestRead(size_t len) //throw UnexpectedEndOfStreamError
+ {
+ if (pos + len > buffer.size())
+ throw UnexpectedEndOfStreamError();
+ size_t oldPos = pos;
+ pos += len;
+ return &*buffer.begin() + oldPos;
+ }
+
+private:
+ const BinaryStream buffer;
+ size_t pos;
+};
+
+struct BinStreamOut
+{
+ void* requestWrite(size_t len)
+ {
+ size_t oldSize = buffer.size();
+ buffer.resize(buffer.size() + len);
+ return &*buffer.begin() + oldSize;
+ }
+
+ BinaryStream get() { return buffer; }
+
+private:
+ BinaryStream buffer;
+};
+
+//----------------------------------------------------------------------
+//functions based on binary stream abstraction
+template <class N, class BinOutputStream> void writeNumber (BinOutputStream& stream, const N& num); //
+template <class C, class BinOutputStream> void writeContainer(BinOutputStream& stream, const C& str); //throw ()
+template < class BinOutputStream> void writeArray (BinOutputStream& stream, const void* data, size_t len); //
+
+//----------------------------------------------------------------------
+
+template <class N, class BinInputStream> N readNumber (BinInputStream& stream); //
+template <class C, class BinInputStream> C readContainer(BinInputStream& stream); //throw UnexpectedEndOfStreamError (corrupted data)
+template < class BinInputStream> void readArray (BinInputStream& stream, void* data, size_t len); //
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//-----------------------implementation-------------------------------
+template <class BinContainer> inline
+void saveBinStream(const Zstring& filename, const BinContainer& cont) //throw FileError
+{
+ assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further)
+
+ FileOutput fileOut(filename, zen::FileOutput::ACC_OVERWRITE); //throw FileError
+ if (!cont.empty())
+ fileOut.write(&*cont.begin(), cont.size()); //throw FileError
+}
+
+
+template <class BinContainer> inline
+BinContainer loadBinStream(const Zstring& filename) //throw FileError, ErrorNotExisting
+{
+ assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further)
+
+ FileInput fileIn(filename); //throw FileError, ErrorNotExisting
+
+ BinContainer contOut;
+ const size_t blockSize = 64 * 1024;
+ do
+ {
+ contOut.resize(contOut.size() + blockSize);
+
+ const size_t bytesRead = fileIn.read(&*contOut.begin() + contOut.size() - blockSize, blockSize); //throw FileError
+ if (bytesRead < blockSize)
+ contOut.resize(contOut.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics
+ }
+ while (!fileIn.eof());
+
+ return contOut;
+}
+
+
+template <class BinOutputStream> inline
+void writeArray(BinOutputStream& stream, const void* data, size_t len)
+{
+ std::copy(static_cast<const char*>(data),
+ static_cast<const char*>(data) + len,
+ static_cast< char*>(stream.requestWrite(len)));
+}
+
+
+template <class N, class BinOutputStream> inline
+void writeNumber(BinOutputStream& stream, const N& num)
+{
+ assert_static((IsArithmetic<N>::value || IsSameType<N, bool>::value));
+ writeArray(stream, &num, sizeof(N));
+}
+
+
+template <class C, class BinOutputStream> inline
+void writeContainer(BinOutputStream& stream, const C& cont) //don't even consider UTF8 conversions here! "string" is expected to handle arbitrary binary data!
+{
+ const auto len = cont.size();
+ writeNumber(stream, static_cast<std::uint32_t>(len));
+ if (len > 0)
+ writeArray(stream, &*cont.begin(), sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface
+}
+
+
+template <class BinInputStream> inline
+void readArray(BinInputStream& stream, void* data, size_t len)
+{
+ const char* const src = static_cast<const char*>(stream.requestRead(len)); //expect external write of len bytes
+ std::copy(src, src + len, static_cast<char*>(data));
+}
+
+
+template <class N, class BinInputStream> inline
+N readNumber(BinInputStream& stream)
+{
+ assert_static((IsArithmetic<N>::value || IsSameType<N, bool>::value));
+ N num = 0;
+ readArray(stream, &num, sizeof(N));
+ return num;
+}
+
+
+template <class C, class BinInputStream> inline
+C readContainer(BinInputStream& stream)
+{
+ C cont;
+ auto strLength = readNumber<std::uint32_t>(stream);
+ if (strLength > 0)
+ try
+ {
+ cont.resize(strLength); //throw std::bad_alloc
+ readArray(stream, &*cont.begin(), sizeof(typename C::value_type) * strLength);
+ }
+ catch (std::bad_alloc&) //most likely this is due to data corruption!
+ {
+ throw UnexpectedEndOfStreamError();
+ }
+ return cont;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef FFS_WIN
+warn_static("get rid of wx, then move to zen")
+#endif
+
+
+
//unchecked, unformatted serialization
-template <class T> T readPOD (wxInputStream& stream);
+template <class T> T readPOD (wxInputStream& stream);
template <class T> void readPOD (wxInputStream& stream, T& pod);
template <class T> void writePOD(wxOutputStream& stream, const T& pod);
@@ -116,29 +408,6 @@ private:
};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//-----------------------implementation-------------------------------
template <class T> inline
T readPOD(wxInputStream& stream)
{
@@ -235,7 +504,7 @@ void CheckedReader::readString(S& str) const //checked read operation
}
catch (std::exception&) { throwException(); }
check();
- if (stream_.LastRead() != str.length() * sizeof(typename S::value_type)) //some additional check
+ if (stream_.LastRead() != str.size() * sizeof(typename S::value_type)) //some additional check
throwException();
}
@@ -260,6 +529,7 @@ void CheckedWriter::writeString(const S& str) const //checked write operation
{
zen::writeString(stream_, str);
check();
+ //warn_static("buggy check if length 0!")
if (stream_.LastWrite() != str.length() * sizeof(typename S::value_type)) //some additional check
throwException();
}
diff --git a/wx+/zlib_wrap.cpp b/wx+/zlib_wrap.cpp
new file mode 100644
index 00000000..22285bab
--- /dev/null
+++ b/wx+/zlib_wrap.cpp
@@ -0,0 +1,54 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#include "zlib_wrap.h"
+#ifdef FFS_WIN
+#include <../src/zlib/zlib.h> //not really a "nice" place to look for a stable solution
+#elif defined FFS_LINUX
+#include <zlib.h> //let's pray this is the same version wxWidgets is linking against!
+#endif
+
+using namespace zen;
+
+
+size_t zen::impl::zlib_compressBound(size_t len)
+{
+ return ::compressBound(static_cast<uLong>(len)); //upper limit for buffer size, larger than input size!!!
+}
+
+
+size_t zen::impl::zlib_compress(const void* src, size_t srcLen, void* trg, size_t trgLen, int level) //throw ZlibInternalError
+{
+ uLongf bufferSize = static_cast<uLong>(trgLen);
+ const int rv = ::compress2(static_cast<Bytef*>(trg), //Bytef* dest,
+ &bufferSize, //uLongf* destLen,
+ static_cast<const Bytef*>(src), //const Bytef* source,
+ static_cast<uLong>(srcLen), //uLong sourceLen,
+ level); //int level
+ // Z_OK: success
+ // Z_MEM_ERROR: not enough memory
+ // Z_BUF_ERROR: not enough room in the output buffer
+ if (rv != Z_OK || bufferSize > trgLen)
+ throw ZlibInternalError();
+ return bufferSize;
+}
+
+
+size_t zen::impl::zlib_decompress(const void* src, size_t srcLen, void* trg, size_t trgLen) //throw ZlibInternalError
+{
+ uLongf bufferSize = static_cast<uLong>(trgLen);
+ const int rv = ::uncompress(static_cast<Bytef*>(trg), //Bytef* dest,
+ &bufferSize, //uLongf* destLen,
+ static_cast<const Bytef*>(src), //const Bytef* source,
+ static_cast<uLong>(srcLen)); //uLong sourceLen
+ // Z_OK: success
+ // Z_MEM_ERROR: not enough memory
+ // Z_BUF_ERROR: not enough room in the output buffer
+ // Z_DATA_ERROR: input data was corrupted or incomplete
+ if (rv != Z_OK || bufferSize > trgLen)
+ throw ZlibInternalError();
+ return bufferSize;
+}
diff --git a/wx+/zlib_wrap.h b/wx+/zlib_wrap.h
new file mode 100644
index 00000000..7b196a75
--- /dev/null
+++ b/wx+/zlib_wrap.h
@@ -0,0 +1,115 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef SIMPLE_H_INCLUDED_18134135134135345489
+#define SIMPLE_H_INCLUDED_18134135134135345489
+
+#include <wx+/serialize.h>
+
+namespace zen
+{
+class ZlibInternalError {};
+
+// compression level must be between 0 and 9:
+// 0: no compression
+// 9: best compression
+template <class BinContainer> //as specified in serialize.h
+BinContainer compress(const BinContainer& stream, int level); //throw ZlibInternalError
+//caveat: output stream is physically larger than input! => strip additional reserved space if needed: "BinContainer(output.begin(), output.end())"
+
+template <class BinContainer>
+BinContainer decompress(const BinContainer& stream); //throw ZlibInternalError
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//######################## implementation ##########################
+namespace impl
+{
+size_t zlib_compressBound(size_t len);
+size_t zlib_compress (const void* src, size_t srcLen, void* trg, size_t trgLen, int level); //throw ZlibInternalError
+size_t zlib_decompress(const void* src, size_t srcLen, void* trg, size_t trgLen); //throw ZlibInternalError
+}
+
+
+template <class BinContainer>
+BinContainer compress(const BinContainer& stream, int level) //throw ZlibInternalError
+{
+ BinContainer contOut;
+
+ //save uncompressed stream size for decompression
+ const std::uint64_t uncompressedSize = stream.size(); //use portable number type!
+ contOut.resize(sizeof(uncompressedSize));
+ std::copy(reinterpret_cast<const char*>(&uncompressedSize),
+ reinterpret_cast<const char*>(&uncompressedSize) + sizeof(uncompressedSize),
+ &*contOut.begin());
+
+ const size_t bufferEstimate = impl::zlib_compressBound(stream.size()); //upper limit for buffer size, larger than input size!!!
+
+ contOut.resize(contOut.size() + bufferEstimate);
+
+ const size_t bytesWritten = impl::zlib_compress(&*stream.begin(),
+ stream.size(),
+ &*contOut.begin() + contOut.size() - bufferEstimate,
+ bufferEstimate,
+ level); //throw ZlibInternalError
+ if (bytesWritten < bufferEstimate)
+ contOut.resize(contOut.size() - (bufferEstimate - bytesWritten)); //caveat: unsigned arithmetics
+ //caveat: physical memory consumption still *unchanged*!
+
+ return contOut;
+}
+
+
+template <class BinContainer>
+BinContainer decompress(const BinContainer& stream) //throw ZlibInternalError
+{
+ //retrieve size of uncompressed data
+ std::uint64_t uncompressedSize = 0; //use portable number type!
+ if (stream.size() < sizeof(uncompressedSize))
+ throw ZlibInternalError();
+ std::copy(&*stream.begin(),
+ &*stream.begin() + sizeof(uncompressedSize),
+ reinterpret_cast<char*>(&uncompressedSize));
+
+ BinContainer contOut;
+ try
+ {
+ contOut.resize(uncompressedSize); //throw std::bad_alloc
+ }
+ catch (std::bad_alloc&) //most likely due to data corruption!
+ {
+ throw ZlibInternalError();
+ }
+
+ const size_t bytesWritten = impl::zlib_decompress(&*stream.begin() + sizeof(uncompressedSize),
+ stream.size() - sizeof(uncompressedSize),
+ &*contOut.begin(),
+ uncompressedSize); //throw ZlibInternalError
+ if (bytesWritten != uncompressedSize)
+ throw ZlibInternalError();
+
+ return contOut;
+}
+}
+
+#endif //SIMPLE_H_INCLUDED_18134135134135345489
diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp
index 9fba5f1a..19f43998 100644
--- a/zen/FindFilePlus/find_file_plus.cpp
+++ b/zen/FindFilePlus/find_file_plus.cpp
@@ -296,7 +296,7 @@ void FileSearcher::readDirImpl(FileInformation& output) //throw FileError
rv == STATUS_INVALID_INFO_CLASS ||
rv == STATUS_UNSUCCESSFUL ||
rv == STATUS_ACCESS_VIOLATION ||
- rv == STATUS_NO_SUCH_FILE)
+ rv == STATUS_NO_SUCH_FILE) //[!]
rv = STATUS_NOT_SUPPORTED;
throw NtFileError(rv); //throws STATUS_NO_MORE_FILES when finished
diff --git a/zen/error_log.h b/zen/error_log.h
index f3f67233..bbb36f00 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -17,10 +17,10 @@ namespace zen
{
enum MessageType
{
- TYPE_INFO = 1,
- TYPE_WARNING = 2,
- TYPE_ERROR = 4,
- TYPE_FATAL_ERROR = 8,
+ TYPE_INFO = 0x1,
+ TYPE_WARNING = 0x2,
+ TYPE_ERROR = 0x4,
+ TYPE_FATAL_ERROR = 0x8,
};
struct LogEntry
@@ -130,4 +130,4 @@ inline std::wstring formatMessage(const LogEntry& entry) { return formatMessageI
}
-#endif // ERRORLOGGING_H_INCLUDED
+#endif //ERRORLOGGING_H_INCLUDED
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index f004e09c..ebfe4d19 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -23,7 +23,6 @@
#include "long_path_prefix.h"
#include <Aclapi.h>
#include "dst_hack.h"
-#include "file_update_handle.h"
#include "win_ver.h"
#include "IFileOperation/file_op.h"
@@ -703,18 +702,25 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, Callb
}
//if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the directory)
catch (const ErrorDifferentVolume&) {}
- catch (const ErrorTargetExisting&) {}
+ catch (const ErrorTargetExisting& ) {}
//create target
if (symlinkExists(sourceDir))
{
- if (!dirExists(targetDir))
+ if (!symlinkExists(targetDir))
copySymlink(sourceDir, targetDir, false); //throw FileError -> don't copy permissions
}
else
{
- if (!dirExists(targetDir)) //check even if ErrorTargetExisting: me may have clashed with a file of the same name!!!
- createDirectory(targetDir, sourceDir, false); //throw FileError
+ try
+ {
+ makeNewDirectory(targetDir, sourceDir, false); //FileError, ErrorTargetExisting
+ }
+ catch (const ErrorTargetExisting&)
+ {
+ if (!dirExists(targetDir))
+ throw; //clashed with a file or symlink of the same name!!!
+ }
//move files/folders recursively
TraverseOneLevel::NameList fileList; //list of names: 1. short 2.long
@@ -888,23 +894,6 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
{
*/
- //may need to remove the readonly-attribute (e.g. FAT usb drives)
- FileUpdateHandle targetHandle(filename, [=]
- {
- return ::CreateFile(applyLongPathPrefix(filename).c_str(),
- FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
- //avoids mysterious "access denied" when using "GENERIC_READ | GENERIC_WRITE" on a read-only file, even after read-only was removed right before:
- //https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3514569&group_id=234430
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory
- (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks
- nullptr);
- });
-
- if (targetHandle.get() == INVALID_HANDLE_VALUE)
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
/*
if (hTarget == INVALID_HANDLE_VALUE && ::GetLastError() == ERROR_SHARING_VIOLATION)
::Sleep(retryInterval); //wait then retry
@@ -913,12 +902,87 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
}
*/
- auto isNullTime = [](const FILETIME & ft) { return ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0; };
+ //temporarily reset read-only flag if required
+ DWORD attribs = INVALID_FILE_ATTRIBUTES;
+ ZEN_ON_SCOPE_EXIT(
+ if (attribs != INVALID_FILE_ATTRIBUTES)
+ ::SetFileAttributes(applyLongPathPrefix(filename).c_str(), attribs);
+ );
+
+ auto removeReadonly = [&]() -> bool //may need to remove the readonly-attribute (e.g. on FAT usb drives)
+ {
+ if (attribs == INVALID_FILE_ATTRIBUTES)
+ {
+ const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(filename).c_str());
+ if (tmpAttr == INVALID_FILE_ATTRIBUTES)
+ throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+
+ if (tmpAttr & FILE_ATTRIBUTE_READONLY)
+ {
+ if (!::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL))
+ throw FileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+
+ attribs = tmpAttr; //reapplied on scope exit
+ return true;
+ }
+ }
+ return false;
+ };
+
+ auto openFile = [&](bool conservativeApproach)
+ {
+ return ::CreateFile(applyLongPathPrefix(filename).c_str(),
+ (conservativeApproach ?
+ //some NAS seem to have issues with FILE_WRITE_ATTRIBUTES, even worse, they may fail silently!
+ //http://sourceforge.net/tracker/?func=detail&atid=1093081&aid=3536680&group_id=234430
+ //Citrix shares seem to have this issue, too, but at least fail with "access denied" => try generic access first:
+ GENERIC_READ | GENERIC_WRITE :
+ //avoids mysterious "access denied" when using "GENERIC_READ | GENERIC_WRITE" on a read-only file, even *after* read-only was removed directly before the call!
+ //http://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3514569&group_id=234430
+ //since former gives an error notification we may very well try FILE_WRITE_ATTRIBUTES second.
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES),
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory
+ (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks
+ nullptr);
+ };
+
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ for (int i = 0; i < 2; ++i) //we will get this handle, no matter what! :)
+ {
+ //1. be conservative
+ hFile = openFile(true);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ if (::GetLastError() == ERROR_ACCESS_DENIED) //fails if file is read-only (or for "other" reasons)
+ if (removeReadonly())
+ continue;
- if (!::SetFileTime(targetHandle.get(), //__in HANDLE hFile,
+ //2. be a *little* fancy
+ hFile = openFile(false);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ if (::GetLastError() == ERROR_ACCESS_DENIED)
+ if (removeReadonly())
+ continue;
+
+ //3. after these herculean stunts we give up...
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted());
+ }
+ }
+ break;
+ }
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
+
+
+ auto isNullTime = [](const FILETIME& ft) { return ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0; };
+
+ if (!::SetFileTime(hFile, //__in HANDLE hFile,
!isNullTime(creationTime) ? &creationTime : nullptr, //__in_opt const FILETIME *lpCreationTime,
- nullptr, //__in_opt const FILETIME *lpLastAccessTime,
- &lastWriteTime)) //__in_opt const FILETIME *lpLastWriteTime
+ nullptr, //__in_opt const FILETIME *lpLastAccessTime,
+ &lastWriteTime)) //__in_opt const FILETIME *lpLastWriteTime
{
auto lastErr = ::GetLastError();
@@ -933,7 +997,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
{
auto setFileInfo = [&](FILE_BASIC_INFO basicInfo) //throw FileError; no const& since SetFileInformationByHandle() requires non-const parameter!
{
- if (!setFileInformationByHandle(targetHandle.get(), //__in HANDLE hFile,
+ if (!setFileInformationByHandle(hFile, //__in HANDLE hFile,
FileBasicInfo, //__in FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
&basicInfo, //__in LPVOID lpFileInformation,
sizeof(basicInfo))) //__in DWORD dwBufferSize
@@ -950,7 +1014,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
//---------------------------------------------------------------------------
BY_HANDLE_FILE_INFORMATION fileInfo = {};
- if (::GetFileInformationByHandle(targetHandle.get(), &fileInfo))
+ if (::GetFileInformationByHandle(hFile, &fileInfo))
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{
FILE_BASIC_INFO basicInfo = {}; //undocumented: file times of "0" stand for "don't change"
@@ -959,6 +1023,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
if (!isNullTime(creationTime))
basicInfo.CreationTime = toLargeInteger(creationTime);
+ //set file time + attributes
setFileInfo(basicInfo); //throw FileError
try //... to restore original file attributes
@@ -972,10 +1037,10 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
lastErr = ERROR_SUCCESS;
}
}
-
- if (lastErr != ERROR_SUCCESS)
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted(lastErr));
}
+
+ if (lastErr != ERROR_SUCCESS)
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)) + L"\n\n" + getLastErrorFormatted(lastErr));
}
#ifndef NDEBUG //dst hack: verify data written
@@ -1005,8 +1070,8 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
else
{
struct timeval newTimes[2] = {};
- newTimes[0].tv_sec = ::time(nullptr); /* seconds */
- newTimes[0].tv_usec = 0; /* microseconds */
+ newTimes[0].tv_sec = ::time(nullptr); //seconds
+ newTimes[0].tv_usec = 0; //microseconds
newTimes[1].tv_sec = to<time_t>(modificationTime);
newTimes[1].tv_usec = 0;
@@ -1140,7 +1205,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
//copy permissions for files, directories or symbolic links: requires admin rights
-void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError;
+void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError
{
#ifdef FFS_WIN
//setting privileges requires admin rights!
@@ -1314,22 +1379,41 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
}
-void createDirectory_straight(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions, int level)
+void createDirectoryStraight(const Zstring& directory, //throw FileError, ErrorTargetExisting, ErrorTargetPathMissing
+ const Zstring& templateDir,
+ bool copyFilePermissions)
{
- //default directory creation
#ifdef FFS_WIN
//don't use ::CreateDirectoryEx:
//- it may fail with "wrong parameter (error code 87)" when source is on mapped online storage
//- automatically copies symbolic links if encountered: unfortunately it doesn't copy symlinks over network shares but silently creates empty folders instead (on XP)!
//- it isn't able to copy most junctions because of missing permissions (although target path can be retrieved alternatively!)
- if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), nullptr))
+ if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), //__in LPCTSTR lpPathName,
+ nullptr)) //__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ {
+ const std::wstring msg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted();
+ const ErrorCode lastError = getLastError();
+
+ if (lastError == ERROR_ALREADY_EXISTS)
+ throw ErrorTargetExisting(msg);
+ else if (lastError == ERROR_PATH_NOT_FOUND)
+ throw ErrorTargetPathMissing(msg);
+ throw FileError(msg);
+ }
+
#elif defined FFS_LINUX
- if (::mkdir(directory.c_str(), 0755) != 0)
-#endif
+ if (::mkdir(directory.c_str(), 0755) != 0) //mode: drwxr-xr-x
{
- if (level != 0) return;
- throw FileError(replaceCpy(_("Cannot create directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
+ const std::wstring msg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted();
+ const ErrorCode lastError = getLastError();
+
+ if (lastError == EEXIST)
+ throw ErrorTargetExisting(msg);
+ else if (lastError == ENOENT)
+ throw ErrorTargetPathMissing(msg);
+ throw FileError(msg);
}
+#endif
if (!templateDir.empty())
{
@@ -1355,11 +1439,12 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
const DWORD sourceAttr = ::GetFileAttributes(applyLongPathPrefix(sourcePath).c_str());
if (sourceAttr != INVALID_FILE_ATTRIBUTES)
{
+ ::SetFileAttributes(applyLongPathPrefix(directory).c_str(), sourceAttr);
+ //copy "read-only and system attributes": http://blogs.msdn.com/b/oldnewthing/archive/2003/09/30/55100.aspx
+
const bool isCompressed = (sourceAttr & FILE_ATTRIBUTE_COMPRESSED) != 0;
const bool isEncrypted = (sourceAttr & FILE_ATTRIBUTE_ENCRYPTED) != 0;
- ::SetFileAttributes(applyLongPathPrefix(directory).c_str(), sourceAttr);
-
if (isEncrypted)
::EncryptFile(directory.c_str()); //seems no long path is required (check passed!)
@@ -1391,6 +1476,7 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
}
}
#endif
+
zen::ScopeGuard guardNewDir = zen::makeGuard([&] { try { removeDirectory(directory); } catch (...) {} }); //ensure cleanup:
//enforce copying file permissions: it's advertized on GUI...
@@ -1402,47 +1488,48 @@ void createDirectory_straight(const Zstring& directory, const Zstring& templateD
}
-void createDirectoryRecursively(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions, int level)
+void createDirectoryRecursively(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions) //FileError, ErrorTargetExisting
{
- if (level == 100) //catch endless recursion
- return;
-
-#ifdef FFS_WIN
- std::unique_ptr<Fix8Dot3NameClash> fnc;
- if (somethingExists(directory))
+ try
{
- //handle issues with already existing short 8.3 file names on Windows
- if (have8dot3NameClash(directory))
- fnc.reset(new Fix8Dot3NameClash(directory)); //move clashing object to the side
- else if (dirExists(directory))
- return;
+ createDirectoryStraight(directory, templateDir, copyFilePermissions); //throw FileError, ErrorTargetExisting, ErrorTargetPathMissing
}
-#elif defined FFS_LINUX
- if (somethingExists(directory))
+ catch (const ErrorTargetExisting&)
{
- if (dirExists(directory))
+#ifdef FFS_WIN
+ //handle issues with already existing short 8.3 file names on Windows
+ if (have8dot3NameClash(directory))
+ {
+ Fix8Dot3NameClash dummy(directory); //move clashing object to the side
+
+ //now try again...
+ createDirectoryStraight(directory, templateDir, copyFilePermissions); //throw FileError, ErrorTargetExisting, ErrorTargetPathMissing
return;
- }
+ }
#endif
- else //if "not somethingExists" we need to create the parent directory
+ throw;
+ }
+ catch (const ErrorTargetPathMissing&)
{
- //try to create parent folders first
+ //we need to create parent directories first
const Zstring dirParent = beforeLast(directory, FILE_NAME_SEPARATOR);
- if (!dirParent.empty() && !dirExists(dirParent))
+ if (!dirParent.empty())
{
//call function recursively
const Zstring templateParent = beforeLast(templateDir, FILE_NAME_SEPARATOR); //returns empty string if ch not found
- createDirectoryRecursively(dirParent, templateParent, copyFilePermissions, level + 1);
+ createDirectoryRecursively(dirParent, templateParent, copyFilePermissions); //throw
+
+ //now try again...
+ createDirectoryStraight(directory, templateDir, copyFilePermissions); //throw FileError, ErrorTargetExisting, ErrorTargetPathMissing
+ return;
}
+ throw;
}
-
- //now creation should be possible
- createDirectory_straight(directory, templateDir, copyFilePermissions, level); //throw FileError
}
}
-void zen::createDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions)
+void zen::makeNewDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions) //FileError, ErrorTargetExisting
{
//remove trailing separator
const Zstring dirFormatted = endsWith(directory, FILE_NAME_SEPARATOR) ?
@@ -1453,13 +1540,22 @@ void zen::createDirectory(const Zstring& directory, const Zstring& templateDir,
beforeLast(templateDir, FILE_NAME_SEPARATOR) :
templateDir;
- createDirectoryRecursively(dirFormatted, templateFormatted, copyFilePermissions, 0);
+ createDirectoryRecursively(dirFormatted, templateFormatted, copyFilePermissions); //FileError, ErrorTargetExisting
}
-void zen::createDirectory(const Zstring& directory)
+void zen::makeDirectory(const Zstring& directory)
{
- zen::createDirectory(directory, Zstring(), false);
+ try
+ {
+ makeNewDirectory(directory, Zstring(), false); //FileError, ErrorTargetExisting
+ }
+ catch (const ErrorTargetExisting&)
+ {
+ if (dirExists(directory))
+ return;
+ throw; //clash with file (dir symlink is okay)
+ }
}
@@ -2254,7 +2350,7 @@ Zstring findUnusedTempName(const Zstring& filename)
{
Zstring output = filename + zen::TEMP_FILE_ENDING;
- //ensure uniqueness (+ minor race condition)
+ //ensure uniqueness (+ minor file system race condition!)
for (int i = 1; somethingExists(output); ++i)
output = filename + Zchar('_') + numberTo<Zstring>(i) + zen::TEMP_FILE_ENDING;
diff --git a/zen/file_handling.h b/zen/file_handling.h
index 8848fbc2..d6444da3 100644
--- a/zen/file_handling.h
+++ b/zen/file_handling.h
@@ -53,18 +53,18 @@ void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = nul
//rename file or directory: no copying!!!
-void renameFile(const Zstring& oldName, const Zstring& newName); //throw FileError;
+void renameFile(const Zstring& oldName, const Zstring& newName); //throw FileError
//move source to target across volumes; prerequisite: all super-directories of target exist
//if target already contains some files/dirs they are seen as remnants of a previous incomplete move - see comment in moveDirectoryImpl
-void moveFile(const Zstring& sourceFile, const Zstring& targetFile, CallbackMoveFile* callback); //throw FileError
-void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, CallbackMoveFile* callback); //throw FileError
+void moveFile (const Zstring& sourceFile, const Zstring& targetFile, CallbackMoveFile* callback); //throw FileError
+void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, CallbackMoveFile* callback); //throw FileError
bool supportsPermissions(const Zstring& dirname); //throw FileError, derefernces symlinks
//creates superdirectories automatically:
-void createDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //throw FileError;
-void createDirectory(const Zstring& directory); //throw FileError; -> function overload avoids default parameter ambiguity issues!
+void makeDirectory(const Zstring& directory); //throw FileError; do nothing if directory already exists!
+void makeNewDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //FileError, ErrorTargetExisting
struct FileAttrib
{
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 3b3c244d..77fcb691 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -81,7 +81,7 @@ FileInput::~FileInput()
}
-size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number of bytes read; throw (FileError)
+size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number of bytes read; throw FileError
{
#ifdef FFS_WIN
DWORD bytesRead = 0;
diff --git a/zen/file_io.h b/zen/file_io.h
index 33074d7e..b134e47a 100644
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -19,6 +19,12 @@
namespace zen
{
+#ifdef FFS_WIN
+static const char LINE_BREAK[] = "\r\n";
+#elif defined FFS_LINUX
+static const char LINE_BREAK[] = "\n";
+#endif
+
//file IO optimized for sequential read/write accesses + better error reporting + long path support (following symlinks)
#ifdef FFS_WIN
@@ -37,6 +43,8 @@ public:
size_t read(void* buffer, size_t bytesToRead); //throw FileError; returns actual number of bytes read
bool eof() { return eofReached; } //end of file reached
+ const Zstring& getFilename() const { return filename_; }
+
private:
FileInput(const FileInput&);
FileInput& operator=(const FileInput&);
@@ -61,6 +69,8 @@ public:
void write(const void* buffer, size_t bytesToWrite); //throw FileError
+ const Zstring& getFilename() const { return filename_; }
+
private:
FileOutput(const FileOutput&);
FileOutput& operator=(const FileOutput&);
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index 3acb0edf..aa46d4f0 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -10,13 +10,12 @@
#include "symlink_target.h"
#ifdef FFS_WIN
-#include "win.h" //includes "windows.h"
+#include <zen/win_ver.h>
#include "long_path_prefix.h"
#include "dst_hack.h"
-#include "file_update_handle.h"
+#include "file_handling.h" //remove this huge dependency when getting rid of DST hack!! until then we need "setFileTime"
#include "dll.h"
#include "FindFilePlus/find_file_plus.h"
-#include <zen/win_ver.h>
#elif defined FFS_LINUX
#include <sys/stat.h>
@@ -179,11 +178,12 @@ struct Win32Traverser
{
struct DirHandle
{
- DirHandle() : searchHandle(nullptr), firstRead(true), firstData() {}
+ DirHandle() : searchHandle(nullptr), haveData(true), data() {}
HANDLE searchHandle;
- bool firstRead;
- WIN32_FIND_DATA firstData;
+
+ bool haveData;
+ WIN32_FIND_DATA data;
};
typedef WIN32_FIND_DATA FindData;
@@ -192,7 +192,7 @@ struct Win32Traverser
{
const Zstring& directoryPf = appendSeparator(directory);
- hnd.searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &hnd.firstData);
+ hnd.searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &hnd.data);
//no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH
if (hnd.searchHandle == INVALID_HANDLE_VALUE)
throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
@@ -208,10 +208,10 @@ struct Win32Traverser
template <class FallbackFun>
static bool getEntry(DirHandle& hnd, const Zstring& directory, FindData& fileInfo, FallbackFun) //throw FileError
{
- if (hnd.firstRead)
+ if (hnd.haveData)
{
- hnd.firstRead = false;
- ::memcpy(&fileInfo, &hnd.firstData, sizeof(fileInfo));
+ hnd.haveData = false;
+ ::memcpy(&fileInfo, &hnd.data, sizeof(fileInfo));
return true;
}
@@ -451,7 +451,7 @@ private:
if (dst::fatHasUtcEncoded(rawTime)) //throw std::runtime_error
fileInfo.lastWriteTimeRaw = toTimeT(dst::fatDecodeUtcTime(rawTime)); //return real UTC time; throw (std::runtime_error)
else
- markForDstHack.push_back(std::make_pair(fullName, Trav::getModTimeRaw(findData)));
+ markForDstHack.push_back(std::make_pair(fullName, toTimeT(rawTime.writeTimeRaw)));
}
//####################################### DST hack ###########################################
@@ -467,52 +467,33 @@ private:
int failedAttempts = 0;
int filesToValidate = 50; //don't let data verification become a performance issue
- for (FilenameTimeList::const_iterator i = markForDstHack.begin(); i != markForDstHack.end(); ++i)
+ for (auto iter = markForDstHack.begin(); iter != markForDstHack.end(); ++iter)
{
if (failedAttempts >= 10) //some cloud storages don't support changing creation/modification times => don't waste (a lot of) time trying to
return;
- dstCallback.requestUiRefresh(i->first);
+ dstCallback.requestUiRefresh(iter->first);
- const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw std::runtime_error
+ try
{
- //may need to remove the readonly-attribute (e.g. FAT usb drives)
- FileUpdateHandle updateHandle(i->first, [=]
- {
- return ::CreateFile(zen::applyLongPathPrefix(i->first).c_str(),
- FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, //needed to open a directory
- nullptr);
- });
- if (updateHandle.get() == INVALID_HANDLE_VALUE)
- {
- ++failedAttempts;
- assert(false); //don't throw exceptions due to dst hack here
- continue;
- }
-
- if (!::SetFileTime(updateHandle.get(),
- &encodedTime.createTimeRaw,
- nullptr,
- &encodedTime.writeTimeRaw))
- {
- ++failedAttempts;
- assert(false); //don't throw exceptions due to dst hack here
- continue;
- }
+ //set modification time including DST hack: this function is too clever to not introduce this dependency
+ setFileTime(iter->first, iter->second, SYMLINK_FOLLOW); //throw FileError
+ }
+ catch (FileError&)
+ {
+ ++failedAttempts;
+ assert(false); //don't throw exceptions due to dst hack here
+ continue;
}
//even at this point it's not sure whether data was written correctly, again cloud storages tend to lie about success status
- if (filesToValidate > 0)
+ if (filesToValidate-- > 0)
{
- --filesToValidate; //don't change during check!
+ const dst::RawTime encodedTime = dst::fatEncodeUtcTime(tofiletime(iter->second)); //throw std::runtime_error
//dst hack: verify data written; attention: this check may fail for "sync.ffs_lock"
WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {};
- ::GetFileAttributesEx(zen::applyLongPathPrefix(i->first).c_str(), //__in LPCTSTR lpFileName,
+ ::GetFileAttributesEx(zen::applyLongPathPrefix(iter->first).c_str(), //__in LPCTSTR lpFileName,
GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId,
&debugeAttr); //__out LPVOID lpFileInformation
@@ -528,7 +509,7 @@ private:
}
const bool isFatFileSystem;
- typedef std::vector<std::pair<Zstring, FILETIME> > FilenameTimeList;
+ typedef std::vector<std::pair<Zstring, Int64> > FilenameTimeList;
FilenameTimeList markForDstHack;
//####################################### DST hack ###########################################
diff --git a/zen/file_update_handle.h b/zen/file_update_handle.h
deleted file mode 100644
index 3df69f10..00000000
--- a/zen/file_update_handle.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef FILE_UPDATE_HANDLE_H_INCLUDED
-#define FILE_UPDATE_HANDLE_H_INCLUDED
-
-#include "win.h" //includes "windows.h"
-#include "long_path_prefix.h"
-
-namespace
-{
-//manage file handle to update existing files (temporarily resetting read-only if necessary)
-//CreateFileCmd: lambda directly returning non-owned file handle from ::CreateFile()
-class FileUpdateHandle
-{
-public:
- template <class CreateFileCmd>
- FileUpdateHandle(const Zstring& filename, CreateFileCmd cmd) :
- filenameFmt(zen::applyLongPathPrefix(filename)),
- hFile(INVALID_HANDLE_VALUE),
- attr(INVALID_FILE_ATTRIBUTES)
- {
- hFile = cmd();
- if (hFile == INVALID_HANDLE_VALUE)
- {
- //try to recover
- if (::GetLastError() == ERROR_ACCESS_DENIED) //function fails if file is read-only
- {
- //read-only file attribute may cause trouble: temporarily reset it
- const DWORD tmpAttr = ::GetFileAttributes(filenameFmt.c_str());
- if (tmpAttr != INVALID_FILE_ATTRIBUTES)
- {
- if (tmpAttr & FILE_ATTRIBUTE_READONLY)
- {
- if (::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL))
- {
- //guardErrorCode.dismiss();
- attr = tmpAttr; //"create" guard on read-only attribute
-
- //now try again
- hFile = cmd();
- }
- }
- else
- ::SetLastError(ERROR_ACCESS_DENIED);
- }
- }
- }
- }
-
- ~FileUpdateHandle()
- {
- if (hFile != INVALID_HANDLE_VALUE)
- ::CloseHandle(hFile);
-
- if (attr != INVALID_FILE_ATTRIBUTES)
- ::SetFileAttributes(filenameFmt.c_str(), attr);
- }
-
- //may return INVALID_FILE_ATTRIBUTES, in which case ::GetLastError() may be called directly after FileUpdateHandle()
- HANDLE get() const { return hFile; }
-
-private:
- FileUpdateHandle(const FileUpdateHandle&);
- FileUpdateHandle& operator=(const FileUpdateHandle&);
-
- Zstring filenameFmt;
- HANDLE hFile;
- DWORD attr;
-};
-}
-
-#endif // FILE_UPDATE_HANDLE_H_INCLUDED
diff --git a/zen/fixed_list.h b/zen/fixed_list.h
index eedbfab9..04a680ad 100644
--- a/zen/fixed_list.h
+++ b/zen/fixed_list.h
@@ -4,8 +4,8 @@
// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef PTR_WRAP_012384670856841394535
-#define PTR_WRAP_012384670856841394535
+#ifndef FIXED_LIST_01238467085684139453534
+#define FIXED_LIST_01238467085684139453534
#include <iterator>
@@ -19,12 +19,13 @@ class FixedList
struct Node
{
Node() : next(nullptr), val() {}
- template <class A> Node(A&& a) : next(nullptr), val(a) {}
- template <class A, class B> Node(A&& a, B&& b) : next(nullptr), val(a, b) {}
- template <class A, class B, class C> Node(A&& a, B&& b, C&& c) : next(nullptr), val(a, b, c) {}
- template <class A, class B, class C, class D> Node(A&& a, B&& b, C&& c, D&& d) : next(nullptr), val(a, b, c, d) {}
- template <class A, class B, class C, class D, class E> Node(A&& a, B&& b, C&& c, D&& d, E&& e) : next(nullptr), val(a, b, c, d, e) {}
- template <class A, class B, class C, class D, class E, class F> Node(A&& a, B&& b, C&& c, D&& d, E&& e, F&& f) : next(nullptr), val(a, b, c, d, e, f) {}
+ //no variadic templates on VC2010... :(
+ template <class A> Node(A&& a) : next(nullptr), val(std::forward<A>(a)) {}
+ template <class A, class B> Node(A&& a, B&& b) : next(nullptr), val(std::forward<A>(a), std::forward<B>(b)) {}
+ template <class A, class B, class C> Node(A&& a, B&& b, C&& c) : next(nullptr), val(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c)) {}
+ template <class A, class B, class C, class D> Node(A&& a, B&& b, C&& c, D&& d) : next(nullptr), val(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c), std::forward<D>(d)) {}
+ template <class A, class B, class C, class D, class E> Node(A&& a, B&& b, C&& c, D&& d, E&& e) : next(nullptr), val(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c), std::forward<D>(d), std::forward<E>(e)) {}
+ template <class A, class B, class C, class D, class E, class F> Node(A&& a, B&& b, C&& c, D&& d, E&& e, F&& f) : next(nullptr), val(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c), std::forward<D>(d), std::forward<E>(e), std::forward<F>(f)) {}
Node* next; //singly linked list is sufficient
T val;
@@ -36,16 +37,7 @@ public:
lastInsert(nullptr),
sz(0) {}
- ~FixedList()
- {
- Node* ptr = first;
- while (ptr)
- {
- Node* tmp = ptr;
- ptr = ptr->next;
- delete tmp;
- }
- }
+ ~FixedList() { clear(); }
template <class NodeT, class U>
class ListIterator : public std::iterator<std::forward_iterator_tag, U>
@@ -73,6 +65,9 @@ public:
const_iterator begin() const { return first; }
const_iterator end () const { return const_iterator(); }
+ const_iterator cbegin() const { return first; }
+ const_iterator cend () const { return const_iterator(); }
+
reference front() { return first->val; }
const_reference front() const { return first->val; }
@@ -112,7 +107,20 @@ public:
}
}
- void clear() { remove_if([](T&) { return true; }); }
+ void clear()
+ {
+ Node* ptr = first;
+ while (ptr)
+ {
+ Node* tmp = ptr;
+ ptr = ptr->next;
+ delete tmp;
+ }
+
+ first = lastInsert = nullptr;
+ sz = 0;
+ }
+
bool empty() const { return first == nullptr; }
size_t size() const { return sz; }
@@ -120,7 +128,7 @@ private:
FixedList(const FixedList&);
FixedList& operator=(const FixedList&);
- void pushNode(Node* newNode)
+ void pushNode(Node* newNode) //throw()
{
++sz;
if (lastInsert == nullptr)
@@ -144,10 +152,9 @@ private:
}
Node* first;
- Node* lastInsert; //point to last insertion; required by emplace_back()
+ Node* lastInsert; //point to last insertion; required by efficient emplace_back()
size_t sz;
};
}
-
-#endif //PTR_WRAP_012384670856841394535
+#endif //FIXED_LIST_01238467085684139453534
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index ed6308dc..1476e87d 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -19,7 +19,7 @@ namespace zen
3. path may already contain \\?\-prefix
*/
Zstring applyLongPathPrefix(const Zstring& path); //throw()
-Zstring applyLongPathPrefixCreateDir(const Zstring& path); //throw() -> special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
+Zstring applyLongPathPrefixCreateDir(const Zstring& path); //throw() -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
Zstring removeLongPathPrefix(const Zstring& path); //throw()
}
diff --git a/zen/optional.h b/zen/optional.h
index 2bd272ae..34e3d21d 100644
--- a/zen/optional.h
+++ b/zen/optional.h
@@ -38,9 +38,17 @@ public:
Opt(NoValue) : value() , valid(false) {}
Opt(const T& val) : value(val), valid(true ) {}
- //rvalue optimization: only basic exception safety:
- Opt(Opt&& tmp) : value(std::move(tmp.value)), valid(tmp.valid) {}
- Opt& operator=(const Opt& tmp) { value = std::move(tmp.value); valid = tmp.valid; }
+ Opt(const Opt& tmp) : value(tmp.valid ? tmp.value : T()), valid(tmp.valid) {}
+
+ Opt& operator=(const Opt& tmp)
+ {
+ if (tmp.valid)
+ value = tmp.value;
+ valid = tmp.valid;
+ }
+
+ ////rvalue optimization: only basic exception safety:
+ // Opt(Opt&& tmp) : value(std::move(tmp.value)), valid(tmp.valid) {}
#ifdef _MSC_VER
private:
@@ -58,6 +66,7 @@ public:
/**/ T* operator->() { return &value; }
void reset() { valid = false; }
+
private:
T value;
bool valid;
diff --git a/zen/read_txt.cpp b/zen/read_txt.cpp
index fd92a10c..0fd310c2 100644
--- a/zen/read_txt.cpp
+++ b/zen/read_txt.cpp
@@ -5,13 +5,13 @@ using namespace zen;
namespace
{
-std::string detectLineBreak(const Zstring& filename) //throw (FileError)
+std::string detectLineBreak(const Zstring& filename) //throw FileError
{
//read a (hopefully) significant portion of data
zen::FileInput input(filename);
std::vector<char> buffer(64 * 1024);
- size_t bytesRead = input.read(&buffer[0], buffer.size()); //throw (FileError);
+ size_t bytesRead = input.read(&buffer[0], buffer.size()); //throw FileError
buffer.resize(bytesRead);
//detect line break
@@ -41,15 +41,15 @@ std::string detectLineBreak(const Zstring& filename) //throw (FileError)
}
-ExtractLines::ExtractLines(const Zstring& filename, const std::string& lineBreak) : //throw (FileError)
+ExtractLines::ExtractLines(const Zstring& filename, const std::string& lineBreak) : //throw FileError
inputStream(filename), bufferLogBegin(buffer.begin()), lineBreak_(lineBreak)
{
if (lineBreak.empty())
- lineBreak_ = detectLineBreak(filename); //throw (FileError)
+ lineBreak_ = detectLineBreak(filename); //throw FileError
}
-bool ExtractLines::getLine(std::string& output) //throw (FileError)
+bool ExtractLines::getLine(std::string& output) //throw FileError
{
for (;;)
{
@@ -80,7 +80,7 @@ bool ExtractLines::getLine(std::string& output) //throw (FileError)
const size_t BLOCK_SIZE = 512 * 1024;
buffer.resize(buffer.size() + BLOCK_SIZE);
- size_t bytesRead = inputStream.read(&buffer[0] + buffer.size() - BLOCK_SIZE, BLOCK_SIZE); //throw (FileError);
+ size_t bytesRead = inputStream.read(&buffer[0] + buffer.size() - BLOCK_SIZE, BLOCK_SIZE); //throw FileError
assert(bytesRead <= BLOCK_SIZE); //promised by FileInput()
if (bytesRead < BLOCK_SIZE)
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index 5e5e56d4..3de795a5 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -71,7 +71,7 @@ Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string
}
-bool zen::moveToRecycleBin(const Zstring& filename) //throw FileError
+bool zen::recycleOrDelete(const Zstring& filename) //throw FileError
{
if (!somethingExists(filename))
return false; //neither file nor any other object with that name existing: no error situation, manual deletion relies on it!
@@ -165,12 +165,37 @@ bool zen::moveToRecycleBin(const Zstring& filename) //throw FileError
#ifdef FFS_WIN
-zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
+StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
{
- warn_static("fix XP not working + finish");
+ const DWORD bufferSize = MAX_PATH + 1;
+ std::vector<wchar_t> buffer(bufferSize);
+ if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName,
+ &buffer[0], //__out LPTSTR lpszVolumePathName,
+ bufferSize)) //__in DWORD cchBufferLength
+ return STATUS_REC_UNKNOWN;
+
+ const Zstring rootPathPf = appendSeparator(&buffer[0]);
+
+ SHQUERYRBINFO recInfo = {};
+ recInfo.cbSize = sizeof(recInfo);
+ HRESULT rv = ::SHQueryRecycleBin(rootPathPf.c_str(), //__in_opt LPCTSTR pszRootPath,
+ &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
+
+ return rv == S_OK ? STATUS_REC_EXISTS : STATUS_REC_MISSING;
+ //1. excessive: traverses whole C:\$Recycle.Bin directory tree each time!!!! But it's safe and correct.
+
+ //2. we would prefer to use CLSID_RecycleBinManager beginning with Vista... if only this interface were documented!!!
+
+ //3. check directory existence of "C:\$Recycle.Bin, C:\RECYCLER, C:\RECYCLED"
+ // -> not upward-compatible, wrong result for subst-alias: recycler assumed existing, although it is not!
+
+ //4. alternative approach a'la Raymond Chen: http://blogs.msdn.com/b/oldnewthing/archive/2008/09/18/8956382.aspx
+ //caveat: might not be reliable, e.g. "subst"-alias of volume contains "$Recycle.Bin" although it is not available!
/*
- const bool canUseFastCheckForRecycler = winXpOrLater();
+ Zstring rootPathPf = appendSeparator(&buffer[0]);
+
+ const bool canUseFastCheckForRecycler = winXpOrLater();
if (!canUseFastCheckForRecycler) //== "checkForRecycleBin"
return STATUS_REC_UNKNOWN;
@@ -180,20 +205,7 @@ zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
if (!checkRecycler)
return STATUS_REC_UNKNOWN; //actually an error since we're >= XP
- const DWORD bufferSize = MAX_PATH + 1;
- std::vector<wchar_t> buffer(bufferSize);
- if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName,
- &buffer[0], //__out LPTSTR lpszVolumePathName,
- bufferSize)) //__in DWORD cchBufferLength
- return STATUS_REC_UNKNOWN;
-
- Zstring rootPathPf = appendSeparator(&buffer[0]);
-
//search root directories for recycle bin folder...
- //we would prefer to use CLSID_RecycleBinManager beginning with Vista... if this interface were documented
-
- //caveat: "subst"-alias of volume contains "$Recycle.Bin" although it is not available!!!
- warn_static("check")
WIN32_FIND_DATA dataRoot = {};
HANDLE hFindRoot = ::FindFirstFile(applyLongPathPrefix(rootPathPf + L'*').c_str(), &dataRoot);
@@ -207,8 +219,8 @@ zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
{
if (!shouldSkip(dataRoot.cFileName) &&
(dataRoot.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
- (dataRoot.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ) != 0 && //maybe a little risky to rely on these attributes, there may be a recycler
- (dataRoot.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) != 0) //(in obscure cases) we don't find, but that's better than the other way round
+ (dataRoot.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ) != 0 && //risky to rely on these attributes!!!
+ (dataRoot.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) != 0) //
{
WIN32_FIND_DATA dataChild = {};
const Zstring childDirPf = rootPathPf + dataRoot.cFileName + L"\\";
@@ -238,25 +250,7 @@ zen::StatusRecycler zen::recycleBinStatus(const Zstring& pathName)
while (::FindNextFile(hFindRoot, &dataRoot)); //
return STATUS_REC_MISSING;
-
*/
-
- const DWORD bufferSize = MAX_PATH + 1;
- std::vector<wchar_t> buffer(bufferSize);
- if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName,
- &buffer[0], //__out LPTSTR lpszVolumePathName,
- bufferSize)) //__in DWORD cchBufferLength
- return STATUS_REC_UNKNOWN;
-
- const Zstring rootPathPf = appendSeparator(&buffer[0]);
-
- SHQUERYRBINFO recInfo = {};
- recInfo.cbSize = sizeof(recInfo);
- HRESULT rv = ::SHQueryRecycleBin(rootPathPf.c_str(), //__in_opt LPCTSTR pszRootPath,
- &recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
- //traverses whole C:\$Recycle.Bin directory each time!!!!
-
- return rv == S_OK ? STATUS_REC_EXISTS : STATUS_REC_MISSING;
}
#elif defined FFS_LINUX
diff --git a/zen/recycler.h b/zen/recycler.h
index 952deec2..1778eb2e 100644
--- a/zen/recycler.h
+++ b/zen/recycler.h
@@ -29,8 +29,8 @@ Linker flags: `pkg-config --libs gio-2.0`
Already included in package "gtk+-2.0"!
*/
-//move a file or folder to Recycle Bin (deletes permanently if recycle is not available)
-bool moveToRecycleBin(const Zstring& filename); //throw FileError, return "true" if file/dir was actually deleted
+//move a file or folder to Recycle Bin (deletes permanently if recycle is not available) -> crappy semantics, but we have no choice thanks to Windows' design
+bool recycleOrDelete(const Zstring& filename); //throw FileError, return "true" if file/dir was actually deleted
#ifdef FFS_WIN
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 78d99832..ace6ebaa 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -33,6 +33,9 @@ void set_remove_if(S& set, Predicate p);
template <class M, class Predicate>
void map_remove_if(M& map, Predicate p);
+template <class M, class K, class V>
+V& map_add_or_update(M& map, const K& key, const V& value); //efficient add or update without "default-constructible" requirement (Effective STL, item 24)
+
//binary search returning an iterator
template <class ForwardIterator, class T, typename Compare>
ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp);
@@ -98,6 +101,20 @@ template <class M, class Predicate> inline
void map_remove_if(M& map, Predicate p) { set_remove_if(map, p); }
+template <class M, class K, class V> inline
+V& map_add_or_update(M& map, const K& key, const V& value) //efficient add or update without "default-constructible" requirement (Effective STL, item 24)
+{
+ auto iter = map.lower_bound(key);
+ if (iter != map.end() && !(map.key_comp()(key, iter->first)))
+ {
+ iter->second = value;
+ return iter->second;
+ }
+ else
+ return map.insert(iter, typename M::value_type(key, value))->second;
+}
+
+
template <class ForwardIterator, class T, typename Compare> inline
ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp)
{
diff --git a/zen/string_base.h b/zen/string_base.h
index 16731089..4c339d56 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -31,7 +31,8 @@ public:
//::operator new/ ::operator delete show same performance characterisics like malloc()/free()!
static void* allocate(size_t size) { return ::operator new(size); } //throw std::bad_alloc
static void deallocate(void* ptr) { ::operator delete(ptr); }
- static size_t calcCapacity(size_t length) { return std::max<size_t>(16, length + length / 2); } //any growth rate should not exceed golden ratio: 1.618033989
+ static size_t calcCapacity(size_t length) { return std::max<size_t>(std::max<size_t>(16, length), length + length / 2); } //size_t might overflow!
+ //any growth rate should not exceed golden ratio: 1.618033989
};
@@ -68,9 +69,9 @@ protected:
static Char* create(size_t size) { return create(size, size); }
static Char* create(size_t size, size_t minCapacity)
{
+ assert(size <= minCapacity);
const size_t newCapacity = AP::calcCapacity(minCapacity);
assert(newCapacity >= minCapacity);
- assert(minCapacity >= size);
Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char)));
@@ -121,9 +122,10 @@ protected:
static Char* create(size_t size) { return create(size, size); }
static Char* create(size_t size, size_t minCapacity)
{
+ assert(size <= minCapacity);
+
const size_t newCapacity = AP::calcCapacity(minCapacity);
assert(newCapacity >= minCapacity);
- assert(minCapacity >= size);
Descriptor* const newDescr = static_cast<Descriptor*>(AP::allocate(sizeof(Descriptor) + (newCapacity + 1) * sizeof(Char)));
new (newDescr) Descriptor(1, size, newCapacity);
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 04ba1eef..00eb50ee 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -90,7 +90,8 @@ bool isWhiteSpace(char ch)
std::isspace(static_cast<unsigned char>(ch)) != 0;
}
-template <> inline bool isWhiteSpace(wchar_t ch) { return std::iswspace(ch) != 0; }
+template <> inline
+bool isWhiteSpace(wchar_t ch) { return std::iswspace(ch) != 0; }
template <class Char> inline
@@ -458,7 +459,7 @@ S formatInteger(Num n, bool hasMinus)
assert(n >= 0);
typedef typename GetCharType<S>::Type CharType;
- const size_t bufferSize = 100; //sufficient for signed 256-bit numbers
+ const size_t bufferSize = 64; //sufficient for signed 128-bit numbers
CharType buffer[bufferSize]; //it's generally faster to use a buffer than to rely on String::operator+=() (in)efficiency
assert_static(2 + 5 * sizeof(n) / 2 <= bufferSize);
//minimum required chars (+ sign char): 1 + ceil(ln_10 (256^sizeof(n))) =~ 1 + ceil(sizeof(n) * 2.4082) <= 2 + floor(sizeof(n) * 2.5)
@@ -492,7 +493,6 @@ S numberTo(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
//--------------------------------------------------------------------------------
-
template <class Num, class S> inline
Num stringTo(const S& str, Int2Type<NUM_TYPE_OTHER>) //default string to number conversion using streams: convenient, but SLOW
{
diff --git a/zen/string_traits.h b/zen/string_traits.h
index cfcf78bb..eea9ae02 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -35,7 +35,7 @@ strLength():
strLength(array); //equals cStringLength(array)
*/
-//wrap a sub-string or a char* as an intermediate string class when the length is already known
+//reference a sub-string or a char* as an intermediate string class when the length is already known
template <class Char>
class StringProxy
{
@@ -126,8 +126,7 @@ public:
enum
{
- isStringLike =
- IsSameType<CharType, char >::value ||
+ isStringLike = IsSameType<CharType, char>::value ||
IsSameType<CharType, wchar_t>::value
};
};
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index dfd5ebfa..17ae1916 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -84,7 +84,7 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError
const DWORD bufferSize = REPARSE_DATA_BUFFER_HEADER_SIZE + MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
std::vector<char> buffer(bufferSize);
- DWORD bytesReturned; //dummy value required by FSCTL_GET_REPARSE_POINT!
+ DWORD bytesReturned = 0; //dummy value required by FSCTL_GET_REPARSE_POINT!
if (!::DeviceIoControl(hLink, //__in HANDLE hDevice,
FSCTL_GET_REPARSE_POINT, //__in DWORD dwIoControlCode,
nullptr, //__in_opt LPVOID lpInBuffer,
diff --git a/zen/thread.h b/zen/thread.h
index 3fb73e70..1fda016d 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -11,15 +11,15 @@
#include <memory>
#include "fixed_list.h"
+//fix this pathetic boost thread warning mess
#ifdef __MINGW32__
#pragma GCC diagnostic push
-
#pragma GCC diagnostic ignored "-Wswitch-enum"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-//#pragma GCC diagnostic ignored "-Wno-attributes"
-//#pragma GCC diagnostic ignored "-Wredundant-decls"
-//#pragma GCC diagnostic ignored "-Wcast-align"
-//#pragma GCC diagnostic ignored "-Wunused-value"
+#pragma GCC diagnostic ignored "-Wshadow"
+#endif
+#ifdef _MSC_VER
+#pragma warning(disable : 4702) //unreachable code
#endif
#include <boost/thread.hpp>
@@ -27,6 +27,9 @@
#ifdef __MINGW32__
#pragma GCC diagnostic pop
#endif
+#ifdef _MSC_VER
+#pragma warning(default : 4702) //unreachable code
+#endif
namespace zen
{
@@ -89,7 +92,7 @@ auto async2(Function fun) -> boost::unique_future<T> //workaround VS2010 bug: bo
boost::packaged_task<T> pt([=] { return fun(); });
auto fut = pt.get_future();
boost::thread(std::move(pt));
- return std::move(fut);
+ return std::move(fut); //compiler error without "move", why needed???
}
bgstack15