diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:20:29 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:20:29 +0200 |
commit | b8f13e45be884dc12884ebe8f3dcd9eecb23a106 (patch) | |
tree | 22a6d8b96815d626061ff3e2d432c13078fca5c4 | |
parent | 5.4 (diff) | |
download | FreeFileSync-b8f13e45be884dc12884ebe8f3dcd9eecb23a106.tar.gz FreeFileSync-b8f13e45be884dc12884ebe8f3dcd9eecb23a106.tar.bz2 FreeFileSync-b8f13e45be884dc12884ebe8f3dcd9eecb23a106.zip |
5.5
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 Binary files differindex 09d8adab..94ea4923 100644 --- a/BUILD/FreeFileSync.chm +++ b/BUILD/FreeFileSync.chm 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 Binary files differindex 54e6e657..2f132d17 100644 --- a/BUILD/Resources.zip +++ b/BUILD/Resources.zip 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='"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)"' /> @@ -50,16 +52,19 @@ <Add option="-Winvalid-pch" /> <Add option='-include "wx+/pch.h"' /> <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 "wx+/pch.h"' /> <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" /> @@ -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='"C:\Program Files\C++\CodeSigning\SignCode.cmd" "$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)"' /> @@ -46,7 +48,7 @@ <Add option="-Winvalid-pch" /> <Add option='-include "../wx+/pch.h"' /> <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¤cy_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¤cy_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¤cy_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¤cy_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??? } |